@runcofactor/cli 0.52.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/{account-3ZG24MOE.js → account-MRZ54P5P.js} +5 -5
- package/dist/{alert-5G7PTAX2.js → alert-XBHELHEI.js} +8 -8
- package/dist/{api-catalog-IBYAFKKQ.js → api-catalog-GWYRX53L.js} +5 -5
- package/dist/{api-key-UXC44BDR.js → api-key-FH6JN447.js} +5 -5
- package/dist/{attachment-T6IRFQW3.js → attachment-J7GRVT5F.js} +5 -5
- package/dist/{auth-SHOCJE6Z.js → auth-VZZQXRDR.js} +3 -3
- package/dist/{benchmark-NJ2U6VTC.js → benchmark-A3SNDARF.js} +5 -5
- package/dist/{blackcat-RQJVFGXQ.js → blackcat-UM6TBQBN.js} +3 -3
- package/dist/{chunk-DHAGRM2F.js → chunk-33U56YGD.js} +14 -5
- package/dist/{chunk-DHAGRM2F.js.map → chunk-33U56YGD.js.map} +1 -1
- package/dist/{chunk-M752EUK3.js → chunk-3JU4UYYN.js} +5 -5
- package/dist/{chunk-G6BCST3G.js → chunk-3ZOUNCA5.js} +7 -7
- package/dist/{chunk-76Z6E7XX.js → chunk-4UZN6TVT.js} +74 -131
- package/dist/chunk-4UZN6TVT.js.map +1 -0
- package/dist/{chunk-ABT3BLRC.js → chunk-5TKXHS3X.js} +3 -3
- package/dist/{chunk-QCYSONXI.js → chunk-CRYHWO4M.js} +2 -2
- package/dist/{chunk-QTYUM4ZB.js → chunk-EJ3ZPH5U.js} +23 -187
- package/dist/chunk-EJ3ZPH5U.js.map +1 -0
- package/dist/{chunk-I5RHTCPY.js → chunk-EL6KJ4PO.js} +4 -4
- package/dist/{chunk-ZL4O6C42.js → chunk-HXBK3AGD.js} +2 -2
- package/dist/{chunk-PRERH4DN.js → chunk-I2SOHQ2C.js} +3 -3
- package/dist/{chunk-CYSPCGO6.js → chunk-JEHHEMUL.js} +5 -5
- package/dist/{chunk-LIEADTEF.js → chunk-LJFVRJCA.js} +2 -2
- package/dist/{chunk-UEJ2HTKU.js → chunk-MJVUMVLO.js} +19 -1
- package/dist/chunk-MJVUMVLO.js.map +1 -0
- package/dist/chunk-N55RKCGR.js +24 -0
- package/dist/chunk-N55RKCGR.js.map +1 -0
- package/dist/{chunk-PHNH3CEU.js → chunk-O4Z44BR7.js} +5 -5
- package/dist/{chunk-QA37WVF6.js → chunk-OQFCZERZ.js} +6 -6
- package/dist/{chunk-EUVB6Y3C.js → chunk-P7L5KELH.js} +8 -8
- package/dist/chunk-P7L5KELH.js.map +1 -0
- package/dist/{chunk-Z3MDQSZG.js → chunk-PJFFGQSB.js} +2 -2
- package/dist/{chunk-IY3ZK46I.js → chunk-QOVJUSSL.js} +2 -2
- package/dist/{chunk-RPJMQBB5.js → chunk-QXU4G4YN.js} +3 -3
- package/dist/{chunk-SZSTJIYU.js → chunk-RRSUKARV.js} +4 -4
- package/dist/{chunk-775FI436.js → chunk-RVD6J6IZ.js} +2 -2
- package/dist/{chunk-5UUIBY6E.js → chunk-TAVBFLCR.js} +3 -3
- package/dist/{chunk-ROX7N3RK.js → chunk-V7HB5LAU.js} +10 -7
- package/dist/chunk-V7HB5LAU.js.map +1 -0
- package/dist/{chunk-LL6TSQWV.js → chunk-VKZOHJCE.js} +3 -3
- package/dist/chunk-VKZOHJCE.js.map +1 -0
- package/dist/{chunk-3HI6QC4V.js → chunk-WRBU6TX7.js} +2 -2
- package/dist/{proofs-TXJGAP5F.js → chunk-X7SUSIY3.js} +118 -20
- package/dist/chunk-X7SUSIY3.js.map +1 -0
- package/dist/{chunk-BF3IPGMP.js → chunk-XSSZMG65.js} +4 -4
- package/dist/{credential-TWSWV64F.js → credential-4RFRU6OH.js} +5 -5
- package/dist/{credential-template-XO5D5AI3.js → credential-template-36PFUTBN.js} +5 -5
- package/dist/{digest-SLEFOLPV.js → digest-THMKFMP7.js} +8 -8
- package/dist/{docs-IDC4V4WQ.js → docs-ZGM53L67.js} +5 -5
- package/dist/{doctor-SDAYEA6C.js → doctor-Z2XBGBM3.js} +3 -3
- package/dist/{environment-VBUIBQ6O.js → environment-5YVZXBN7.js} +7 -7
- package/dist/eval-SO5TPD37.js +1177 -0
- package/dist/eval-SO5TPD37.js.map +1 -0
- package/dist/{exploration-IREIR5PO.js → exploration-GZ4WUJJH.js} +5 -5
- package/dist/{exploratory-test-4Q7BMEFT.js → exploratory-test-Y7P4ZDLD.js} +5 -5
- package/dist/{external-run-S7LULKPT.js → external-run-IJGGZOGI.js} +7 -7
- package/dist/{feature-flag-IASHTUGU.js → feature-flag-UH6Z7774.js} +5 -5
- package/dist/{flow-IBEZFZTU.js → flow-MRWAQYZZ.js} +5 -5
- package/dist/{github-HAEZRULP.js → github-VDJU3PU3.js} +6 -6
- package/dist/index.js +101 -82
- package/dist/index.js.map +1 -1
- package/dist/{init-LT2TZMQY.js → init-CROSTPA6.js} +5 -5
- package/dist/{install-RTEYH6TK.js → install-ECR7OLAY.js} +5 -5
- package/dist/{issues-5GE277R2.js → issues-K5TL2S4Z.js} +7 -7
- package/dist/{knobs-AMIWGYUZ.js → knobs-OKQFBQLK.js} +5 -5
- package/dist/{landing-3VLVVQL5.js → landing-XANIBPVM.js} +7 -7
- package/dist/{list-GDJR6UY6.js → list-64GX47Q4.js} +5 -5
- package/dist/{local-4R6GVW7U.js → local-QMQY2ZUX.js} +7 -7
- package/dist/{login-IXVAWTLO.js → login-I7UQ3GTM.js} +5 -5
- package/dist/{mcp-BM2MJWX4.js → mcp-XZV63DX5.js} +11 -11
- package/dist/{mcp-BM2MJWX4.js.map → mcp-XZV63DX5.js.map} +1 -1
- package/dist/{metrics-SSIP5CEB.js → metrics-KBTQ3KGZ.js} +5 -5
- package/dist/{monitor-ESZYHXT2.js → monitor-UGWY43IU.js} +5 -5
- package/dist/perf-CCHWHCSR.js +961 -0
- package/dist/perf-CCHWHCSR.js.map +1 -0
- package/dist/{product-VCGUV5TH.js → product-KLG2ZTHC.js} +5 -5
- package/dist/{product-map-AXKZNQDM.js → product-map-AMEZ76EQ.js} +5 -5
- package/dist/{prompts-FVPSON2N.js → prompts-ZVQNGL7X.js} +5 -5
- package/dist/proofs-QCNSQAPX.js +20 -0
- package/dist/{property-XEPCC7KQ.js → property-PJDQFHAL.js} +6 -6
- package/dist/{psql-JKF3OYYJ.js → psql-AURAN27C.js} +5 -5
- package/dist/{record-REQ37S54.js → record-SYWBTUOB.js} +6 -6
- package/dist/{redis-WGHT2GJB.js → redis-2H752SKO.js} +5 -5
- package/dist/{release-SNDIVIA6.js → release-OSIYUXSC.js} +5 -5
- package/dist/{runbook-XFJG2LFC.js → runbook-7LVHF6KV.js} +5 -5
- package/dist/{sandbox-DYCKLCMY.js → sandbox-TJQPMRGS.js} +18 -30
- package/dist/sandbox-TJQPMRGS.js.map +1 -0
- package/dist/{scenarios-PVHCKP55.js → scenarios-P2ABU4HK.js} +5 -5
- package/dist/{schedule-DGC7CX23.js → schedule-XLS56NP5.js} +8 -8
- package/dist/{session-ERGUFDDI.js → session-ACSFC3UB.js} +8 -8
- package/dist/{skill-6QO2E3TB.js → skill-F7I5P6AI.js} +43 -28
- package/dist/{skill-6QO2E3TB.js.map → skill-F7I5P6AI.js.map} +1 -1
- package/dist/{slack-WE7THLLH.js → slack-ZEK4GRND.js} +6 -6
- package/dist/{spec-SEOY7N3L.js → spec-XPIRRSV6.js} +5 -5
- package/dist/{src-CCK3TKBX.js → src-N7ZCYCXU.js} +4 -4
- package/dist/{src-AEWV5HYH.js → src-XSBBMVGW.js} +3 -3
- package/dist/{start-EPGLHTND.js → start-DKWLOQI6.js} +5 -5
- package/dist/{status-DTE2GXM2.js → status-K7KH5DI3.js} +5 -5
- package/dist/{tag-GIFEWGBL.js → tag-2Y3OMQQC.js} +6 -6
- package/dist/{task-VLJCHSFB.js → task-4PIOC4QV.js} +6 -6
- package/dist/{teams-J2OOJBL4.js → teams-KUM56BE2.js} +83 -47
- package/dist/teams-KUM56BE2.js.map +1 -0
- package/dist/{test-suite-CTACGIAZ.js → test-suite-SW25YGJV.js} +138 -96
- package/dist/test-suite-SW25YGJV.js.map +1 -0
- package/dist/{trace-RWQDYL4K.js → trace-QPXHYBLA.js} +7 -7
- package/dist/{triage-6UAXLCGU.js → triage-EZABRZZM.js} +6 -6
- package/dist/trigger-7C7KX5KH.js +137 -0
- package/dist/trigger-7C7KX5KH.js.map +1 -0
- package/dist/{update-check-QRREAM3N.js → update-check-E3X7UIY6.js} +3 -3
- package/dist/{upgrade-5Y655TQ6.js → upgrade-EJGTMW44.js} +4 -4
- package/dist/{usage-KCXFY46V.js → usage-GZCQDULF.js} +7 -7
- package/dist/{utilities-SUON2KZK.js → utilities-RIITD53A.js} +6 -6
- package/dist/{visual-GJZVJC32.js → visual-FH67OKS2.js} +5 -5
- package/dist/{workflow-R5QAXWBX.js → workflow-34YJZ2QQ.js} +38 -86
- package/dist/workflow-34YJZ2QQ.js.map +1 -0
- package/dist/{workflow-cache-PFBTWLGM.js → workflow-cache-YQ3BGJIG.js} +17 -17
- package/dist/{workflow-cache-convergence-resolve-UZGRPC3B.js → workflow-cache-convergence-resolve-SPLBRSNK.js} +5 -5
- package/dist/{workflow-debug-RACNWWOL.js → workflow-debug-HZB7TJGK.js} +10 -10
- package/dist/workflow-debug-HZB7TJGK.js.map +1 -0
- package/dist/{workflow-feedback-RJIQ5R3R.js → workflow-feedback-6UOTIWIQ.js} +5 -5
- package/dist/{workflow-fork-LINDCYJ3.js → workflow-fork-IDYHAHCX.js} +5 -5
- package/dist/workflow-promotion-U6WYFY5U.js +62 -0
- package/dist/workflow-promotion-U6WYFY5U.js.map +1 -0
- package/dist/{workflow-proposals-E4EXKAGM.js → workflow-proposals-MMVNIQT3.js} +5 -5
- package/dist/{workflow-revisions-5M6APN6R.js → workflow-revisions-BPUOLCZB.js} +5 -5
- package/dist/{workflow-status-7KL73WS2.js → workflow-status-RA3IEMEW.js} +5 -5
- package/package.json +3 -2
- package/dist/chat-target-IZ7YLLU3.js +0 -502
- package/dist/chat-target-IZ7YLLU3.js.map +0 -1
- package/dist/chunk-76Z6E7XX.js.map +0 -1
- package/dist/chunk-EUVB6Y3C.js.map +0 -1
- package/dist/chunk-LL6TSQWV.js.map +0 -1
- package/dist/chunk-QTYUM4ZB.js.map +0 -1
- package/dist/chunk-ROX7N3RK.js.map +0 -1
- package/dist/chunk-UEJ2HTKU.js.map +0 -1
- package/dist/proofs-TXJGAP5F.js.map +0 -1
- package/dist/sandbox-DYCKLCMY.js.map +0 -1
- package/dist/teams-J2OOJBL4.js.map +0 -1
- package/dist/test-suite-CTACGIAZ.js.map +0 -1
- package/dist/workflow-R5QAXWBX.js.map +0 -1
- /package/dist/{account-3ZG24MOE.js.map → account-MRZ54P5P.js.map} +0 -0
- /package/dist/{alert-5G7PTAX2.js.map → alert-XBHELHEI.js.map} +0 -0
- /package/dist/{api-catalog-IBYAFKKQ.js.map → api-catalog-GWYRX53L.js.map} +0 -0
- /package/dist/{api-key-UXC44BDR.js.map → api-key-FH6JN447.js.map} +0 -0
- /package/dist/{attachment-T6IRFQW3.js.map → attachment-J7GRVT5F.js.map} +0 -0
- /package/dist/{auth-SHOCJE6Z.js.map → auth-VZZQXRDR.js.map} +0 -0
- /package/dist/{benchmark-NJ2U6VTC.js.map → benchmark-A3SNDARF.js.map} +0 -0
- /package/dist/{blackcat-RQJVFGXQ.js.map → blackcat-UM6TBQBN.js.map} +0 -0
- /package/dist/{chunk-M752EUK3.js.map → chunk-3JU4UYYN.js.map} +0 -0
- /package/dist/{chunk-G6BCST3G.js.map → chunk-3ZOUNCA5.js.map} +0 -0
- /package/dist/{chunk-ABT3BLRC.js.map → chunk-5TKXHS3X.js.map} +0 -0
- /package/dist/{chunk-QCYSONXI.js.map → chunk-CRYHWO4M.js.map} +0 -0
- /package/dist/{chunk-I5RHTCPY.js.map → chunk-EL6KJ4PO.js.map} +0 -0
- /package/dist/{chunk-ZL4O6C42.js.map → chunk-HXBK3AGD.js.map} +0 -0
- /package/dist/{chunk-PRERH4DN.js.map → chunk-I2SOHQ2C.js.map} +0 -0
- /package/dist/{chunk-CYSPCGO6.js.map → chunk-JEHHEMUL.js.map} +0 -0
- /package/dist/{chunk-LIEADTEF.js.map → chunk-LJFVRJCA.js.map} +0 -0
- /package/dist/{chunk-PHNH3CEU.js.map → chunk-O4Z44BR7.js.map} +0 -0
- /package/dist/{chunk-QA37WVF6.js.map → chunk-OQFCZERZ.js.map} +0 -0
- /package/dist/{chunk-Z3MDQSZG.js.map → chunk-PJFFGQSB.js.map} +0 -0
- /package/dist/{chunk-IY3ZK46I.js.map → chunk-QOVJUSSL.js.map} +0 -0
- /package/dist/{chunk-RPJMQBB5.js.map → chunk-QXU4G4YN.js.map} +0 -0
- /package/dist/{chunk-SZSTJIYU.js.map → chunk-RRSUKARV.js.map} +0 -0
- /package/dist/{chunk-775FI436.js.map → chunk-RVD6J6IZ.js.map} +0 -0
- /package/dist/{chunk-5UUIBY6E.js.map → chunk-TAVBFLCR.js.map} +0 -0
- /package/dist/{chunk-3HI6QC4V.js.map → chunk-WRBU6TX7.js.map} +0 -0
- /package/dist/{chunk-BF3IPGMP.js.map → chunk-XSSZMG65.js.map} +0 -0
- /package/dist/{credential-TWSWV64F.js.map → credential-4RFRU6OH.js.map} +0 -0
- /package/dist/{credential-template-XO5D5AI3.js.map → credential-template-36PFUTBN.js.map} +0 -0
- /package/dist/{digest-SLEFOLPV.js.map → digest-THMKFMP7.js.map} +0 -0
- /package/dist/{docs-IDC4V4WQ.js.map → docs-ZGM53L67.js.map} +0 -0
- /package/dist/{doctor-SDAYEA6C.js.map → doctor-Z2XBGBM3.js.map} +0 -0
- /package/dist/{environment-VBUIBQ6O.js.map → environment-5YVZXBN7.js.map} +0 -0
- /package/dist/{exploration-IREIR5PO.js.map → exploration-GZ4WUJJH.js.map} +0 -0
- /package/dist/{exploratory-test-4Q7BMEFT.js.map → exploratory-test-Y7P4ZDLD.js.map} +0 -0
- /package/dist/{external-run-S7LULKPT.js.map → external-run-IJGGZOGI.js.map} +0 -0
- /package/dist/{feature-flag-IASHTUGU.js.map → feature-flag-UH6Z7774.js.map} +0 -0
- /package/dist/{flow-IBEZFZTU.js.map → flow-MRWAQYZZ.js.map} +0 -0
- /package/dist/{github-HAEZRULP.js.map → github-VDJU3PU3.js.map} +0 -0
- /package/dist/{init-LT2TZMQY.js.map → init-CROSTPA6.js.map} +0 -0
- /package/dist/{install-RTEYH6TK.js.map → install-ECR7OLAY.js.map} +0 -0
- /package/dist/{issues-5GE277R2.js.map → issues-K5TL2S4Z.js.map} +0 -0
- /package/dist/{knobs-AMIWGYUZ.js.map → knobs-OKQFBQLK.js.map} +0 -0
- /package/dist/{landing-3VLVVQL5.js.map → landing-XANIBPVM.js.map} +0 -0
- /package/dist/{list-GDJR6UY6.js.map → list-64GX47Q4.js.map} +0 -0
- /package/dist/{local-4R6GVW7U.js.map → local-QMQY2ZUX.js.map} +0 -0
- /package/dist/{login-IXVAWTLO.js.map → login-I7UQ3GTM.js.map} +0 -0
- /package/dist/{metrics-SSIP5CEB.js.map → metrics-KBTQ3KGZ.js.map} +0 -0
- /package/dist/{monitor-ESZYHXT2.js.map → monitor-UGWY43IU.js.map} +0 -0
- /package/dist/{product-VCGUV5TH.js.map → product-KLG2ZTHC.js.map} +0 -0
- /package/dist/{product-map-AXKZNQDM.js.map → product-map-AMEZ76EQ.js.map} +0 -0
- /package/dist/{prompts-FVPSON2N.js.map → prompts-ZVQNGL7X.js.map} +0 -0
- /package/dist/{src-AEWV5HYH.js.map → proofs-QCNSQAPX.js.map} +0 -0
- /package/dist/{property-XEPCC7KQ.js.map → property-PJDQFHAL.js.map} +0 -0
- /package/dist/{psql-JKF3OYYJ.js.map → psql-AURAN27C.js.map} +0 -0
- /package/dist/{record-REQ37S54.js.map → record-SYWBTUOB.js.map} +0 -0
- /package/dist/{redis-WGHT2GJB.js.map → redis-2H752SKO.js.map} +0 -0
- /package/dist/{release-SNDIVIA6.js.map → release-OSIYUXSC.js.map} +0 -0
- /package/dist/{runbook-XFJG2LFC.js.map → runbook-7LVHF6KV.js.map} +0 -0
- /package/dist/{scenarios-PVHCKP55.js.map → scenarios-P2ABU4HK.js.map} +0 -0
- /package/dist/{schedule-DGC7CX23.js.map → schedule-XLS56NP5.js.map} +0 -0
- /package/dist/{session-ERGUFDDI.js.map → session-ACSFC3UB.js.map} +0 -0
- /package/dist/{slack-WE7THLLH.js.map → slack-ZEK4GRND.js.map} +0 -0
- /package/dist/{spec-SEOY7N3L.js.map → spec-XPIRRSV6.js.map} +0 -0
- /package/dist/{src-CCK3TKBX.js.map → src-N7ZCYCXU.js.map} +0 -0
- /package/dist/{tag-GIFEWGBL.js.map → src-XSBBMVGW.js.map} +0 -0
- /package/dist/{start-EPGLHTND.js.map → start-DKWLOQI6.js.map} +0 -0
- /package/dist/{status-DTE2GXM2.js.map → status-K7KH5DI3.js.map} +0 -0
- /package/dist/{trace-RWQDYL4K.js.map → tag-2Y3OMQQC.js.map} +0 -0
- /package/dist/{task-VLJCHSFB.js.map → task-4PIOC4QV.js.map} +0 -0
- /package/dist/{triage-6UAXLCGU.js.map → trace-QPXHYBLA.js.map} +0 -0
- /package/dist/{update-check-QRREAM3N.js.map → triage-EZABRZZM.js.map} +0 -0
- /package/dist/{upgrade-5Y655TQ6.js.map → update-check-E3X7UIY6.js.map} +0 -0
- /package/dist/{utilities-SUON2KZK.js.map → upgrade-EJGTMW44.js.map} +0 -0
- /package/dist/{usage-KCXFY46V.js.map → usage-GZCQDULF.js.map} +0 -0
- /package/dist/{workflow-debug-RACNWWOL.js.map → utilities-RIITD53A.js.map} +0 -0
- /package/dist/{visual-GJZVJC32.js.map → visual-FH67OKS2.js.map} +0 -0
- /package/dist/{workflow-cache-PFBTWLGM.js.map → workflow-cache-YQ3BGJIG.js.map} +0 -0
- /package/dist/{workflow-cache-convergence-resolve-UZGRPC3B.js.map → workflow-cache-convergence-resolve-SPLBRSNK.js.map} +0 -0
- /package/dist/{workflow-feedback-RJIQ5R3R.js.map → workflow-feedback-6UOTIWIQ.js.map} +0 -0
- /package/dist/{workflow-fork-LINDCYJ3.js.map → workflow-fork-IDYHAHCX.js.map} +0 -0
- /package/dist/{workflow-proposals-E4EXKAGM.js.map → workflow-proposals-MMVNIQT3.js.map} +0 -0
- /package/dist/{workflow-revisions-5M6APN6R.js.map → workflow-revisions-BPUOLCZB.js.map} +0 -0
- /package/dist/{workflow-status-7KL73WS2.js.map → workflow-status-RA3IEMEW.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/workflow.ts","../src/workflow-create.ts","../src/workflow-get.ts","../src/workflow-format.ts","../src/workflow-list.ts","../src/workflow-cancel.ts","../src/workflow-run.ts","../src/cache-only-failure.ts","../src/workflow-runs.ts","../src/workflow-sync.ts","../src/workflow-api-sequence.ts","../src/workflow-api-sequence-cmds.ts","../src/workflow-seed-create.ts","../../content/src/workflow-guide/overview.txt","../../content/src/workflow-guide/node-types.txt","../../content/src/workflow-guide/spec-grammar.txt","../../content/src/workflow-guide/action-nodes.txt","../../content/src/workflow-guide/playbook.txt","../../content/src/workflow-guide/best-practices.txt","../../content/src/workflow-guide/macros.txt","../../content/src/workflow-guide/seed-workflows.txt","../../content/src/workflow-guide/seed-users.txt","../../content/src/workflow-guide/data-lifecycle.txt","../../content/src/workflow-guide/assertions.txt","../../content/src/workflow-guide/api-sequences.txt","../../content/src/workflow-guide/cli-seeds.txt","../../content/src/workflow-guide/cli-api-sequences.txt","../../content/src/workflow-guide/cli-chat-evals.txt","../../content/src/workflow-guide/write-a-test.txt","../../content/src/workflow-guide/prove-changes.txt","../../content/src/workflow-guide/visual-checkpoints.txt","../../content/src/workflow-guide/index.ts"],"sourcesContent":["/**\n * CLI Workflow Management\n *\n * Inspect workflow definitions and steps from the terminal.\n */\n\nimport fs from 'node:fs/promises';\nimport process from 'node:process';\nimport { resolveConfig, getArgValue, hasFlag } from './auth.js';\nimport {\n apiRequest,\n fetchWorkflowEnvironments,\n getGuideSectionArg,\n readTextOrFile,\n renderWorkflowUserError,\n stripOneTrailingNewline,\n resolveEnvironmentByNameOrId,\n} from './cli-helpers.js';\nimport { fetchOrExit } from './api-fetch.js';\nimport { applyWorkflowTagFlags } from './tag.js';\nimport { specExtension, writeRawOutput } from './brand.js';\nimport { handleWorkflowCreate } from './workflow-create.js';\nimport { handleWorkflowGet } from './workflow-get.js';\nimport { handleWorkflowList } from './workflow-list.js';\nimport { handleWorkflowCancel } from './workflow-cancel.js';\nimport { handleWorkflowRun } from './workflow-run.js';\nimport { runWorkflowRuns } from './workflow-runs.js';\nimport { handleWorkflowSync } from './workflow-sync.js';\nimport { handleWorkflowGenerateApiSequence } from './workflow-api-sequence.js';\nimport { handleWorkflowApiSequence } from './workflow-api-sequence-cmds.js';\nimport { handleWorkflowSeedCreate } from './workflow-seed-create.js';\nimport { WORKFLOW_GUIDE_SECTIONS } from '@chatsdet/content/workflow-guide';\nimport { topoOrderNodes } from '@chatsdet/workflow-diff';\nimport { printGuide } from '@chatsdet/content';\nimport {\n USER_SETTABLE_WORKFLOW_STATUSES,\n WORKFLOW_FLOW_TYPES,\n isWorkflowFlowType,\n isBrowserViewportPreset,\n} from '@chatsdet/types';\nimport type { PullWorkflow } from '@chatsdet/canary-spec';\nimport { getNodeTitle, type WorkflowDetailResponse } from './workflow-format.js';\n\nexport { shouldPrintWorkflowUrlTrailer } from './workflow-get.js';\n\nconst WORKFLOW_STATUS_DESCRIPTIONS: Record<\n (typeof USER_SETTABLE_WORKFLOW_STATUSES)[number],\n string\n> = {\n draft: 'not yet approved — no human has signed off on the spec',\n approved: 'a human verified the test checks the right thing',\n};\n\nconst formatWorkflowStatusList = (): string =>\n USER_SETTABLE_WORKFLOW_STATUSES.map((s) => `${s} (${WORKFLOW_STATUS_DESCRIPTIONS[s]})`).join(\n ', '\n );\n\n/* ── Patch Handler ───────────────────────────────────────────────────── */\n\ntype WorkflowUpdateResponse = {\n ok: boolean;\n error?: string;\n workflow?: { id: string; name: string; status: string; flowType: string };\n};\n\nexport async function handlePatch(argv: string[], apiUrl: string, token: string): Promise<void> {\n const viewport = getArgValue(argv, '--viewport');\n const workflowId = argv.find((a) => !a.startsWith('-') && a !== viewport);\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n console.error(\n 'Usage: canary workflow patch <workflowId> [--name ...] [--description <text|@file>] [--preflight <text|@file>] [--cleanup <text|@file>] [--status ...] [--flow-type ...] [--viewport <preset|default>] [--default-environment <name|id>] [--clear-default-environment] [--any-environment] [--eligible-env-types permanent,sandbox] [--eligible-environments <names|ids>]'\n );\n process.exit(1);\n }\n\n if (hasFlag(argv, '--viewport') && viewport === undefined) {\n console.error('Error: --viewport requires a preset or default.');\n process.exit(1);\n }\n\n const name = getArgValue(argv, '--name');\n const description = getArgValue(argv, '--description');\n const preflight = getArgValue(argv, '--preflight');\n const cleanup = getArgValue(argv, '--cleanup');\n const status = getArgValue(argv, '--status');\n const flowType = getArgValue(argv, '--flow-type');\n const seedOutputsJsonRaw = getArgValue(argv, '--seed-outputs-json');\n const seedOutputsFile = getArgValue(argv, '--seed-outputs-file');\n const teardownEnabledRaw = getArgValue(argv, '--teardown-enabled');\n const jsonOutput = hasFlag(argv, '--json');\n\n // Environment config flags (resolved name→id against the flow's property).\n const defaultEnvironment = getArgValue(argv, '--default-environment');\n const clearDefaultEnvironment = hasFlag(argv, '--clear-default-environment');\n const anyEnvironment = hasFlag(argv, '--any-environment');\n const eligibleEnvTypes = getArgValue(argv, '--eligible-env-types');\n const eligibleEnvironments = getArgValue(argv, '--eligible-environments');\n const hasEnvFlag =\n defaultEnvironment !== undefined ||\n clearDefaultEnvironment ||\n anyEnvironment ||\n eligibleEnvTypes !== undefined ||\n eligibleEnvironments !== undefined;\n\n const hasTagFlag =\n getArgValue(argv, '--tags') !== undefined ||\n getArgValue(argv, '--tags-add') !== undefined ||\n getArgValue(argv, '--tags-remove') !== undefined ||\n getArgValue(argv, '--tag-id') !== undefined;\n\n if (\n !name &&\n !description &&\n preflight === undefined &&\n cleanup === undefined &&\n !status &&\n !flowType &&\n !seedOutputsJsonRaw &&\n !seedOutputsFile &&\n teardownEnabledRaw === undefined &&\n viewport === undefined &&\n !hasTagFlag &&\n !hasEnvFlag\n ) {\n console.error(\n 'Error: No fields to update. Provide at least one of: --name, --description, --preflight, --cleanup, --status, --flow-type, --seed-outputs-json, --seed-outputs-file, --teardown-enabled, --viewport, --tags, --tags-add, --tags-remove, --tag-id, --default-environment, --clear-default-environment, --any-environment, --eligible-env-types, --eligible-environments'\n );\n process.exit(1);\n }\n\n if (teardownEnabledRaw !== undefined && teardownEnabledRaw !== 'true' && teardownEnabledRaw !== 'false') {\n console.error('Error: --teardown-enabled takes true or false.');\n process.exit(1);\n }\n\n if (anyEnvironment && (eligibleEnvTypes !== undefined || eligibleEnvironments !== undefined)) {\n console.error(\n 'Error: --any-environment is mutually exclusive with --eligible-env-types / --eligible-environments.'\n );\n process.exit(1);\n }\n if (clearDefaultEnvironment && defaultEnvironment !== undefined) {\n console.error(\n 'Error: --clear-default-environment is mutually exclusive with --default-environment.'\n );\n process.exit(1);\n }\n\n if (status && !(USER_SETTABLE_WORKFLOW_STATUSES as readonly string[]).includes(status)) {\n console.error(`Error: Invalid status \"${status}\". Valid: ${formatWorkflowStatusList()}`);\n process.exit(1);\n }\n\n if (flowType && !isWorkflowFlowType(flowType)) {\n console.error(\n `Error: Invalid flow type \"${flowType}\". Must be one of: ${WORKFLOW_FLOW_TYPES.join(', ')}`\n );\n process.exit(1);\n }\n\n const body: Record<string, unknown> = {};\n if (viewport !== undefined) {\n if (viewport !== 'default' && !isBrowserViewportPreset(viewport)) {\n console.error('Error: --viewport requires desktop, desktop_large, laptop, tablet, mobile, or default.');\n process.exit(1);\n }\n body.viewportSize = viewport === 'default' ? null : viewport;\n }\n if (name) body.name = name;\n const descriptionText = description ? stripOneTrailingNewline(readTextOrFile(description)) : '';\n if (descriptionText) body.description = descriptionText;\n // `!== undefined` (not truthiness, unlike --description) so `--preflight \"\"`\n // clears notes an author is moving out of a stale preflight.\n if (preflight !== undefined) body.preflight = stripOneTrailingNewline(readTextOrFile(preflight)) || null;\n if (cleanup !== undefined) body.cleanup = stripOneTrailingNewline(readTextOrFile(cleanup)) || null;\n if (status) body.status = status;\n if (flowType) body.flowType = flowType;\n if (teardownEnabledRaw !== undefined) body.teardownEnabled = teardownEnabledRaw === 'true';\n\n if (seedOutputsJsonRaw || seedOutputsFile) {\n let raw: string;\n if (seedOutputsFile) {\n try {\n raw = await fs.readFile(seedOutputsFile, 'utf-8');\n } catch (err) {\n console.error(\n `Error reading ${seedOutputsFile}: ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n } else {\n raw = seedOutputsJsonRaw!;\n }\n try {\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) {\n throw new Error('seedOutputsJson must be a JSON array');\n }\n body.seedOutputsJson = parsed;\n } catch (err) {\n console.error(\n `Error: Invalid --seed-outputs-json: ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n }\n\n // Environment config: resolve named envs against the flow's property (the\n // GET payload already carries `environments` + eligibility), then build the\n // `defaultEnvironmentId` / `environmentConstraints` body fields.\n if (hasEnvFlag) {\n if (anyEnvironment) body.environmentConstraints = null;\n if (eligibleEnvTypes !== undefined) {\n const types = eligibleEnvTypes\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n const valid = ['permanent', 'ephemeral', 'local', 'sandbox'];\n const bad = types.filter((t) => !valid.includes(t));\n if (bad.length > 0) {\n console.error(`Error: invalid env type(s): ${bad.join(', ')}. Valid: ${valid.join(', ')}`);\n process.exit(1);\n }\n body.environmentConstraints = { mode: 'envTypes', types };\n }\n if (clearDefaultEnvironment) body.defaultEnvironmentId = null;\n\n const needsResolution = defaultEnvironment !== undefined || eligibleEnvironments !== undefined;\n if (needsResolution) {\n const envs = await fetchWorkflowEnvironments(apiUrl, token, workflowId);\n if (defaultEnvironment !== undefined) {\n body.defaultEnvironmentId = resolveEnvironmentByNameOrId(envs, defaultEnvironment);\n }\n if (eligibleEnvironments !== undefined) {\n const ids = eligibleEnvironments\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean)\n .map((nameOrId) => resolveEnvironmentByNameOrId(envs, nameOrId));\n body.environmentConstraints = { mode: 'only', environmentIds: ids };\n }\n }\n }\n\n let tagResult: Awaited<ReturnType<typeof applyWorkflowTagFlags>> = null;\n\n if (Object.keys(body).length > 0) {\n const result = await apiRequest<WorkflowUpdateResponse>(\n apiUrl,\n token,\n 'PUT',\n `/workflows/${workflowId}`,\n body\n );\n\n if (!result.ok) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify({ ok: false, error: result.error ?? 'Unknown error' }, null, 2));\n } else {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n }\n process.exit(1);\n }\n }\n\n if (hasTagFlag) {\n try {\n tagResult = await applyWorkflowTagFlags({ apiUrl, token, argv, workflowId });\n } catch (err) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(\n { ok: false, error: err instanceof Error ? err.message : String(err) },\n null,\n 2\n )\n );\n } else {\n console.error(`Error applying tags:\\n${err instanceof Error ? err.message : String(err)}`);\n }\n process.exit(1);\n }\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(\n { ok: true, workflowId, updated: body, tags: tagResult?.tagIds ?? null },\n null,\n 2\n )\n );\n return;\n }\n\n const updatedKeys = Object.keys(body);\n if (updatedKeys.length > 0) {\n console.log(`Workflow ${workflowId} updated (${updatedKeys.join(', ')}).`);\n }\n if (tagResult) {\n console.log(`Tags: ${tagResult.tagIds.length} assigned.`);\n }\n}\n\n/* ── Archive / Unarchive Handlers ────────────────────────────────────── */\n\nasync function handleArchive(argv: string[], apiUrl: string, token: string): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n console.error('Usage: canary workflow archive <workflowId> [--yes] [--json]');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const skipConfirm = hasFlag(argv, '--yes', '-y');\n\n if (!skipConfirm) {\n if (!process.stdin.isTTY) {\n console.error(\n 'Error: Archiving requires confirmation. Pass --yes (or -y) for non-interactive use.'\n );\n process.exit(1);\n }\n process.stdout.write(\n `Archive workflow ${workflowId}? It will be hidden from lists and skipped by test suites. [y/N] `\n );\n const answer = await new Promise<string>((resolve) => {\n process.stdin.setEncoding('utf-8');\n process.stdin.once('data', (chunk) => resolve(String(chunk).trim().toLowerCase()));\n });\n if (answer !== 'y' && answer !== 'yes') {\n console.error('Aborted.');\n process.exit(1);\n }\n }\n\n type ArchiveResult = { ok: boolean; success?: boolean; archived?: boolean; error?: string };\n const result = await apiRequest<ArchiveResult>(\n apiUrl,\n token,\n 'DELETE',\n `/workflows/${workflowId}`\n );\n\n if (result.error) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n } else {\n renderWorkflowUserError(result);\n }\n process.exit(1);\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n } else {\n console.log(\n `Archived workflow ${workflowId}. Use 'canary workflow unarchive ${workflowId}' to restore.`\n );\n }\n}\n\nasync function handleUnarchive(argv: string[], apiUrl: string, token: string): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n console.error('Usage: canary workflow unarchive <workflowId> [--json]');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n\n type UnarchiveResult = { ok: boolean; error?: string };\n const result = await apiRequest<UnarchiveResult>(\n apiUrl,\n token,\n 'POST',\n `/workflows/${workflowId}/unarchive`,\n {}\n );\n\n if (result.error) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n } else {\n renderWorkflowUserError(result);\n }\n process.exit(1);\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n } else {\n console.log(`Restored workflow ${workflowId}.`);\n }\n}\n\n/* ── Approve / Promote / Pause Handlers ──────────────────────────────── */\n\nconst APPROVAL_GUIDANCE = [\n 'Approving a test asserts that a HUMAN has verified it tests the right thing.',\n '',\n 'If you are an agent running this command on behalf of a user:',\n ' - Describe to the user what this test does and what approval means.',\n ' - Confirm the user has personally verified the test is correct.',\n ' - Only re-run with --yes after the user explicitly confirms.',\n '',\n 'Approval alone does NOT include the test in suites — a flow becomes eligible for',\n 'suite runs once it is approved AND has passed at least once.',\n].join('\\n');\n\nasync function handleApprove(argv: string[], apiUrl: string, token: string): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n console.error('Usage: canary workflow approve <workflowId> [--yes] [--json]');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n\n if (!hasFlag(argv, '--yes')) {\n console.error(APPROVAL_GUIDANCE);\n console.error(`\\nRe-run with --yes to approve: canary workflow approve ${workflowId} --yes`);\n process.exit(1);\n }\n\n type ApproveResult = {\n ok: boolean;\n error?: string;\n code?: string;\n workflow?: { id: string; name: string; status: string; approvedAt: string | null };\n };\n const result = await apiRequest<ApproveResult>(\n apiUrl,\n token,\n 'POST',\n `/workflows/${workflowId}/approve`,\n {}\n );\n\n if (result.error) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n } else {\n console.error(`Error: ${result.error}`);\n }\n process.exit(1);\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify({ ok: true, workflowId, workflow: result.workflow ?? null }, null, 2)\n );\n return;\n }\n console.log(`Workflow ${workflowId} approved.`);\n console.log(\n `It becomes eligible for suite runs once it has also passed at least once ` +\n `(run it with: canary workflow run ${workflowId}).`\n );\n}\n\n// Promote a flow into suite runs (promotion model / `workflow.eligibility` flag OFF).\n// The CLI can't cheaply resolve the org's flag, so both `promote` and `pause`/`unpause`\n// stay available; the server branches on the org model for pause/unpause.\nasync function handlePromote(argv: string[], apiUrl: string, token: string): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n console.error('Usage: canary workflow promote <workflowId> [--force] [--json]');\n process.exit(1);\n }\n\n const force = hasFlag(argv, '--force');\n const jsonOutput = hasFlag(argv, '--json');\n\n type PromoteResult = {\n ok: boolean;\n error?: string;\n code?: string;\n workflow?: { id: string; name: string; promotion: string | null };\n };\n const result = await apiRequest<PromoteResult>(\n apiUrl,\n token,\n 'POST',\n `/workflows/${workflowId}/promote`,\n force ? { force: true } : {}\n );\n\n if (result.error) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n } else {\n const hint =\n result.code === 'FLOW_NOT_READY_TO_PROMOTE'\n ? '\\n Trigger a successful run first (canary workflow run <id>), or pass --force.'\n : result.code === 'PROMOTION_REQUIRES_APPROVAL'\n ? `\\n Approve the test first: canary workflow approve ${workflowId} --yes\\n (Approval asserts a human verified the test checks the right thing — it cannot be forced.)`\n : '';\n console.error(`Error: ${result.error}${hint}`);\n }\n process.exit(1);\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify({ ok: true, workflowId, workflow: result.workflow ?? null }, null, 2)\n );\n return;\n }\n console.log(`Workflow ${workflowId} promoted — it will run when test suites run.`);\n}\n\nasync function handlePauseToggle(\n argv: string[],\n apiUrl: string,\n token: string,\n paused: boolean\n): Promise<void> {\n const action = paused ? 'pause' : 'unpause';\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n console.error(`Usage: canary workflow ${action} <workflowId> [--reason \"...\"] [--json]`);\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const reason = getArgValue(argv, '--reason');\n\n type PauseResult = {\n ok: boolean;\n error?: string;\n code?: string;\n workflow?: { id: string; name: string; paused: boolean };\n };\n const result = await apiRequest<PauseResult>(\n apiUrl,\n token,\n 'POST',\n `/workflows/${workflowId}/${action}`,\n reason ? { reason } : {}\n );\n\n if (result.error) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n } else {\n console.error(`Error: ${result.error}`);\n }\n process.exit(1);\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify({ ok: true, workflowId, workflow: result.workflow ?? null }, null, 2)\n );\n return;\n }\n if (paused) {\n console.log(`Workflow ${workflowId} paused — excluded from suite runs until unpaused.`);\n } else {\n console.log(`Workflow ${workflowId} unpaused — it runs in suites again once eligible.`);\n }\n}\n\n/* ── Node Patch Handler ──────────────────────────────────────────────── */\n\nfunction getAllArgValues(argv: string[], flag: string): string[] {\n const values: string[] = [];\n for (let i = 0; i < argv.length; i++) {\n if (argv[i] === flag && i + 1 < argv.length) {\n values.push(argv[i + 1]!);\n i++;\n }\n }\n return values;\n}\n\nexport async function handleNodePatch(\n argv: string[],\n apiUrl: string,\n token: string\n): Promise<void> {\n const positional = argv.filter((a) => !a.startsWith('-'));\n const workflowId = positional[0];\n const nodeId = positional[1];\n\n if (!workflowId || !nodeId) {\n console.error('Error: Missing workflow ID and/or node ID.');\n console.error(\n 'Usage: canary workflow node patch <workflowId> <nodeId> --set-input key=value [--config \\'{\"...\"}\\'] [--json]'\n );\n process.exit(1);\n }\n\n const configArg = getArgValue(argv, '--config');\n const setInputArgs = getAllArgValues(argv, '--set-input');\n const jsonOutput = hasFlag(argv, '--json');\n\n if (!configArg && setInputArgs.length === 0) {\n console.error(\n 'Error: No changes specified. Provide --set-input key=value and/or --config \\'{\"...\"}\\''\n );\n process.exit(1);\n }\n\n // Build configJson from flags\n let configJson: Record<string, unknown> = {};\n\n if (configArg) {\n try {\n configJson = JSON.parse(configArg) as Record<string, unknown>;\n } catch (e) {\n console.error(\n `Error: Invalid JSON in --config: ${e instanceof Error ? e.message : String(e)}`\n );\n process.exit(1);\n }\n }\n\n // Fetch current state for before/after diff\n const getRes = await fetchOrExit(`${apiUrl}/workflows/${workflowId}`, {\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n token,\n });\n const getResult = (await getRes.json()) as WorkflowDetailResponse;\n if (!getResult.workflow) {\n console.error(`Error: Workflow not found.`);\n process.exit(1);\n }\n\n const existingNode = getResult.workflow.nodes.find((n) => n.id === nodeId);\n if (!existingNode) {\n console.error(`Error: Node ${nodeId} not found in workflow ${workflowId}.`);\n console.error('\\nAvailable nodes:');\n for (const n of topoOrderNodes(getResult.workflow.nodes, getResult.workflow.edges ?? [])) {\n console.error(` ${n.id} [${n.nodeType}] ${getNodeTitle(n)}`);\n }\n process.exit(1);\n }\n\n // The server merges configJson one level deep, so inputValues is replaced\n // wholesale: seed it from the node's current inputs so only named keys change.\n if (configJson.inputValues !== undefined || setInputArgs.length > 0) {\n const inputValues: Record<string, unknown> = {\n ...(existingNode.configJson?.inputValues as Record<string, unknown> | undefined),\n ...(configJson.inputValues as Record<string, unknown> | undefined),\n };\n for (const arg of setInputArgs) {\n const eqIdx = arg.indexOf('=');\n if (eqIdx === -1) {\n console.error(`Error: --set-input must be key=value, got: \"${arg}\"`);\n process.exit(1);\n }\n inputValues[arg.slice(0, eqIdx)] = arg.slice(eqIdx + 1);\n }\n configJson.inputValues = inputValues;\n }\n\n // Apply the patch\n const patchRes = await fetchOrExit(`${apiUrl}/workflows/${workflowId}/nodes/${nodeId}`, {\n method: 'PUT',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n token,\n body: JSON.stringify({ configJson }),\n });\n\n if (!patchRes.ok) {\n const errBody = await patchRes.text();\n if (jsonOutput) {\n console.log(errBody || JSON.stringify({ ok: false, status: patchRes.status }, null, 2));\n } else {\n let rendered: string | null = null;\n try {\n const parsed = JSON.parse(errBody) as Record<string, unknown>;\n rendered = renderWorkflowUserError(parsed);\n } catch {\n rendered = null;\n }\n console.error(rendered ?? `Error (${patchRes.status}): ${errBody.slice(0, 500)}`);\n }\n process.exit(1);\n }\n\n const patchResult = (await patchRes.json()) as { node: PullWorkflow['nodes'][number] };\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify({ ok: true, node: patchResult.node }, null, 2));\n return;\n }\n\n // Show before/after diff\n const title = getNodeTitle(existingNode);\n console.log(`Updated node [${existingNode.nodeType}] \"${title}\" (${nodeId}):\\n`);\n\n const oldConfig = existingNode.configJson ?? {};\n for (const [key, newVal] of Object.entries(configJson)) {\n if (\n typeof newVal === 'object' &&\n newVal !== null &&\n typeof oldConfig[key] === 'object' &&\n oldConfig[key] !== null\n ) {\n // Diff nested objects (e.g. inputValues)\n const oldObj = oldConfig[key] as Record<string, unknown>;\n const newObj = newVal as Record<string, unknown>;\n for (const [subKey, subVal] of Object.entries(newObj)) {\n const oldVal = oldObj[subKey];\n if (oldVal !== subVal) {\n console.log(\n ` ${key}.${subKey}: ${JSON.stringify(oldVal ?? null)} -> ${JSON.stringify(subVal)}`\n );\n }\n }\n } else {\n const oldVal = oldConfig[key];\n if (oldVal !== newVal) {\n console.log(` ${key}: ${JSON.stringify(oldVal ?? null)} -> ${JSON.stringify(newVal)}`);\n }\n }\n }\n}\n\n/* ── Help & Entry Point ───────────────────────────────────────────────── */\n\nfunction printWorkflowHelp(): void {\n console.log(\n [\n 'Usage: canary workflow <sub-command> [options]',\n '',\n ' Tip: Run \"canary workflow guide\" for the full authoring reference',\n ' (node types, playbooks, macros, seeds, assertions, best practices, visual checkpoints)',\n '',\n 'Sub-commands:',\n ' guide [section] [--json] Authoring guide (node-types, macros, visual-checkpoints, etc.)',\n ' list [options] List workflows',\n ' get <workflowId> [options] Get workflow definition with steps',\n ' create [options] Create workflow from JSON',\n ' sync <workflowId> [options] Replace all nodes (same format as create)',\n ' fork <verb> Create a fork / map fork nodes back to origin',\n ' patch <workflowId> [options] Update workflow properties',\n ' approve <workflowId> [--yes] [--json] Mark the test as human-verified (spec is right)',\n ' promote <workflowId> [--force] [--json] Include the test in suite runs (promotion model; requires approval)',\n ' status <workflowId> [--set <status>] Show or change the management status (blocked, paused, …)',\n ' events <workflowId> [--limit <n>] [--json] Audit timeline: status changes + node (de)activations',\n ' revisions <list|get|restore> <workflowId> [number] Immutable definition history',\n ' event ticket <wfId> <eventId> --add|--remove Attach/detach tickets on an event',\n ' pause <workflowId> [--reason \"…\"] [--json] Exclude the test from suite runs (idempotent)',\n ' unpause <workflowId> [--reason \"…\"] [--json] Re-include the test in suite runs (idempotent)',\n ' archive <workflowId> [--yes] [--json] Soft-delete: hide from lists, skip in test suites (reversible)',\n ' unarchive <workflowId> [--json] Restore a previously archived workflow',\n ' run <workflowId> [--cache-only] [options] Trigger a workflow execution (--cache-only waits; --sandbox <id>: on a sandbox you claimed)',\n ' cancel <runId> [--workflow <id>] [--json] Cancel a running workflow run',\n ' api-sequence <verb> <workflowId> Manage the API sequence attached to a workflow',\n ' generate-api-sequence <workflowId> [opts] (deprecated alias for `api-sequence generate`)',\n ' seed <sub-command> Create seed workflows',\n ' node <sub-command> Manage individual nodes',\n ' runs <sub-command> Query workflow run results',\n ' debug <runId|sub-command> Debug a run (overview/steps/cache/thoughts/logs/trace)',\n '',\n 'List options:',\n ' --search <query> Search by name',\n ` --flow-type <type> Filter: ${WORKFLOW_FLOW_TYPES.join(', ')}`,\n ' --status <status> Filter: draft, approved',\n ' --page <n> Page number (default: 1)',\n ' --page-size <n> Page size (default: 25)',\n ' --json Output raw JSON',\n '',\n 'Get options:',\n ' --format json|markdown|spec Output format (default: json)',\n ' --json Shorthand for --format json',\n ` --markdown Shorthand for editable ${specExtension} spec output`,\n ' --output <file> Write output to file',\n '',\n 'Create options:',\n ' --from-stdin Read workflow JSON from stdin (default)',\n ' --from-file <path> Read workflow JSON from file',\n ' --api-only Create an API-only workflow with a backing ApiSequence',\n ' Requires: --name <name>, and',\n ' --sequence-from-file <path> or --sequence-from-stdin',\n ' Optional: --credential <id>, --guidance <text>',\n ' Input shape: { steps, description?, stopOnFailure?, exports? }',\n ' Returns: { workflowId, apiSequenceId, nodeId }',\n ' --tags <names> Comma-separated tag names to assign (names, not IDs)',\n ' --tag-id <ids> Comma-separated raw tag IDs (escape hatch)',\n '',\n ' Input: { name, nodes: [{ nodeType, configJson }] }',\n ' Run \"canary workflow guide node-types\" for available node types.',\n ' Run \"canary workflow guide macros\" for dynamic test data ($EMAIL(), $RANDOM_STRING(6), etc.)',\n '',\n 'Sync options:',\n ' --from-file <path> Read nodes JSON from file',\n ' --from-stdin Read nodes JSON from stdin',\n ' --no-snapshot Skip creating a draft snapshot before sync',\n ' --propose Create a proposal instead of applying directly',\n ' --title <title> Proposal title (with --propose)',\n ' --description <desc> Proposal description (with --propose)',\n ' --json Output raw JSON',\n '',\n ' Sync accepts the same minimal node format as create.',\n ' Edges, IDs, positions, and ordering are auto-generated when omitted.',\n ' Input: { nodes: [{ nodeType, configJson }] }',\n '',\n ' When using --propose on an existing workflow, run `canary workflow get',\n \" <id>` first and reuse each node's existing `id` for steps you intend\",\n ' to keep. Only omit `id` for genuinely new steps. Without ID reuse the',\n ' proposal will diff as a full remove-everything/add-everything rewrite.',\n '',\n 'Patch options:',\n ' --name <name> Update workflow name',\n ' --description <text|@file> Update description: the spirit of the test, in one or two sentences',\n ' --preflight <text|@file> Update preflight: what the test depends on (data, flags, third parties; \"\" clears)',\n \" --cleanup <text|@file> Update cleanup: how the test's side effects get reset (\\\"\\\" clears)\",\n ' --status <status> Set status (approval axis). Valid:',\n ' draft — not yet approved',\n ' approved — a human verified the test checks the right thing',\n ' (suite inclusion is derived eligibility — approved AND',\n ' passed at least once — with a separate pause/unpause toggle;',\n ' reliability is tracked automatically by health)',\n ` --flow-type <type> Set type: ${WORKFLOW_FLOW_TYPES.join(', ')}`,\n ' --viewport <preset|default> Save a viewport for ordinary runs and suites; default inherits the organization setting',\n ' --seed-outputs-json <json> Replace seedOutputsJson (array) — seed flows only',\n ' --seed-outputs-file <path> Replace seedOutputsJson from a JSON file',\n ' --teardown-enabled <true|false> Run the paired teardown after each consuming flow — seed flows only',\n ' --tags <names> Replace tags with these names (comma-separated)',\n ' --tags-add <names> Add these tag names to the existing set',\n ' --tags-remove <names> Remove these tag names from the existing set',\n ' --tag-id <ids> Raw tag IDs (comma-separated)',\n ' --json Output raw JSON',\n '',\n 'Approve options:',\n ' --yes Confirm approval (required non-interactively)',\n ' --json Output raw JSON',\n '',\n ' Approval asserts a human verified the test checks the right thing.',\n ' Agents: describe the test to the user and confirm they personally',\n ' verified it before re-running with --yes.',\n '',\n 'Promote options (promotion model):',\n ' --force Promote without requiring a successful run (skips the',\n ' run gate; the approval gate can never be forced)',\n ' --json Output raw JSON',\n '',\n ' Promote includes the test in suite runs on the legacy promotion model.',\n ' Requires the test to be approved, and (without --force) a passing run.',\n '',\n 'Status options (management status — the manual lifecycle axis):',\n ' --set <status> Transition to: active, paused, blocked,',\n ' under_construction, deprecated',\n ' --reason <text|@file> Auditable reason recorded on the change event',\n ' --ticket <iss_…|url> Attach a ticket to the event (repeatable) —',\n ' an internal issue id or an external Linear/Jira URL',\n ' --json Output raw JSON',\n '',\n ' Distinct from approval (`patch --status`) and computed health. Any',\n ' non-active status excludes the flow from suite runs. Every change is',\n ' recorded as a workflow event (who/when/why) shown in the Comments tab',\n ' and via `workflow events`. Without --set, prints all three axes.',\n '',\n 'Pause / unpause options:',\n ' --reason <text> Auditable reason recorded on the change event',\n ' --json Output raw JSON',\n '',\n ' On the eligibility model, a flow is eligible for suite runs once it is',\n ' approved AND has passed at least once — no explicit promote step. Pause',\n ' excludes a flow from suite runs; unpause re-includes it. Both are',\n ' idempotent (equivalent to `status --set paused|active`). Suites always',\n ' execute the live definition — edits take effect immediately.',\n '',\n 'Run options:',\n ' --viewport <preset> Override the saved workflow viewport for this run only',\n ' --environment <name|id> Run against this environment of the workflow\\'s application (e.g. a sandbox environment)',\n ' --cache-only Replay workflow actions only and wait for completion; authentication may use AI login',\n ' --stream Follow execution until completion',\n ' --json Output raw JSON',\n '',\n 'API Sequence sub-commands:',\n ' api-sequence get <wf> Show config + steps',\n ' api-sequence update <wf> --from-file <f> Replace config',\n ' api-sequence execute <wf> Run the sequence',\n ' api-sequence delete <wf> Delete the sequence',\n ' api-sequence set-api-only <wf> [--off] Toggle workflow apiOnly flag',\n ' api-sequence generate <wf> [--prompt ...] AI-generate a config (streams)',\n '',\n ' Run \"canary workflow guide api-sequences\" for step shape and template syntax.',\n '',\n 'Seed sub-commands:',\n ' seed create [options] Create a seed workflow with outputs',\n '',\n 'Seed create options:',\n ' --name <name> Seed workflow name (required unless JSON input)',\n ' --description <desc> Description',\n ' --output <key:name[:desc]> Declare an output (repeatable)',\n ' --outputs-json <json> Full outputs array as inline JSON',\n ' --from-stdin Read full config from stdin',\n ' --from-file <path> Read full config from file',\n ' --no-teardown Skip creating paired teardown workflow',\n ' --status <status> Initial status (default: draft)',\n ' --json Output raw JSON',\n '',\n 'Node sub-commands:',\n \" node patch <workflowId> <nodeId> [options] Update a node's config\",\n ' node deactivate <wfId> <nodeId> [--reason \"…\"] Skip this node during runs (audited event)',\n ' node activate <wfId> <nodeId> [--reason \"…\"] Re-enable a deactivated node (audited event)',\n '',\n 'Node patch options:',\n ' --set-input key=value Set an inputValue (repeatable)',\n ' --config \\'{\"...\"}\\' Merge arbitrary configJson (partial update)',\n ' --json Output raw JSON',\n '',\n 'Runs sub-commands:',\n ' runs list <workflowId> List runs for a workflow',\n ' runs get <workflowId> <runId> Get run detail with steps',\n ' runs diagnostics <workflowId> <runId> Get failure diagnostic',\n '',\n 'Cache sub-commands:',\n ' cache status <workflowId> Show per-node cache version, health, recent failures',\n ' cache clear <workflowId> [--node <id>] [--below-version <n>] [--stale-only] [--mode all]',\n ' Targeted cache invalidation (rows kept, isValid=false)',\n ' cache clear <workflowId> --mode hard --yes DESTRUCTIVE: delete cache rows, strip playbookSteps,',\n ' null lastRunId. Same as the UI \"Reset flow\" button',\n ' cache optimize <workflowId> [--run <runId>] Enqueue the async cache-optimizer job',\n ' cache optimize-dry --run <runId> [--workflow <id>] Run local deterministic optimizer dry-run',\n ' cache convergence-report <convergenceRunId> [--out <f>] Markdown review doc for a cache-convergence run',\n ' cache convergence-resolve <convergenceRunId> [--reason <t>] Drop a run parked awaiting review (does not merge the fork)',\n '',\n 'Feedback sub-commands:',\n ' feedback list --workflow <id> Show pending + answered/canceled feedback requests',\n ' feedback answer <requestId> --workflow <id> Answer a parked maintenance run\\'s question',\n ' --answer intentional|bug --explanation \"<text>\" (resumes the convergence run)',\n '',\n 'Common options:',\n ' --env <env> Target environment (prod, dev, local)',\n ' --api-url <url> API URL override',\n ' --token <key> API token override',\n ].join('\\n')\n );\n}\n\nexport async function runWorkflow(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === 'help') {\n printWorkflowHelp();\n return;\n }\n\n if (subCommand === 'debug' && hasFlag(rest, '--help', '-h')) {\n const { handleWorkflowDebug } = await import('./workflow-debug.js');\n await handleWorkflowDebug(rest, '', '');\n return;\n }\n\n if (hasFlag(argv, '--help', '-h')) {\n printWorkflowHelp();\n return;\n }\n\n if (subCommand === 'guide') {\n const sectionSlug = getGuideSectionArg(rest);\n const jsonOutput = hasFlag(rest, '--json');\n printGuide(WORKFLOW_GUIDE_SECTIONS, sectionSlug, jsonOutput);\n return;\n }\n\n const { apiUrl, token, appSubdomain } = await resolveConfig(argv);\n\n switch (subCommand) {\n case 'list':\n await handleWorkflowList(rest, apiUrl, token);\n break;\n case 'get':\n await handleWorkflowGet(rest, apiUrl, token, appSubdomain);\n break;\n case 'create':\n await handleWorkflowCreate(rest, apiUrl, token, appSubdomain);\n break;\n case 'patch':\n await handlePatch(rest, apiUrl, token);\n break;\n case 'approve':\n await handleApprove(rest, apiUrl, token);\n break;\n case 'promote':\n await handlePromote(rest, apiUrl, token);\n break;\n case 'pause':\n await handlePauseToggle(rest, apiUrl, token, true);\n break;\n case 'unpause':\n await handlePauseToggle(rest, apiUrl, token, false);\n break;\n case 'archive':\n await handleArchive(rest, apiUrl, token);\n break;\n case 'unarchive':\n await handleUnarchive(rest, apiUrl, token);\n break;\n case 'cancel':\n await handleWorkflowCancel(rest, apiUrl, token);\n break;\n case 'run':\n await handleWorkflowRun(rest, apiUrl, token, appSubdomain);\n break;\n case 'runs':\n await runWorkflowRuns(rest, apiUrl, token);\n break;\n case 'status': {\n const { handleWorkflowStatus } = await import('./workflow-status.js');\n await handleWorkflowStatus(rest, apiUrl, token);\n break;\n }\n case 'events': {\n const { handleWorkflowEvents } = await import('./workflow-status.js');\n await handleWorkflowEvents(rest, apiUrl, token);\n break;\n }\n case 'revisions': {\n const { handleWorkflowRevisions } = await import('./workflow-revisions.js');\n await handleWorkflowRevisions(rest, apiUrl, token);\n break;\n }\n case 'event': {\n const [eventSub, ...eventRest] = rest;\n if (eventSub === 'ticket') {\n const { handleWorkflowEventTicket } = await import('./workflow-status.js');\n await handleWorkflowEventTicket(eventRest, apiUrl, token);\n } else {\n console.error(`Unknown event sub-command: ${eventSub ?? '(none)'}`);\n printWorkflowHelp();\n process.exit(1);\n }\n break;\n }\n case 'node': {\n const [nodeSub, ...nodeRest] = rest;\n if (nodeSub === 'patch') {\n await handleNodePatch(nodeRest, apiUrl, token);\n } else if (nodeSub === 'deactivate' || nodeSub === 'activate') {\n // Audited toggle: hits the dedicated endpoint, which patches\n // configJson.deactivated AND records a workflow event with actor +\n // --reason. A deactivated node is skipped during runs (step status\n // `skipped`), letting you converge a flow node-by-node from the front.\n const { handleNodeDeactivateToggle } = await import('./workflow-status.js');\n await handleNodeDeactivateToggle(nodeRest, apiUrl, token, nodeSub === 'deactivate');\n } else {\n console.error(`Unknown node sub-command: ${nodeSub ?? '(none)'}`);\n printWorkflowHelp();\n process.exit(1);\n }\n break;\n }\n case 'seed': {\n const [seedSub, ...seedRest] = rest;\n if (seedSub === 'create') {\n await handleWorkflowSeedCreate(seedRest, apiUrl, token, appSubdomain);\n } else {\n console.error(`Unknown seed sub-command: ${seedSub ?? '(none)'}`);\n printWorkflowHelp();\n process.exit(1);\n }\n break;\n }\n case 'sync':\n await handleWorkflowSync(rest, apiUrl, token);\n break;\n case 'fork': {\n const { handleWorkflowFork } = await import('./workflow-fork.js');\n await handleWorkflowFork(rest, apiUrl, token);\n break;\n }\n case 'proposals': {\n const { handleWorkflowProposals } = await import('./workflow-proposals.js');\n await handleWorkflowProposals(rest, apiUrl, token);\n break;\n }\n case 'generate-api-sequence':\n // Deprecated alias — forwards to `api-sequence generate`.\n await handleWorkflowGenerateApiSequence(rest, apiUrl, token);\n break;\n case 'api-sequence':\n await handleWorkflowApiSequence(rest, apiUrl, token);\n break;\n case 'cache': {\n const { handleWorkflowCache } = await import('./workflow-cache.js');\n await handleWorkflowCache(rest, apiUrl, token);\n break;\n }\n case 'debug': {\n const { handleWorkflowDebug } = await import('./workflow-debug.js');\n await handleWorkflowDebug(rest, apiUrl, token);\n break;\n }\n case 'feedback': {\n const { handleWorkflowFeedback } = await import('./workflow-feedback.js');\n await handleWorkflowFeedback(rest, apiUrl, token);\n break;\n }\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printWorkflowHelp();\n process.exit(1);\n }\n}\n","/**\n * CLI Workflow Creation\n *\n * Creates a workflow with nodes and edges atomically via the API.\n * Supports reading workflow JSON from stdin or file.\n *\n * @module workflow-create\n */\n\nimport fs from \"node:fs/promises\";\nimport process from \"node:process\";\nimport type { WorkflowFlowType } from \"@chatsdet/types\";\nimport { getArgValue, hasFlag, resolveOrgAppUrl } from \"./auth.js\";\nimport { renderWorkflowUserError, type CredentialListItem } from \"./cli-helpers.js\";\nimport { fetchOrExit } from \"./api-fetch.js\";\nimport { applyWorkflowTagFlags } from \"./tag.js\";\nimport { normalizeNodeType, NODE_TYPE_LABEL } from \"@chatsdet/types\";\nimport type { BrowserViewportPreset } from '@chatsdet/types';\nimport { writeRawOutput } from './brand.js';\n\n/* ── Types ────────────────────────────────────────────────────────────── */\n\ntype WorkflowNodeInput = {\n nodeType: string;\n configJson?: Record<string, unknown>;\n};\n\ntype WorkflowCreateInput = {\n name: string;\n description?: string;\n status?: \"draft\" | \"approved\";\n flowType?: WorkflowFlowType;\n createdVia?: string;\n propertyId?: string;\n credentialId?: string;\n viewportSize?: BrowserViewportPreset | null;\n nodes: WorkflowNodeInput[];\n};\n\ntype CreateResponse = {\n ok: boolean;\n error?: string;\n /** Set on structured user errors (e.g. WORKFLOW_VALIDATION_FAILED). */\n code?: string;\n /** Per-node validation issues, surfaced via renderWorkflowUserError. */\n issues?: unknown[];\n warnings?: string[];\n workflow?: {\n id: string;\n name: string;\n status: string;\n flowType: string;\n createdVia: string | null;\n };\n nodes?: Array<{ id: string; nodeType: string; orderIndex: number }>;\n edges?: Array<{ id: string; sourceNodeId: string; targetNodeId: string }>;\n};\n\n/* ── Input Reading ───────────────────────────────────────────────────── */\n\nasync function readFromStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n const stdin = process.stdin;\n\n if (stdin.isTTY) {\n throw new Error(\"No input on stdin. Pipe workflow JSON or use --from-file.\");\n }\n\n return new Promise((resolve, reject) => {\n stdin.on(\"data\", (chunk) => {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n stdin.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf-8\")));\n stdin.on(\"error\", reject);\n });\n}\n\nasync function readWorkflowInput(argv: string[]): Promise<WorkflowCreateInput> {\n let raw: string;\n\n const fromFile = getArgValue(argv, \"--from-file\");\n if (fromFile) {\n try {\n raw = await fs.readFile(fromFile, \"utf-8\");\n } catch (err) {\n throw new Error(`Failed to read file ${fromFile}: ${err instanceof Error ? err.message : String(err)}`);\n }\n } else {\n raw = await readFromStdin();\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\"Invalid JSON input. Please provide valid workflow JSON.\");\n }\n\n const input = parsed as WorkflowCreateInput;\n\n if (!input.name || typeof input.name !== \"string\") {\n throw new Error('Workflow JSON must include a \"name\" string field.');\n }\n\n if (!Array.isArray(input.nodes) || input.nodes.length === 0) {\n throw new Error('Workflow JSON must include a non-empty \"nodes\" array.');\n }\n\n // Source the allowlist from the canonical node-type set so it never drifts\n // from the server enum (`workflowNodeTypeEnum`). NODE_TYPE_LABEL's keys are\n // that set — including sandbox_action, audio, audio-assertion, and visual_checkpoint.\n const validNodeTypes = Object.keys(NODE_TYPE_LABEL);\n for (const node of input.nodes) {\n // Accept \"acting-as\" as an alias for \"login\" — keep persisted type canonical.\n if (typeof node.nodeType === \"string\") {\n node.nodeType = normalizeNodeType(node.nodeType);\n }\n if (!node.nodeType || !validNodeTypes.includes(node.nodeType)) {\n throw new Error(\n `Invalid nodeType \"${node.nodeType}\". Valid types: ${validNodeTypes.join(\", \")}`\n );\n }\n }\n\n return input;\n}\n\n/* ── Credential Resolution ──────────────────────────────────────────── */\n\nasync function fetchOrgCredentials(\n apiUrl: string,\n token: string\n): Promise<CredentialListItem[]> {\n const res = await fetch(`${apiUrl}/org/credentials`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return [];\n const data = (await res.json()) as { ok: boolean; items: CredentialListItem[] };\n return (data.items ?? []).filter((c) => !c.isEphemeral);\n}\n\n/**\n * Resolve a credential for login nodes that are missing credentialId.\n * Resolution order:\n * 1. Match by credentialName, when given; a name that matches nothing is an\n * error, never another credential (a login node must sign in as who it names)\n * 2. Pick the default credential (isDefault: true)\n * 3. Pick the only non-local credential (if exactly one)\n * 4. Error with available credentials listed so the caller can retry\n */\nasync function resolveCredential(\n apiUrl: string,\n token: string,\n credentialName?: string\n): Promise<{ credentialId: string; credentialName: string; propertyId?: string }> {\n const credentials = await fetchOrgCredentials(apiUrl, token);\n\n if (credentials.length === 0) {\n throw new Error(\n \"No credentials found for this organization. Create one in the web app first.\"\n );\n }\n\n // 1. Match by name if provided\n if (credentialName) {\n const match = credentials.find(\n (c) => c.name.toLowerCase() === credentialName.toLowerCase()\n );\n if (match) {\n const isLocal = /\\blocal\\b/i.test(match.name);\n if (isLocal) {\n console.warn(\n `Warning: Credential \"${match.name}\" appears to be local-only. ` +\n `The workflow may fail in deployed environments. Consider using a non-local credential.`\n );\n }\n return { credentialId: match.id, credentialName: match.name, propertyId: match.propertyId };\n }\n throw new Error(\n `No credential is named \"${credentialName}\". Set the login node's credentialId, ` +\n `or credentialSource \"from_template\" with credentialTemplateId for a persona.\\n\\n` +\n `Available credentials:\\n${credentialLines(credentials)}`\n );\n }\n\n // 2. Pick the default credential\n const defaults = credentials.filter((c) => c.isDefault);\n if (defaults.length === 1) {\n console.log(`Auto-selected default credential: ${defaults[0].name} (${defaults[0].id})`);\n return { credentialId: defaults[0].id, credentialName: defaults[0].name, propertyId: defaults[0].propertyId };\n }\n\n // 3. Pick the only non-local credential\n const nonLocal = credentials.filter((c) => !/\\blocal\\b/i.test(c.name));\n if (nonLocal.length === 1) {\n console.log(`Auto-selected credential: ${nonLocal[0].name} (${nonLocal[0].id})`);\n return { credentialId: nonLocal[0].id, credentialName: nonLocal[0].name, propertyId: nonLocal[0].propertyId };\n }\n\n // 4. Ambiguous — list credentials and error\n throw new Error(\n `Cannot auto-resolve credential. Specify credentialId in the login node configJson.\\n\\n` +\n `Available credentials:\\n${credentialLines(credentials)}`\n );\n}\n\nfunction credentialLines(credentials: CredentialListItem[]): string {\n return credentials\n .map((c) => ` ${c.id} ${c.name}${c.isDefault ? \" (default)\" : \"\"}${c.propertyName ? ` — ${c.propertyName}` : \"\"}`)\n .join(\"\\n\");\n}\n\n/* ── API-only workflow branch ────────────────────────────────────────── */\n\ntype ApiSequenceConfig = {\n steps: unknown[];\n description?: string;\n stopOnFailure?: boolean;\n exports?: unknown[];\n};\n\nasync function readApiSequenceConfig(argv: string[]): Promise<ApiSequenceConfig> {\n const fromFile = getArgValue(argv, \"--sequence-from-file\");\n const fromStdin = hasFlag(argv, \"--sequence-from-stdin\");\n\n if (!fromFile && !fromStdin) {\n throw new Error(\n \"--api-only needs a sequence with at least one step: pass --sequence-from-file <path> or --sequence-from-stdin.\"\n );\n }\n\n let raw: string;\n if (fromFile) {\n raw = await fs.readFile(fromFile, \"utf-8\");\n } else {\n raw = await readFromStdin();\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\"Invalid JSON for sequence config.\");\n }\n\n const cfg = parsed as ApiSequenceConfig;\n if (!cfg || !Array.isArray(cfg.steps)) {\n throw new Error('Sequence config must be { \"steps\": [...] }.');\n }\n return cfg;\n}\n\nasync function handleApiOnlyCreate(\n argv: string[],\n apiUrl: string,\n token: string,\n appSubdomain?: string | null\n): Promise<void> {\n const name = getArgValue(argv, \"--name\");\n if (!name) {\n console.error('Error: --api-only requires --name <workflow name>.');\n process.exit(1);\n }\n\n const credentialId = getArgValue(argv, \"--credential\");\n const guidance = getArgValue(argv, \"--guidance\");\n\n let config: ApiSequenceConfig;\n try {\n config = await readApiSequenceConfig(argv);\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n const body: Record<string, unknown> = { name, config };\n if (credentialId) body.credentialId = credentialId;\n if (guidance) body.guidancePrompt = guidance;\n\n const res = await fetchOrExit(`${apiUrl}/api-sequences/create-with-workflow`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n token,\n body: JSON.stringify(body),\n });\n\n const raw = (await res.json().catch(() => ({}))) as {\n ok: boolean;\n error?: string;\n code?: string;\n issues?: Array<{ path: string; code: string; message: string; hint?: string }>;\n data?: { workflowId: string; apiSequenceId: string; nodeId?: string };\n };\n\n if (!res.ok || !raw.ok || !raw.data) {\n const jsonOutput = hasFlag(argv, \"--json\") || !process.stdout.isTTY;\n if (raw.code === 'API_SEQUENCE_INVALID' && Array.isArray(raw.issues)) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(\n {\n ok: false,\n error: raw.error ?? 'API sequence configuration is invalid',\n code: 'API_SEQUENCE_INVALID',\n issueCount: raw.issues.length,\n issues: raw.issues,\n },\n null,\n 2,\n ),\n );\n } else {\n console.error(`Error: ${raw.error ?? 'API sequence configuration is invalid'}`);\n console.error(`Found ${raw.issues.length} issue${raw.issues.length === 1 ? '' : 's'}:`);\n console.error('');\n for (const issue of raw.issues) {\n console.error(` ${issue.path || '(root)'} [${issue.code}] :: ${issue.message}`);\n if (issue.hint) console.error(` hint: ${issue.hint}`);\n }\n }\n process.exit(1);\n }\n console.error(`Error: ${raw.error ?? `${res.status} ${res.statusText}`}`);\n process.exit(1);\n }\n\n if (hasFlag(argv, \"--json\") || !process.stdout.isTTY) {\n writeRawOutput(JSON.stringify({ ok: true, data: raw.data }, null, 2));\n return;\n }\n\n const appUrl = resolveOrgAppUrl(apiUrl, appSubdomain);\n console.log(`\\n\\u2713 API-only workflow created: ${name}`);\n console.log(` Workflow ID: ${raw.data.workflowId}`);\n console.log(` API Sequence ID: ${raw.data.apiSequenceId}`);\n if (raw.data.nodeId) console.log(` Node ID: ${raw.data.nodeId}`);\n console.log(` Steps: ${config.steps.length}`);\n console.log(` URL: ${appUrl}/flows/${raw.data.workflowId}`);\n console.log(`\\n Next:`);\n console.log(` canary workflow api-sequence get ${raw.data.workflowId}`);\n console.log(` canary workflow api-sequence update ${raw.data.workflowId} --from-file seq.json`);\n console.log(` canary workflow api-sequence execute ${raw.data.workflowId}`);\n}\n\n/* ── Main Handler ────────────────────────────────────────────────────── */\n\nexport async function handleWorkflowCreate(\n argv: string[],\n apiUrl: string,\n token: string,\n appSubdomain?: string | null\n): Promise<void> {\n if (hasFlag(argv, \"--api-only\")) {\n await handleApiOnlyCreate(argv, apiUrl, token, appSubdomain);\n return;\n }\n\n // Auto-publish was removed with the approval/eligibility lifecycle split:\n // a human approves, and a flow becomes eligible for suites once it has also\n // passed at least once (no explicit promote step).\n if (hasFlag(argv, \"--run-and-publish\")) {\n console.error(\n \"Error: --run-and-publish was removed. Run the test (canary workflow run <id>) and\\n\" +\n \"approve it (canary workflow approve <id> --yes); it becomes eligible for suites once it has passed.\"\n );\n process.exit(1);\n }\n\n // 1. Read and validate input\n let input: WorkflowCreateInput;\n try {\n input = await readWorkflowInput(argv);\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n // 2. Resolve credentials for login nodes missing credentialId\n const loginNodes = input.nodes.filter((n) => n.nodeType === \"login\");\n for (const loginNode of loginNodes) {\n const config = loginNode.configJson ?? {};\n // Only a static login names a stored credential; a persona (from_template),\n // a seed's credential or a credential input resolves at run time. Mirrors\n // the server's `needsStaticCredentialResolution` (workflow-node-name-resolution.ts).\n const resolvesAtRunTime =\n config.credentialSource === \"from_template\" ||\n config.credentialSource === \"from_seed\" ||\n Boolean(config.credentialTemplateId || config.credentialInputName || config.seedCredentialRef);\n if (!resolvesAtRunTime && config.performLogin !== false && !config.credentialId && !input.credentialId) {\n try {\n const resolved = await resolveCredential(\n apiUrl,\n token,\n config.credentialName as string | undefined\n );\n config.credentialId = resolved.credentialId;\n config.credentialName = resolved.credentialName;\n loginNode.configJson = config;\n if (resolved.propertyId && !input.propertyId) {\n input.propertyId = resolved.propertyId;\n }\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n }\n }\n\n // All flows start as drafts — approval is an explicit follow-up step\n // (canary workflow approve). A flow becomes eligible for suites once it is\n // approved AND has passed at least once. Reliability is tracked separately\n // by the workflow's `health` (starts at `unverified`).\n input.createdVia = \"cli\";\n\n // 4. Create workflow via API\n const res = await fetchOrExit(`${apiUrl}/workflows/create-with-nodes`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n token,\n body: JSON.stringify(input),\n });\n\n const result = (await res.json()) as CreateResponse;\n\n if (!result.ok || !result.workflow) {\n // Surface per-node validation detail (WORKFLOW_VALIDATION_FAILED carries an\n // `issues` array) instead of the bare catalog message. Same renderer the\n // `workflow run` path uses.\n const rendered = renderWorkflowUserError(result as unknown as Record<string, unknown>);\n console.error(rendered ?? `Error: ${result.error ?? \"Failed to create workflow\"}`);\n process.exit(1);\n }\n\n const { workflow, nodes, edges } = result;\n\n const { warnings } = result;\n\n console.log(`\\n\\u2713 Workflow created: ${workflow.name}`);\n console.log(` ID: ${workflow.id}`);\n console.log(` Status: ${workflow.status}`);\n console.log(` Nodes: ${nodes?.length ?? 0}`);\n console.log(` Edges: ${edges?.length ?? 0}`);\n\n if (warnings && warnings.length > 0) {\n console.log(`\\n Warnings:`);\n for (const w of warnings) {\n console.log(` \\u26A0 ${w}`);\n }\n }\n\n const appUrl = resolveOrgAppUrl(apiUrl, appSubdomain);\n console.log(` URL: ${appUrl}/flows/${workflow.id}`);\n\n // 5. Apply --tags / --tag-id if provided.\n try {\n const tagResult = await applyWorkflowTagFlags({\n apiUrl,\n token,\n argv,\n workflowId: workflow.id,\n });\n if (tagResult) {\n console.log(` Tags: ${tagResult.tagIds.length} assigned`);\n }\n } catch (err) {\n console.error(`\\nError applying tags:\\n${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n console.log(\n `\\n Next: run it (canary workflow run ${workflow.id}) and approve it ` +\n `(canary workflow approve ${workflow.id} --yes). Once approved and passing, ` +\n `it becomes eligible for suite runs.`\n );\n}\n","import fs from 'node:fs/promises';\nimport process from 'node:process';\nimport { getArgValue, hasFlag, resolveOrgAppUrl } from './auth.js';\nimport { apiFetch, exitOnFailure } from './api-fetch.js';\nimport { writeRawOutput } from './brand.js';\nimport {\n formatWorkflowJson,\n formatWorkflowMarkdown,\n type WorkflowDetailResponse,\n} from './workflow-format.js';\n\n/**\n * Whether `workflow get` should append the human-readable `URL: …` trailer.\n *\n * The trailer is a courtesy for a human at a terminal running the bare\n * `workflow get <id>` (which defaults to pretty JSON). It must NOT be emitted\n * for any explicitly requested machine/file format — `--json` / `--format json`\n * or the markdown/spec formats — because the trailing non-JSON line breaks\n * downstream parsers piping stdout.\n */\nexport function shouldPrintWorkflowUrlTrailer(argv: string[]): boolean {\n const jsonOutput = hasFlag(argv, '--json') || getArgValue(argv, '--format') === 'json';\n const markdownOutput =\n hasFlag(argv, '--markdown') ||\n getArgValue(argv, '--format') === 'markdown' ||\n getArgValue(argv, '--format') === 'spec';\n return !jsonOutput && !markdownOutput;\n}\n\nexport async function handleWorkflowGet(\n argv: string[],\n apiUrl: string,\n token: string,\n appSubdomain?: string | null\n): Promise<void> {\n const workflowId = argv[0];\n if (!workflowId || workflowId.startsWith('--')) {\n console.error('Error: Missing workflow ID.');\n console.error('Usage: canary workflow get <workflowId>');\n process.exit(1);\n }\n\n const markdownOutput =\n hasFlag(argv, '--markdown') ||\n getArgValue(argv, '--format') === 'markdown' ||\n getArgValue(argv, '--format') === 'spec';\n const outputFile = getArgValue(argv, '--output');\n\n const apiRes = await apiFetch(`${apiUrl}/workflows/${workflowId}`, {\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n token,\n });\n if (!apiRes.ok) exitOnFailure(apiRes.failure);\n const result = (await apiRes.response.json()) as WorkflowDetailResponse;\n\n if (result.error === 'WORKFLOW_NOT_FOUND') {\n console.error('Error: Workflow not found.');\n process.exit(1);\n }\n if (result.error === 'WORKFLOW_WRONG_ORG') {\n console.error(\n `Error: Workflow belongs to another org: ${result.targetOrgName ?? result.targetOrgId}`\n );\n process.exit(1);\n }\n if (!result.workflow) {\n console.error(`Error: ${result.error ?? 'Unexpected response'}`);\n process.exit(1);\n }\n\n const workflow = result.workflow;\n let output: string;\n\n if (markdownOutput) {\n output = formatWorkflowMarkdown(workflow);\n } else {\n // Default to JSON for agent-friendly output\n output = JSON.stringify(formatWorkflowJson(workflow), null, 2);\n }\n\n if (outputFile) {\n try {\n await fs.writeFile(outputFile, output, 'utf-8');\n console.log(`Written to ${outputFile}`);\n } catch (err) {\n console.error(\n `Error writing to ${outputFile}: ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n return;\n }\n\n writeRawOutput(output);\n\n if (shouldPrintWorkflowUrlTrailer(argv)) {\n const appUrl = resolveOrgAppUrl(apiUrl, appSubdomain);\n console.log(`\\nURL: ${appUrl}/flows/${workflowId}`);\n }\n}\n","import { NODE_TYPE_LABEL } from '@chatsdet/types';\nimport { workflowToSpec, type PullWorkflow } from '@chatsdet/canary-spec';\nimport { topoOrderNodes } from '@chatsdet/workflow-diff';\n\ntype SeedOutput = {\n dataKey: string;\n name: string;\n description?: string;\n displayLabel: string;\n propertyId: string;\n attributes?: Record<string, unknown>;\n credentialOutput?: Record<string, unknown>;\n};\n\nexport type WorkflowSummary = PullWorkflow & {\n seedOutputsJson?: SeedOutput[] | null;\n};\n\nexport type WorkflowDetailResponse = {\n ok?: boolean;\n error?: string;\n workflow?: WorkflowSummary;\n targetOrgId?: string;\n targetOrgName?: string;\n};\n\n/** Environment fields the workflow-detail payload carries for `workflow get`. */\ntype WorkflowEnvFields = {\n viewportSize?: import('@chatsdet/types').BrowserViewportPreset | null;\n defaultEnvironmentId?: string | null;\n environments?: Array<{ id: string; name: string; type: string; isDefault: boolean }>;\n eligibleEnvironmentIds?: string[];\n passByEnvironment?: Array<{\n environmentId: string;\n environmentName: string;\n environmentType: string;\n everPassed: boolean;\n passed: number;\n total: number;\n health: string;\n }>;\n};\n\nexport function truncate(text: string, max: number): string {\n if (text.length <= max) return text;\n return text.slice(0, max - 1) + '…';\n}\n\nexport function getNodeTitle(node: PullWorkflow['nodes'][number]): string {\n const c = node.configJson ?? {};\n switch (node.nodeType) {\n case 'login':\n return (c.credentialName as string) || NODE_TYPE_LABEL.login;\n case 'navigate':\n return (c.pageTitle as string) || truncate((c.pageUrl as string) || 'Navigate', 40);\n case 'action':\n return (\n (c.customActionTitle as string) || truncate((c.actionDescription as string) || 'Action', 50)\n );\n case 'assertion':\n return truncate((c.condition as string) || 'Assertion', 50);\n case 'setup':\n return (c.setupFlowName as string) || 'Setup';\n case 'seed':\n return (c.seedWorkflowName as string) || 'Seed';\n case 'wait':\n return 'Wait';\n case 'condition':\n return truncate((c.conditionDescription as string) || 'Condition', 50);\n case 'visual_checkpoint':\n return truncate((c.name as string) || NODE_TYPE_LABEL.visual_checkpoint, 50);\n case 'end':\n return 'End';\n case 'api_sequence':\n return 'API Sequence';\n default:\n return node.nodeType;\n }\n}\n\nfunction getCleanConfig(node: PullWorkflow['nodes'][number]): Record<string, unknown> {\n const c = node.configJson ?? {};\n switch (node.nodeType) {\n case 'login':\n // Keep the credential wiring metadata, not secrets. Passwords/tokens live\n // on credential records, never in configJson.\n return pick(c, [\n 'credentialName',\n 'performLogin',\n 'credentialSource',\n 'credentialTemplateId',\n 'credentialTemplateName',\n 'credentialId',\n 'seedCredentialRef',\n ]);\n case 'navigate':\n return {\n ...pick(c, ['pageUrl', 'pageTitle']),\n ...(c.openInNewTab ? { openInNewTab: true } : {}),\n };\n case 'action':\n return pick(c, [\n 'actionDescription',\n 'playbookSteps',\n 'inputValues',\n 'declaredOutputs',\n 'capturedVariableKeys',\n 'dataRequirements',\n 'inlineAssertions',\n 'alwaysUseAgent',\n ]);\n case 'assertion':\n // Mirrors what the markdown spec shows. Legacy `strict: true` means\n // severity 'fail' and an unset severity reads as 'warn' (canary-spec\n // authored-fields), so JSON reports the same value markdown does.\n return {\n ...pick(c, ['condition', 'description', 'expectedOutcome', 'strict', 'alwaysUseAgent']),\n severity: c.severity ?? (c.strict === true ? 'fail' : 'warn'),\n };\n case 'setup':\n return pick(c, ['setupFlowId', 'setupFlowName']);\n case 'seed':\n return pick(c, ['seedWorkflowId', 'seedWorkflowName', 'snapshotVersion']);\n case 'end':\n return pick(c, ['outcome']);\n case 'wait':\n case 'condition':\n case 'api_sequence':\n return c;\n default:\n return c;\n }\n}\n\nfunction pick(obj: Record<string, unknown>, keys: string[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const key of keys) {\n if (obj[key] !== undefined && obj[key] !== null) {\n result[key] = obj[key];\n }\n }\n return result;\n}\n\nexport function formatWorkflowMarkdown(workflow: WorkflowSummary): string {\n const seedOutputs = workflow.seedOutputsJson ?? workflow.seedOutputs;\n return workflowToSpec({ ...workflow, seedOutputs });\n}\n\nexport function formatWorkflowJson(workflow: WorkflowSummary): object {\n const sorted = topoOrderNodes(workflow.nodes, workflow.edges ?? []);\n const seedOutputs = workflow.seedOutputsJson;\n const env = workflow as WorkflowSummary & WorkflowEnvFields;\n\n return {\n workflow: {\n id: workflow.id,\n name: workflow.name,\n description: workflow.description,\n preflight: workflow.preflight,\n cleanup: workflow.cleanup,\n status: workflow.status,\n flowType: workflow.flowType,\n ...(env.viewportSize !== undefined ? { viewportSize: env.viewportSize } : {}),\n ...(seedOutputs && seedOutputs.length > 0 ? { seedOutputs } : {}),\n ...(env.defaultEnvironmentId !== undefined\n ? { defaultEnvironmentId: env.defaultEnvironmentId }\n : {}),\n ...(env.eligibleEnvironmentIds ? { eligibleEnvironmentIds: env.eligibleEnvironmentIds } : {}),\n ...(env.passByEnvironment && env.passByEnvironment.length > 0\n ? {\n passByEnvironment: env.passByEnvironment.map((p) => ({\n environment: `${p.environmentName} (${p.environmentType})`,\n everPassed: p.everPassed,\n passed: p.passed,\n total: p.total,\n health: p.health,\n })),\n }\n : {}),\n },\n steps: sorted.map((node, i) => ({\n index: i + 1,\n nodeId: node.id,\n nodeType: node.nodeType,\n title: getNodeTitle(node),\n config: getCleanConfig(node),\n })),\n };\n}\n","import process from 'node:process';\nimport { getArgValue, hasFlag } from './auth.js';\nimport { writeRawOutput } from './brand.js';\nimport { apiRequest } from './cli-helpers.js';\nimport { truncate } from './workflow-format.js';\n\nexport type WorkflowListPagination = {\n page: number;\n pageSize: number;\n totalItems: number;\n totalPages: number;\n};\n\nexport type WorkflowListItem = {\n id: string;\n name: string;\n status: string;\n flowType: string;\n nodeCount?: number;\n};\n\nexport type WorkflowListResponse = {\n ok: boolean;\n error?: string;\n data: WorkflowListItem[];\n pagination: WorkflowListPagination;\n};\n\nexport function formatWorkflowListTable(args: {\n data: readonly WorkflowListItem[];\n pagination: WorkflowListPagination;\n}): string {\n const lines = [\n `Workflows: ${args.pagination.totalItems} total (page ${args.pagination.page}/${args.pagination.totalPages})`,\n '',\n ];\n\n if (args.data.length === 0) {\n lines.push('No workflows found.');\n return lines.join('\\n');\n }\n\n const idW = 36;\n const nameW = 30;\n const statusW = 12;\n const typeW = 10;\n\n lines.push(\n ['ID'.padEnd(idW), 'Name'.padEnd(nameW), 'Status'.padEnd(statusW), 'Type'.padEnd(typeW)].join(\n ' '\n )\n );\n\n for (const workflow of args.data) {\n lines.push(\n [\n workflow.id.padEnd(idW),\n truncate(workflow.name, nameW).padEnd(nameW),\n workflow.status.padEnd(statusW),\n workflow.flowType.padEnd(typeW),\n ].join(' ')\n );\n }\n\n return lines.join('\\n');\n}\n\nexport async function handleWorkflowList(\n argv: string[],\n apiUrl: string,\n token: string\n): Promise<void> {\n const jsonOutput = hasFlag(argv, '--json');\n\n const params = new URLSearchParams();\n const search = getArgValue(argv, '--search');\n const flowType = getArgValue(argv, '--flow-type');\n const status = getArgValue(argv, '--status');\n const page = getArgValue(argv, '--page');\n const pageSize = getArgValue(argv, '--page-size');\n\n if (search) params.set('search', search);\n if (flowType) params.set('flowType', flowType);\n if (status) params.set('status', status);\n if (page) params.set('page', page);\n if (pageSize) params.set('pageSize', pageSize);\n\n const qs = params.toString();\n const path = `/workflows${qs ? `?${qs}` : ''}`;\n\n const result = await apiRequest<WorkflowListResponse>(apiUrl, token, 'GET', path);\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify({ data: result.data, pagination: result.pagination }, null, 2));\n return;\n }\n\n writeRawOutput(formatWorkflowListTable({ data: result.data, pagination: result.pagination }));\n}\n","/**\n * `cofactor workflow cancel <runId>`: cancel a workflow run through\n * `POST /workflows/:workflowId/runs/:runId/cancel`.\n *\n * @module\n */\n\nimport process from 'node:process';\nimport { getArgValue, hasFlag } from './auth.js';\nimport { apiRequest } from './cli-helpers.js';\nimport { writeRawOutput } from './brand.js';\nimport { resolveWorkflowIdForRun } from './workflow-debug.js';\n\nconst USAGE = 'Usage: cofactor workflow cancel <runId> [--workflow <workflowId>] [--json]';\n\nexport async function handleWorkflowCancel(argv: string[], apiUrl: string, token: string): Promise<void> {\n const [runId] = argv.filter((a, i) => !a.startsWith('-') && argv[i - 1] !== '--workflow');\n if (!runId) {\n console.error('Error: Missing run ID.');\n console.error(USAGE);\n process.exit(1);\n }\n let workflowId: string;\n try {\n workflowId = await resolveWorkflowIdForRun({ runId, explicitWorkflowId: getArgValue(argv, '--workflow'), apiUrl, token });\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n console.error(' Pass --workflow <workflowId> explicitly.');\n process.exit(1);\n }\n\n const result = await apiRequest<{ ok: boolean; error?: string }>(\n apiUrl,\n token,\n 'POST',\n `/workflows/${workflowId}/runs/${runId}/cancel`,\n {}\n );\n if (hasFlag(argv, '--json')) {\n writeRawOutput(JSON.stringify(result, null, 2));\n } else if (result.ok) {\n console.log(`Cancelled run ${runId}.`);\n } else {\n console.error(`Error: ${result.error ?? 'could not cancel the run'}`);\n }\n if (!result.ok) process.exit(1);\n}\n","/**\n * CLI handler for triggering a workflow execution.\n *\n * Usage:\n * canary workflow run <workflowId> [options]\n * --cache-only waits for the run to reach a terminal status.\n *\n * @module WorkflowRunCLI\n */\n\nimport process from 'node:process';\nimport { getArgValue, hasFlag, resolveOrgAppUrl } from './auth.js';\nimport {\n apiRequest,\n fetchWorkflowEnvironments,\n renderWorkflowUserError,\n resolveEnvironmentByNameOrId,\n} from './cli-helpers.js';\nimport { statusIcon } from './cli-format.js';\nimport { formatCacheOnlyFailure, getCacheOnlyFailure } from './cache-only-failure.js';\nimport { writeRawOutput } from './brand.js';\nimport { resolveApplicationId } from './environment.js';\nimport { isBrowserViewportPreset } from '@chatsdet/types';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype ExecuteResponse = {\n ok: boolean;\n error?: string;\n runId: string;\n streamId: string;\n};\n\ntype RunStatusResponse = {\n ok: boolean;\n error?: string;\n data: {\n run: {\n id: string;\n status: string;\n startedAt: string | null;\n finishedAt: string | null;\n errorMessage: string | null;\n metadataJson: Record<string, unknown> | null;\n };\n };\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// ---------------------------------------------------------------------------\n// Handler\n// ---------------------------------------------------------------------------\n\nexport async function handleWorkflowRun(\n argv: string[],\n apiUrl: string,\n token: string,\n appSubdomain: string | null | undefined\n): Promise<void> {\n // `--environment` takes a value; exclude that token when picking the\n // positional workflow id so `run --environment staging <wf>` still works.\n const environmentArg = getArgValue(argv, '--environment');\n const viewportArg = getArgValue(argv, '--viewport');\n const claimScopeArg = getArgValue(argv, '--claim-scope');\n const browserModeArg = getArgValue(argv, '--browser-mode');\n const sandboxArg = getArgValue(argv, '--sandbox');\n const previewArg = getArgValue(argv, '--preview');\n const applicationArg = getArgValue(argv, '--application') ?? getArgValue(argv, '--property');\n const flagValues = new Set(\n [environmentArg, viewportArg, claimScopeArg, browserModeArg, sandboxArg, previewArg, applicationArg].filter((v): v is string =>\n Boolean(v)\n )\n );\n const workflowId = argv.find((a) => !a.startsWith('-') && !flagValues.has(a));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n console.error(\n 'Usage: canary workflow run <workflowId> [--environment <name|id>] [--sandbox <id> | --preview <pr> --application <name|id>] [--browser-mode <headed|headless>] [--cache-only] [--stream] [--json]'\n );\n console.error(' --cache-only Replay cached actions only and wait for completion.');\n console.error(' --sandbox Run on a sandbox you claimed (`cofactor sandbox claim`) instead of a fresh copy.');\n console.error(\" --preview Run on a private copy of a pull request's preview at its applied head (needs --application).\");\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const stream = hasFlag(argv, '--stream');\n const cacheOnly = hasFlag(argv, '--cache-only');\n const waitForTerminal = stream || cacheOnly;\n const requestBody: Record<string, unknown> = {\n triggerSource: 'cli_direct',\n };\n if (hasFlag(argv, '--viewport') && !isBrowserViewportPreset(viewportArg)) {\n console.error('Error: --viewport requires desktop, desktop_large, laptop, tablet, or mobile.');\n process.exit(1);\n }\n if (viewportArg !== undefined) requestBody.viewportSize = viewportArg;\n if (cacheOnly) {\n requestBody.cacheOnly = true;\n }\n if (claimScopeArg) {\n requestBody.claimScope = claimScopeArg;\n }\n // The run uses this claimed sandbox (and the files synced into it), and never destroys it.\n if (sandboxArg) {\n requestBody.sandboxV2SandboxId = sandboxArg;\n }\n // A private copy of the pull request's preview, so the run is true of that commit.\n if (previewArg) {\n const prNumber = Number(previewArg);\n if (!/^[1-9]\\d*$/.test(previewArg)) {\n console.error('Error: --preview takes a pull request number.');\n process.exit(1);\n }\n if (sandboxArg) {\n console.error('Error: --preview and --sandbox name different sandboxes; pass one.');\n process.exit(1);\n }\n requestBody.preview = { applicationId: await resolveApplicationId(argv, apiUrl, token), prNumber };\n }\n if (browserModeArg) {\n if (browserModeArg !== 'headed' && browserModeArg !== 'headless') {\n console.error('Error: --browser-mode must be headed or headless.');\n process.exit(1);\n }\n requestBody.browserMode = browserModeArg;\n }\n\n // Optional environment override. Resolve a name/id against the flow's\n // property and pass `environmentId` to the execute endpoint. When omitted the\n // server falls back to the workflow's configured `defaultEnvironmentId` (then\n // credential-bound / property-default env), so a plain run targets the\n // sandbox once the flow's default is set via `workflow patch`.\n let resolvedEnvironmentId: string | undefined;\n if (environmentArg) {\n const envs = await fetchWorkflowEnvironments(apiUrl, token, workflowId);\n resolvedEnvironmentId = resolveEnvironmentByNameOrId(envs, environmentArg);\n requestBody.environmentId = resolvedEnvironmentId;\n }\n\n // Trigger execution\n const result = await apiRequest<ExecuteResponse>(\n apiUrl,\n token,\n 'POST',\n `/workflows/${workflowId}/execute`,\n requestBody\n );\n\n if (!result.ok) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n } else {\n const rendered = renderWorkflowUserError(result as unknown as Record<string, unknown>);\n console.error(rendered ?? `Error: ${result.error ?? 'Unknown error'}`);\n }\n process.exit(1);\n }\n\n const { runId } = result;\n const url = `${resolveOrgAppUrl(apiUrl, appSubdomain)}/flows/${workflowId}?runId=${runId}`;\n\n if (jsonOutput && !waitForTerminal) {\n writeRawOutput(JSON.stringify({ ok: true, runId, streamId: result.streamId, url }, null, 2));\n return;\n }\n\n if (!waitForTerminal) {\n console.log(`Run triggered successfully.`);\n console.log(` Run ID: ${runId}`);\n console.log(` URL: ${url}`);\n if (environmentArg) {\n console.log(` Environment: ${environmentArg} (${resolvedEnvironmentId})`);\n }\n console.log(`\\nCheck status: canary workflow runs get ${workflowId} ${runId}`);\n return;\n }\n\n // Stream and cache-only modes poll run status until completion.\n if (!jsonOutput) {\n console.log(`Run triggered (${runId}). Waiting for completion...\\n`);\n }\n\n const terminalStatuses = new Set([\n 'completed',\n 'success',\n 'passed',\n 'failed',\n 'inconclusive',\n 'canceled',\n 'timeout',\n ]);\n let lastStatus = '';\n let firstPoll = true;\n\n for (;;) {\n if (!firstPoll) await sleep(3000);\n firstPoll = false;\n\n const status = await apiRequest<RunStatusResponse>(\n apiUrl,\n token,\n 'GET',\n `/workflows/${workflowId}/runs/${runId}`\n );\n\n if (!status.ok) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(status, null, 2));\n } else {\n console.error(`Error polling status: ${status.error ?? 'Unknown error'}`);\n }\n process.exit(1);\n }\n\n const run = status.data.run;\n\n if (cacheOnly && run.metadataJson?.cacheOnly !== true) {\n const isTerminal = terminalStatuses.has(run.status);\n const cancellation = isTerminal\n ? null\n : await apiRequest<{ ok: boolean; error?: string }>(\n apiUrl,\n token,\n 'POST',\n `/workflows/${workflowId}/runs/${runId}/cancel`,\n {}\n );\n const cancellationMessage = isTerminal\n ? 'The run was already terminal before it could be canceled.'\n : cancellation?.ok\n ? 'The run was canceled before polling continued.'\n : `Automatic cancellation failed: ${cancellation?.error ?? 'unknown error'}`;\n const error =\n 'Cache-only safety check failed: the created run did not persist cacheOnly=true. ' +\n cancellationMessage +\n ' Cancellation acknowledgment does not prove the run is quiescent; wait for its full job and agent tree to stop before retrying or restoring cache rows.';\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(\n { ok: false, runId, streamId: result.streamId, url, status: run.status, error },\n null,\n 2\n )\n );\n } else {\n console.error(`Error: ${error}`);\n console.error(`Run ID: ${runId}`);\n }\n process.exit(1);\n }\n\n if (!jsonOutput && run.status !== lastStatus) {\n console.log(` ${statusIcon(run.status)} ${run.status}`);\n lastStatus = run.status;\n }\n\n if (terminalStatuses.has(run.status)) {\n const cacheOnlyFailure = getCacheOnlyFailure(run.metadataJson);\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(\n {\n ok: !['failed', 'timeout', 'canceled'].includes(run.status),\n runId,\n streamId: result.streamId,\n url,\n status: run.status,\n error: run.errorMessage,\n ...(cacheOnlyFailure ? { cacheOnlyFailure } : {}),\n },\n null,\n 2\n )\n );\n } else {\n if (run.errorMessage) {\n writeRawOutput(`\\nError: ${run.errorMessage}`);\n }\n if (run.status === 'failed' && cacheOnlyFailure) {\n console.log('');\n for (const line of formatCacheOnlyFailure(cacheOnlyFailure)) {\n writeRawOutput(line);\n }\n }\n console.log(`\\nRun finished: ${run.status}`);\n console.log(`URL: ${url}`);\n console.log(`Details: canary workflow runs get ${workflowId} ${runId}`);\n }\n\n if (run.status === 'inconclusive') {\n process.exit(2);\n }\n if (run.status === 'failed' || run.status === 'timeout' || run.status === 'canceled') {\n process.exit(1);\n }\n return;\n }\n }\n}\n","export type CacheOnlyFailureReport = {\n nodeId: string;\n nodeName: string;\n stepIndex: number;\n nodeHash?: string;\n cacheId?: string;\n failureClass: string;\n cacheOutcome: string;\n cacheOutcomeReason?: string;\n failureCategory?: string;\n failedStepOrder?: number;\n error?: string;\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction hasOptionalString(record: Record<string, unknown>, key: string): boolean {\n return record[key] === undefined || typeof record[key] === 'string';\n}\n\nexport function isCacheOnlyFailureReport(value: unknown): value is CacheOnlyFailureReport {\n if (!isRecord(value)) return false;\n\n return (\n typeof value.nodeId === 'string' &&\n typeof value.nodeName === 'string' &&\n typeof value.stepIndex === 'number' &&\n typeof value.failureClass === 'string' &&\n typeof value.cacheOutcome === 'string' &&\n hasOptionalString(value, 'nodeHash') &&\n hasOptionalString(value, 'cacheId') &&\n hasOptionalString(value, 'cacheOutcomeReason') &&\n hasOptionalString(value, 'failureCategory') &&\n (value.failedStepOrder === undefined || typeof value.failedStepOrder === 'number') &&\n hasOptionalString(value, 'error')\n );\n}\n\nexport function getCacheOnlyFailure(\n metadataJson: Record<string, unknown> | null | undefined\n): CacheOnlyFailureReport | null {\n const report = metadataJson?.cacheOnlyFailure;\n return isCacheOnlyFailureReport(report) ? report : null;\n}\n\nexport function formatCacheOnlyFailure(report: CacheOnlyFailureReport): string[] {\n const lines = [\n 'Cache-only failure:',\n ` Node: ${report.nodeName}`,\n ` Failure class: ${report.failureClass}`,\n ` Cache outcome: ${report.cacheOutcome}`,\n ];\n\n if (report.cacheOutcomeReason) {\n lines.push(` Reason: ${report.cacheOutcomeReason}`);\n }\n if (report.failedStepOrder !== undefined) {\n lines.push(` Failed step order: ${report.failedStepOrder}`);\n }\n if (report.error) {\n lines.push(` Error: ${report.error}`);\n }\n\n return lines;\n}\n","/**\n * CLI subcommand for querying workflow run results.\n *\n * Usage:\n * canary workflow runs list <workflowId> [options]\n * canary workflow runs get <workflowId> <runId> [options]\n * canary workflow runs diagnostics <workflowId> <runId> [options]\n *\n * @module WorkflowRunsCLI\n */\n\nimport process from 'node:process';\nimport { elapsedTestAttemptMs } from '@chatsdet/types';\nimport { getArgValue, hasFlag } from './auth.js';\nimport { apiRequest } from './cli-helpers.js';\nimport {\n statusIcon,\n formatRelative,\n computeDuration,\n formatElapsedDurationMs,\n formatRecordedUtcTimestamp,\n pad,\n} from './cli-format.js';\nimport { writeRawOutput } from './brand.js';\nimport { formatCacheOnlyFailure, getCacheOnlyFailure } from './cache-only-failure.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype Pagination = {\n page: number;\n pageSize: number;\n totalItems: number;\n totalPages: number;\n};\n\ntype RunSummary = {\n id: string;\n status: string;\n createdAt: string;\n startedAt: string | null;\n finishedAt: string | null;\n errorMessage: string | null;\n browserMode: string | null;\n stepTotals: { total: number; passed: number; failed: number } | null;\n snapshotVersion: number | null;\n};\n\ntype RunListResponse = {\n ok: boolean;\n error?: string;\n data: { runs: RunSummary[] };\n pagination: Pagination;\n};\n\ntype RunStep = {\n id: string;\n runId: string;\n nodeId: string;\n status: string;\n startedAt: string | null;\n finishedAt: string | null;\n errorMessage: string | null;\n orderIndex: number;\n metadataJson: Record<string, unknown> | null;\n createdAt: string;\n};\n\ntype RunDetail = {\n id: string;\n workflowId: string;\n status: string;\n startedAt: string | null;\n finishedAt: string | null;\n errorMessage: string | null;\n metadataJson: Record<string, unknown> | null;\n steps: RunStep[];\n draftSnapshot: { id: string; version: string; basePublishedVersion: number } | null;\n};\n\ntype RunDetailResponse = {\n ok: boolean;\n error?: string;\n data: { run: RunDetail };\n};\n\ntype DiagnosticJson = {\n category?: string;\n title?: string;\n analysis?: string;\n recommendation?: string;\n smokingGun?: { type: string; description: string; detail?: string } | null;\n};\n\ntype FailureDiagnosticResponse = {\n ok: boolean;\n error?: string;\n data: {\n id: string;\n status: string;\n diagnostic: DiagnosticJson | null;\n createdAt: string;\n updatedAt: string;\n } | null;\n};\n\ntype RawDiagnosticsResponse = {\n ok: boolean;\n error?: string;\n consoleLogs: Array<{ level: string; text: string; timestamp?: string }>;\n networkRequests: Array<{ method: string; url: string; status: number }>;\n};\n\nfunction nativeRunElapsedMs(\n run: Pick<RunDetail, 'status' | 'startedAt' | 'finishedAt'>\n): number | null {\n if (run.finishedAt) return elapsedTestAttemptMs(run.startedAt, run.finishedAt);\n if (run.status.toLowerCase() === 'running' && run.startedAt) {\n return elapsedTestAttemptMs(run.startedAt, new Date().toISOString());\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Handlers\n// ---------------------------------------------------------------------------\n\ntype AnnotatedRun = RunSummary & { side: 'browser' | 'api' };\n\ntype ApiSequenceRunRow = {\n id: string;\n status: string;\n startedAt: string | null;\n finishedAt: string | null;\n errorMessage: string | null;\n createdAt?: string;\n};\n\ntype ApiSequenceByWorkflow = {\n ok: boolean;\n error?: string;\n data?: { id: string } | null;\n};\n\ntype ApiSequenceRunsResponse = {\n ok: boolean;\n error?: string;\n data: ApiSequenceRunRow[];\n pagination?: Pagination;\n};\n\nasync function fetchBrowserRuns(\n apiUrl: string,\n token: string,\n workflowId: string,\n page: string,\n pageSize: string\n): Promise<{ runs: RunSummary[]; pagination: Pagination } | { error: string }> {\n const params = new URLSearchParams({ page, pageSize });\n const result = await apiRequest<RunListResponse>(\n apiUrl,\n token,\n 'GET',\n `/workflows/${workflowId}/runs?${params}`\n );\n if (!result.ok) return { error: result.error ?? 'Unknown error' };\n return { runs: result.data.runs, pagination: result.pagination };\n}\n\nasync function fetchApiRuns(\n apiUrl: string,\n token: string,\n workflowId: string,\n page: string,\n pageSize: string\n): Promise<\n { runs: RunSummary[]; pagination: Pagination | null } | { error: string; code?: string }\n> {\n const seqRes = await apiRequest<ApiSequenceByWorkflow & { code?: string }>(\n apiUrl,\n token,\n 'GET',\n `/api-sequences/by-workflow/${workflowId}`\n );\n if (!seqRes.ok) {\n return {\n error: seqRes.error ?? 'Unknown error',\n ...(seqRes.code ? { code: seqRes.code } : {}),\n };\n }\n if (!seqRes.data) return { runs: [], pagination: null };\n const params = new URLSearchParams({ page, pageSize });\n const runsRes = await apiRequest<ApiSequenceRunsResponse>(\n apiUrl,\n token,\n 'GET',\n `/api-sequences/${seqRes.data.id}/runs?${params}`\n );\n if (!runsRes.ok) return { error: runsRes.error ?? 'Unknown error' };\n const runs: RunSummary[] = (runsRes.data ?? []).map((r) => ({\n id: r.id,\n status: r.status,\n createdAt: r.createdAt ?? r.startedAt ?? new Date(0).toISOString(),\n startedAt: r.startedAt,\n finishedAt: r.finishedAt,\n errorMessage: r.errorMessage,\n browserMode: null,\n stepTotals: null,\n snapshotVersion: null,\n }));\n return { runs, pagination: runsRes.pagination ?? null };\n}\n\nasync function handleRunsList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID. Usage: canary workflow runs list <workflowId>');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const page = getArgValue(argv, '--page') ?? '1';\n const pageSize = getArgValue(argv, '--page-size') ?? '10';\n const explicitSide = getArgValue(argv, '--side') ?? getArgValue(argv, '--mode');\n const sideArg = (explicitSide ?? 'all').toLowerCase();\n\n if (!['all', 'api', 'browser'].includes(sideArg)) {\n console.error(`Error: --side must be one of: all, api, browser (got \"${sideArg}\")`);\n process.exit(1);\n }\n\n const annotated: AnnotatedRun[] = [];\n let browserPagination: Pagination | null = null;\n let apiPagination: Pagination | null = null;\n\n if (sideArg === 'browser' || sideArg === 'all') {\n const browser = await fetchBrowserRuns(apiUrl, token, workflowId, page, pageSize);\n if ('error' in browser) {\n console.error(`Error: ${browser.error}`);\n process.exit(1);\n }\n browserPagination = browser.pagination;\n for (const r of browser.runs) annotated.push({ ...r, side: 'browser' });\n }\n\n if (sideArg === 'api' || sideArg === 'all') {\n const api = await fetchApiRuns(apiUrl, token, workflowId, page, pageSize);\n if ('error' in api) {\n // When --side wasn't explicit and the workflow simply has no api-sequence,\n // don't hard-fail the whole listing — just skip the api leg.\n const isMissingSequence = api.code === 'API_SEQUENCE_NOT_FOUND';\n if (!explicitSide && isMissingSequence) {\n if (!jsonOutput) {\n console.error('Note: workflow has no api-sequence — showing browser runs only.');\n }\n } else {\n console.error(`Error: ${api.error}`);\n process.exit(1);\n }\n } else {\n apiPagination = api.pagination;\n for (const r of api.runs) annotated.push({ ...r, side: 'api' });\n }\n }\n\n annotated.sort((a, b) => {\n const ta = new Date(a.startedAt ?? a.createdAt).getTime();\n const tb = new Date(b.startedAt ?? b.createdAt).getTime();\n return tb - ta;\n });\n\n if (jsonOutput) {\n writeRawOutput(\n JSON.stringify(\n {\n ok: true,\n data: { runs: annotated },\n pagination: { browser: browserPagination, api: apiPagination },\n },\n null,\n 2\n )\n );\n return;\n }\n\n if (annotated.length === 0) {\n console.log('No runs found.');\n return;\n }\n\n console.log(`Runs (${annotated.length} shown, side=${sideArg})\\n`);\n const idW = 36;\n const sideW = 8;\n const statusW = 12;\n const durationW = 10;\n console.log(\n [\n 'ID'.padEnd(idW),\n 'Side'.padEnd(sideW),\n 'Status'.padEnd(statusW),\n 'Duration'.padEnd(durationW),\n 'Started',\n ].join(' ')\n );\n\n for (const run of annotated) {\n const icon = statusIcon(run.status);\n const dur = computeDuration(run.startedAt, run.finishedAt);\n const time = formatRelative(run.startedAt ?? run.createdAt);\n console.log(\n [\n run.id.padEnd(idW),\n pad(run.side, sideW),\n `${icon} ${pad(run.status, statusW - 3)}`,\n pad(dur, durationW),\n time,\n ].join(' ')\n );\n }\n console.log('');\n}\n\nasync function handleRunsGet(argv: string[], apiUrl: string, token: string): Promise<void> {\n const positional = argv.filter((a, index) =>\n !a.startsWith('-') && !['--step', '--api-call'].includes(argv[index - 1] ?? '')\n );\n const [workflowId, runId] = positional;\n if (!workflowId || !runId) {\n console.error('Error: Missing arguments. Usage: cofactor workflow runs get <workflowId> <runId>');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const runStepId = getArgValue(argv, '--step');\n const apiStepId = getArgValue(argv, '--api-call');\n if (argv.some((arg) => ['--step', '--api-call'].some(\n (flag) => arg === flag || arg.startsWith(`${flag}=`)\n ))) {\n if (!runStepId || runStepId.startsWith('-') || !apiStepId || apiStepId.startsWith('-')) {\n console.error('Error: --step <runStepId> and --api-call <apiStepId> must be used together.');\n process.exit(1);\n }\n const result = await apiRequest<{\n ok: boolean;\n error?: string;\n data: { stepId: string; body: string | null; requestBody: string | null };\n }>(apiUrl, token, 'GET',\n `/workflows/${encodeURIComponent(workflowId)}/runs/${encodeURIComponent(runId)}` +\n `/steps/${encodeURIComponent(runStepId)}/api-calls/${encodeURIComponent(apiStepId)}`\n );\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n } else {\n writeRawOutput(`Request body:\\n${result.data.requestBody ?? ''}`);\n writeRawOutput(`Response body:\\n${result.data.body ?? ''}`);\n }\n return;\n }\n\n const result = await apiRequest<RunDetailResponse>(\n apiUrl,\n token,\n 'GET',\n `/workflows/${workflowId}/runs/${runId}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n return;\n }\n\n const { run } = result.data;\n const elapsed = nativeRunElapsedMs(run);\n const ended =\n !run.finishedAt && run.status.toLowerCase() === 'running'\n ? 'Running'\n : formatRecordedUtcTimestamp(run.finishedAt);\n const cacheOnly = run.metadataJson?.cacheOnly === true;\n const cacheOnlyFailure = getCacheOnlyFailure(run.metadataJson);\n\n console.log(`Run: ${run.id}`);\n console.log(`Status: ${statusIcon(run.status)} ${run.status}`);\n if (cacheOnly) {\n console.log('Mode: cache-only');\n }\n console.log(`Started: ${formatRecordedUtcTimestamp(run.startedAt)}`);\n console.log(`Ended: ${ended}`);\n console.log(`Total Time: ${formatElapsedDurationMs(elapsed)}`);\n\n if (run.errorMessage) {\n writeRawOutput(`Error: ${run.errorMessage}`);\n }\n\n if (run.draftSnapshot) {\n console.log(\n `Snapshot: v${run.draftSnapshot.version} (base: v${run.draftSnapshot.basePublishedVersion})`\n );\n }\n\n if (cacheOnlyFailure) {\n console.log('');\n for (const line of formatCacheOnlyFailure(cacheOnlyFailure)) {\n console.log(line);\n }\n }\n\n const steps = (run.steps ?? []).sort((a, b) => a.orderIndex - b.orderIndex);\n\n if (steps.length === 0) {\n console.log('\\nNo steps recorded.');\n return;\n }\n\n console.log(`\\nSteps (${steps.length}):`);\n for (const step of steps) {\n const idx = String(step.orderIndex + 1).padStart(2);\n const icon = statusIcon(step.status);\n const nodeId = step.nodeId.slice(0, 8);\n const dur = computeDuration(step.startedAt, step.finishedAt);\n\n console.log(` ${idx}. ${icon} ${pad(nodeId, 10)} ${dur}`);\n\n if (step.errorMessage) {\n writeRawOutput(` Error: ${step.errorMessage}`);\n }\n }\n\n console.log('');\n}\n\nasync function handleRunsDiagnostics(argv: string[], apiUrl: string, token: string): Promise<void> {\n const positional = argv.filter((a) => !a.startsWith('-'));\n if (positional.length < 2) {\n console.error(\n 'Error: Missing arguments. Usage: canary workflow runs diagnostics <workflowId> <runId>'\n );\n process.exit(1);\n }\n\n const [workflowId, runId] = positional;\n const jsonOutput = hasFlag(argv, '--json');\n\n // Try AI failure diagnostic first\n const result = await apiRequest<FailureDiagnosticResponse>(\n apiUrl,\n token,\n 'GET',\n `/workflows/${workflowId}/runs/${runId}/failure-diagnostic`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n\n if (jsonOutput && result.data) {\n writeRawOutput(JSON.stringify(result, null, 2));\n return;\n }\n\n if (result.data) {\n const { status, diagnostic } = result.data;\n\n if (status === 'pending' || status === 'running') {\n console.log(`Diagnostic is still in progress (status: ${status}).`);\n return;\n }\n\n if (status === 'failed') {\n console.log('Diagnostic analysis failed.');\n return;\n }\n\n if (diagnostic) {\n console.log('Failure Diagnostic');\n console.log(`Status: ${status}`);\n if (diagnostic.category) {\n console.log(`Category: ${diagnostic.category}`);\n }\n if (diagnostic.title) {\n writeRawOutput(`Title: ${diagnostic.title}`);\n }\n\n if (diagnostic.analysis) {\n console.log('');\n console.log('Analysis:');\n writeRawOutput(` ${diagnostic.analysis}`);\n }\n\n if (diagnostic.recommendation) {\n console.log('');\n console.log('Recommendation:');\n writeRawOutput(` ${diagnostic.recommendation}`);\n }\n\n if (diagnostic.smokingGun) {\n console.log('');\n console.log('Smoking Gun:');\n writeRawOutput(` > ${diagnostic.smokingGun.description}`);\n if (diagnostic.smokingGun.detail) {\n writeRawOutput(` ${diagnostic.smokingGun.detail}`);\n }\n }\n\n console.log('');\n return;\n }\n }\n\n // Fall back to raw console/network diagnostics\n const rawResult = await apiRequest<RawDiagnosticsResponse>(\n apiUrl,\n token,\n 'GET',\n `/workflows/${workflowId}/runs/${runId}/diagnostics`\n );\n\n if (!rawResult.ok) {\n console.log('No diagnostic available for this run.');\n return;\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(rawResult, null, 2));\n return;\n }\n\n const hasConsole = rawResult.consoleLogs && rawResult.consoleLogs.length > 0;\n const hasNetwork = rawResult.networkRequests && rawResult.networkRequests.length > 0;\n\n if (!hasConsole && !hasNetwork) {\n console.log('No diagnostic data available for this run.');\n return;\n }\n\n if (hasConsole) {\n console.log(`Console Logs (${rawResult.consoleLogs.length}):`);\n for (const log of rawResult.consoleLogs.slice(0, 50)) {\n const level = log.level.toUpperCase().padEnd(7);\n writeRawOutput(` [${level}] ${log.text}`);\n }\n if (rawResult.consoleLogs.length > 50) {\n console.log(` ... and ${rawResult.consoleLogs.length - 50} more`);\n }\n console.log('');\n }\n\n if (hasNetwork) {\n console.log(`Network Requests (${rawResult.networkRequests.length}):`);\n for (const req of rawResult.networkRequests.slice(0, 30)) {\n const statusStr = req.status >= 400 ? `${req.status} !!!` : String(req.status);\n writeRawOutput(` ${req.method.padEnd(6)} ${statusStr.padEnd(8)} ${req.url}`);\n }\n if (rawResult.networkRequests.length > 30) {\n console.log(` ... and ${rawResult.networkRequests.length - 30} more`);\n }\n console.log('');\n }\n}\n\n// ---------------------------------------------------------------------------\n// Help\n// ---------------------------------------------------------------------------\n\nfunction printRunsHelp(): void {\n console.log(\n [\n 'Usage: canary workflow runs <sub-command> [options]',\n '',\n 'Sub-commands:',\n ' list <workflowId> [options] List runs for a workflow',\n ' get <workflowId> <runId> [options] Get run timing, detail, and steps',\n ' diagnostics <workflowId> <runId> [options] Get failure diagnostic',\n '',\n 'List options:',\n ' --page <n> Page number (default: 1)',\n ' --page-size <n> Page size (default: 10)',\n ' --side <side> Filter: browser, api, all (default: all). Alias: --mode',\n '',\n 'Get options:',\n ' --step <runStepId> --api-call <apiStepId> Print stored (capped) request/response bodies',\n '',\n 'Output options:',\n ' --json Output raw JSON',\n '',\n 'Common options:',\n ' --env <env> Target environment (prod, dev, local)',\n ' --api-url <url> API URL override',\n ' --token <key> API token override',\n ].join('\\n')\n );\n}\n\n// ---------------------------------------------------------------------------\n// Entry point\n// ---------------------------------------------------------------------------\n\nexport async function runWorkflowRuns(\n argv: string[],\n apiUrl: string,\n token: string\n): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === 'help' || hasFlag(argv, '--help', '-h')) {\n printRunsHelp();\n return;\n }\n\n switch (subCommand) {\n case 'list':\n await handleRunsList(rest, apiUrl, token);\n break;\n case 'get':\n await handleRunsGet(rest, apiUrl, token);\n break;\n case 'diagnostics':\n await handleRunsDiagnostics(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printRunsHelp();\n process.exit(1);\n }\n}\n","/**\n * CLI handler for syncing a workflow's DAG (nodes + edges) atomically.\n *\n * Reads the new state from a JSON file or stdin, creates a draft snapshot\n * of the current state for safety, then replaces all nodes and edges.\n *\n * Input is flexible — the CLI auto-fills missing fields:\n * - Node `id` and `orderIndex` are auto-generated\n * - `edges` array is optional — linear sequential edges are created\n * - Accepts the same minimal format as `canary workflow create`\n *\n * Usage:\n * canary workflow sync <workflowId> --from-file <path>\n * cat state.json | canary workflow sync <workflowId> --from-stdin\n *\n * Minimal input: { \"nodes\": [{ \"nodeType\": \"login\", \"configJson\": {} }, ...] }\n *\n * @module WorkflowSyncCLI\n */\n\nimport crypto from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport process from 'node:process';\nimport { alignSnapshotNodeIds, type AlignNode } from '@chatsdet/workflow-diff';\nimport { normalizeNodeType } from '@chatsdet/types';\nimport { getArgValue, hasFlag } from './auth.js';\nimport { apiRequest } from './cli-helpers.js';\nimport { readFromStdin } from './cli-format.js';\nimport { writeRawOutput } from './brand.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype SyncResponse = {\n ok: boolean;\n error?: string;\n snapshotVersion?: string;\n};\n\ntype ProposalResponse = {\n ok: boolean;\n error?: string;\n data?: {\n id: string;\n title: string;\n status: string;\n };\n};\n\n// ---------------------------------------------------------------------------\n// Auto-fill helpers\n// ---------------------------------------------------------------------------\n\ntype RawNode = Record<string, unknown>;\ntype RawEdge = Record<string, unknown>;\n\nfunction normalizeNodesAndEdges(\n rawNodes: RawNode[],\n rawEdges?: RawEdge[]\n): { nodes: RawNode[]; edges: RawEdge[] } {\n // Fill missing node fields with defaults\n const nodes = rawNodes.map((node, i) => ({\n ...node,\n id: (node.id as string) ?? crypto.randomUUID(),\n orderIndex: (node.orderIndex as number) ?? i,\n configJson: (node.configJson as Record<string, unknown>) ?? {},\n }));\n\n // If edges provided, just fill missing IDs\n if (rawEdges && rawEdges.length > 0) {\n const edges = rawEdges.map((edge) => ({\n ...edge,\n id: (edge.id as string) ?? crypto.randomUUID(),\n }));\n return { nodes, edges };\n }\n\n // Auto-generate linear sequential edges\n const edges: RawEdge[] = [];\n for (let i = 0; i < nodes.length - 1; i++) {\n edges.push({\n id: crypto.randomUUID(),\n sourceNodeId: nodes[i].id,\n targetNodeId: nodes[i + 1].id,\n edgeType: 'default',\n });\n }\n\n return { nodes, edges };\n}\n\n// ---------------------------------------------------------------------------\n// Input reading\n// ---------------------------------------------------------------------------\n\nasync function readSyncInput(argv: string[]): Promise<{ nodes: RawNode[]; edges?: RawEdge[] }> {\n const filePath = getArgValue(argv, '--from-file');\n const fromStdin = hasFlag(argv, '--from-stdin');\n\n let raw: string;\n if (filePath) {\n try {\n raw = await fs.readFile(filePath, 'utf-8');\n } catch (err) {\n console.error(`Error reading file: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n } else if (fromStdin) {\n try {\n raw = await readFromStdin();\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n } else {\n console.error('Error: Must provide --from-file <path> or --from-stdin');\n process.exit(1);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n console.error('Error: Invalid JSON input');\n process.exit(1);\n }\n\n const obj = parsed as Record<string, unknown>;\n\n // Normalize \"acting-as\" → \"login\" on user-supplied node entries so callers\n // can use the new spelling without breaking the canonical persisted type.\n const normalizeNodes = (raw: unknown[]): RawNode[] => {\n return raw.map((entry) => {\n if (entry && typeof entry === 'object' && 'nodeType' in entry) {\n const node = entry as RawNode;\n if (typeof node.nodeType === 'string') {\n node.nodeType = normalizeNodeType(node.nodeType);\n }\n }\n return entry as RawNode;\n });\n };\n\n // Direct format: { nodes: [...], edges?: [...] }\n if (Array.isArray(obj.nodes)) {\n return {\n nodes: normalizeNodes(obj.nodes),\n edges: Array.isArray(obj.edges) ? obj.edges : undefined,\n };\n }\n\n // Wrapped format from `canary workflow get`: { workflow: { nodes: [...], edges: [...] } }\n const workflow = obj.workflow as Record<string, unknown> | undefined;\n if (workflow && Array.isArray(workflow.nodes)) {\n return {\n nodes: normalizeNodes(workflow.nodes),\n edges: Array.isArray(workflow.edges) ? workflow.edges : undefined,\n };\n }\n\n console.error('Error: JSON must contain a \"nodes\" array.');\n console.error('Accepted formats:');\n console.error(' { \"nodes\": [{ \"nodeType\": \"login\", \"configJson\": {} }, ...] }');\n console.error(' { \"nodes\": [...], \"edges\": [...] }');\n console.error(' { \"workflow\": { \"nodes\": [...], \"edges\": [...] } }');\n console.error('');\n console.error('Edges, IDs, positions, and ordering are auto-generated when omitted.');\n process.exit(1);\n}\n\n// ---------------------------------------------------------------------------\n// Current-workflow ID alignment (for --propose)\n// ---------------------------------------------------------------------------\n\ntype WorkflowGetResponse = {\n ok: boolean;\n error?: string;\n workflow?: {\n id: string;\n nodes?: Array<{\n id: string;\n nodeType: string;\n orderIndex?: number;\n configJson?: Record<string, unknown> | null;\n }>;\n };\n};\n\nasync function alignWithCurrentWorkflow(\n apiUrl: string,\n token: string,\n workflowId: string,\n nodes: RawNode[],\n edges: RawEdge[],\n): Promise<{ nodes: RawNode[]; edges: RawEdge[] }> {\n // Best-effort: a failed fetch (network blip, 404, permissions) shouldn't\n // block the proposal — the server-side aligner will still run.\n let currentNodes: AlignNode[] = [];\n try {\n const current = await apiRequest<WorkflowGetResponse>(\n apiUrl,\n token,\n 'GET',\n `/workflows/${workflowId}`,\n );\n if (current.ok && current.workflow?.nodes) {\n currentNodes = current.workflow.nodes.map((n) => ({\n id: n.id,\n nodeType: n.nodeType,\n orderIndex: n.orderIndex,\n configJson: n.configJson ?? {},\n }));\n }\n } catch {\n // Swallow — alignment is a best-effort optimization on the client.\n }\n\n if (currentNodes.length === 0) {\n return { nodes, edges };\n }\n\n const proposedSnapshot = {\n nodes: nodes.map((n) => ({\n id: String(n.id),\n nodeType: String(n.nodeType ?? ''),\n orderIndex: typeof n.orderIndex === 'number' ? n.orderIndex : undefined,\n configJson: (n.configJson as Record<string, unknown> | null | undefined) ?? {},\n })),\n edges: edges.map((e) => ({\n id: String(e.id),\n sourceNodeId: String(e.sourceNodeId),\n targetNodeId: String(e.targetNodeId),\n edgeType: (e.edgeType as string | null | undefined) ?? null,\n })),\n };\n\n const { snapshot } = alignSnapshotNodeIds(proposedSnapshot, currentNodes);\n\n // Splice aligned IDs back onto the original raw nodes/edges so any extra\n // fields callers passed through (canonicalPageId, etc.) are preserved.\n const alignedNodes: RawNode[] = nodes.map((n, i) => ({\n ...n,\n id: snapshot.nodes[i]!.id,\n }));\n const alignedEdges: RawEdge[] = edges.map((e, i) => ({\n ...e,\n sourceNodeId: snapshot.edges[i]!.sourceNodeId,\n targetNodeId: snapshot.edges[i]!.targetNodeId,\n }));\n\n return { nodes: alignedNodes, edges: alignedEdges };\n}\n\n// ---------------------------------------------------------------------------\n// Handler\n// ---------------------------------------------------------------------------\n\nexport async function handleWorkflowSync(\n argv: string[],\n apiUrl: string,\n token: string\n): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n console.error('Usage: canary workflow sync <workflowId> --from-file <path>');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const noSnapshot = hasFlag(argv, '--no-snapshot');\n const propose = hasFlag(argv, '--propose');\n const proposalTitle = getArgValue(argv, '--title');\n const proposalDescription = getArgValue(argv, '--description');\n\n const raw = await readSyncInput(argv);\n const { nodes, edges } = normalizeNodesAndEdges(raw.nodes, raw.edges);\n\n // --propose: create a proposal instead of applying directly\n if (propose) {\n const title = proposalTitle ?? `CLI sync proposal (${nodes.length} nodes)`;\n\n // Reuse existing workflow node IDs whenever a proposed step lines up with\n // a current step (same nodeType + orderIndex). Without this the diff\n // engine — which matches by node.id — sees the proposal as a wholesale\n // rewrite even when only a few configs changed. The server-side aligner\n // is the authoritative pass; doing it here too keeps CLI output sensible\n // and gives agents a clean diff even before they round-trip through the\n // API.\n const aligned = await alignWithCurrentWorkflow(apiUrl, token, workflowId, nodes, edges);\n\n const result = await apiRequest<ProposalResponse>(\n apiUrl,\n token,\n 'POST',\n `/workflows/${workflowId}/proposals`,\n {\n title,\n description: proposalDescription ?? null,\n snapshotJson: { nodes: aligned.nodes, edges: aligned.edges },\n source: 'api',\n }\n );\n\n if (!result.ok) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify({ ok: false, error: result.error ?? 'Unknown error' }, null, 2));\n } else {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n }\n process.exit(1);\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(`Proposal created for workflow ${workflowId} (${nodes.length} nodes, ${edges.length} edges).`);\n if (result.data?.id) {\n console.log(`Proposal ID: ${result.data.id}`);\n }\n return;\n }\n\n const result = await apiRequest<SyncResponse>(\n apiUrl,\n token,\n 'PUT',\n `/workflows/${workflowId}/draft-state`,\n { nodes, edges, createSnapshot: !noSnapshot }\n );\n\n if (!result.ok) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify({ ok: false, error: result.error ?? 'Unknown error' }, null, 2));\n } else {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n }\n process.exit(1);\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(`Workflow ${workflowId} synced (${nodes.length} nodes, ${edges.length} edges).`);\n if (result.snapshotVersion) {\n console.log(`Draft snapshot created: ${result.snapshotVersion}`);\n }\n}\n","/**\n * CLI handler for generating an API sequence from a workflow.\n *\n * Generates from the latest successful run (default) or from a text prompt.\n * Streams progress events via SSE and outputs the resulting ApiSequenceConfig.\n *\n * Usage:\n * canary workflow generate-api-sequence <workflowId> [--guidance \"text\"] [--json]\n * canary workflow generate-api-sequence --prompt \"Create user\" [--property <id>] [--json]\n *\n * @module WorkflowApiSequenceCLI\n */\n\nimport process from 'node:process';\nimport { createParser, type EventSourceMessage } from 'eventsource-parser';\nimport { getArgValue, hasFlag } from './auth.js';\nimport { writeRawOutput } from './brand.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype GenerateResponse = {\n ok: boolean;\n error?: string;\n generationId?: string;\n};\n\ntype ApiSequenceEvent = {\n emittedAt: string;\n workflowId: string;\n} & (\n | { eventType: 'progress'; message: string }\n | { eventType: 'tool-call'; toolName: string; args: unknown }\n | { eventType: 'tool-result'; toolName: string; result: unknown; success: boolean }\n | { eventType: 'text'; delta: string }\n | {\n eventType: 'complete';\n config: unknown;\n summary: string;\n propertyId: string | null;\n credentialId: string | null;\n }\n | { eventType: 'error'; message: string }\n);\n\n// ---------------------------------------------------------------------------\n// Handler\n// ---------------------------------------------------------------------------\n\nexport async function handleWorkflowGenerateApiSequence(\n argv: string[],\n apiUrl: string,\n token: string\n): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n const prompt = getArgValue(argv, '--prompt');\n const guidance = getArgValue(argv, '--guidance');\n const propertyId = getArgValue(argv, '--property');\n const jsonOutput = hasFlag(argv, '--json');\n const verbose = hasFlag(argv, '--verbose', '-v');\n\n if (!workflowId && !prompt) {\n console.error('Error: Provide a workflow ID or --prompt.');\n console.error('');\n console.error('Usage:');\n console.error(' canary workflow generate-api-sequence <workflowId> [--guidance \"text\"]');\n console.error(' canary workflow generate-api-sequence --prompt \"Create user\" [--property <id>]');\n process.exit(1);\n }\n\n // 1. Trigger generation\n let endpoint: string;\n let body: Record<string, unknown>;\n\n if (workflowId && !prompt) {\n // Generate from latest successful run\n endpoint = '/api-sequence-agent/generate-from-run';\n body = { workflowId };\n if (guidance) body.guidancePrompt = guidance;\n if (!jsonOutput) {\n console.error(`Generating API sequence from latest run of workflow ${workflowId}...`);\n }\n } else {\n // Generate from prompt\n endpoint = '/api-sequence-agent/generate';\n body = { prompt: prompt! };\n if (propertyId) body.propertyId = propertyId;\n if (workflowId) body.workflowId = workflowId;\n if (!jsonOutput) {\n console.error(`Generating API sequence from prompt...`);\n }\n }\n\n let triggerRes: Response;\n try {\n triggerRes = await fetch(`${apiUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n } catch (err) {\n console.error(`Failed to connect to API: ${err}`);\n process.exit(1);\n }\n\n if (triggerRes.status === 403) {\n const data = (await triggerRes.json().catch(() => ({}))) as { error?: string };\n console.error(`Error: ${data.error ?? 'This feature is not enabled for your organization.'}`);\n process.exit(1);\n }\n\n if (!triggerRes.ok) {\n const data = (await triggerRes.json().catch(() => ({}))) as { error?: string };\n console.error(`Error: ${data.error ?? `${triggerRes.status} ${triggerRes.statusText}`}`);\n process.exit(1);\n }\n\n const triggerData = (await triggerRes.json()) as GenerateResponse;\n if (!triggerData.ok || !triggerData.generationId) {\n console.error(`Error: ${triggerData.error ?? 'Failed to start generation'}`);\n process.exit(1);\n }\n\n const { generationId } = triggerData;\n\n // 2. Subscribe to SSE stream\n const streamUrl = `${apiUrl}/api-sequence-agent/stream?generationId=${generationId}`;\n\n let streamRes: Response;\n try {\n streamRes = await fetch(streamUrl, {\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: 'text/event-stream',\n },\n });\n } catch (err) {\n console.error(`Failed to connect to event stream: ${err}`);\n process.exit(1);\n }\n\n if (!streamRes.ok || !streamRes.body) {\n console.error(`Failed to connect to event stream: ${streamRes.status}`);\n process.exit(1);\n }\n\n // 3. Parse SSE events\n let resultConfig: unknown = null;\n let resultSummary = '';\n let hasCompleted = false;\n let exitCode = 0;\n\n const parser = createParser({\n onEvent: (event: EventSourceMessage) => {\n if (!event.data || event.event !== 'api-sequence-generation') return;\n\n try {\n const data = JSON.parse(event.data) as ApiSequenceEvent;\n\n switch (data.eventType) {\n case 'progress':\n if (!jsonOutput) console.error(` ${data.message}`);\n break;\n\n case 'tool-call':\n if (verbose) console.error(` [tool] ${data.toolName}`);\n break;\n\n case 'tool-result':\n if (verbose) {\n const icon = data.success ? '\\u2713' : '\\u2717';\n console.error(` [tool] ${icon} ${data.toolName}`);\n }\n break;\n\n case 'text':\n // Accumulate but don't print deltas in non-verbose mode\n if (verbose) process.stderr.write(data.delta);\n break;\n\n case 'complete':\n resultConfig = data.config;\n resultSummary = data.summary;\n hasCompleted = true;\n break;\n\n case 'error':\n console.error(`\\nError: ${data.message}`);\n exitCode = 1;\n hasCompleted = true;\n break;\n }\n } catch {\n // Ignore parse errors for keepalive etc.\n }\n },\n });\n\n const reader = streamRes.body.getReader();\n const decoder = new TextDecoder();\n\n try {\n while (!hasCompleted) {\n const { done, value } = await reader.read();\n if (done) break;\n parser.feed(decoder.decode(value, { stream: true }));\n }\n } finally {\n reader.releaseLock();\n }\n\n // 4. Output result\n if (exitCode !== 0) {\n process.exit(exitCode);\n }\n\n if (!resultConfig) {\n console.error('Generation completed but no config was returned.');\n process.exit(1);\n }\n\n if (jsonOutput) {\n writeRawOutput(JSON.stringify({ ok: true, config: resultConfig, summary: resultSummary }, null, 2));\n } else {\n if (resultSummary) {\n console.error('');\n console.error(resultSummary);\n }\n console.error('');\n writeRawOutput(JSON.stringify(resultConfig, null, 2));\n }\n}\n","/**\n * `canary workflow api-sequence <verb>` — manage the API sequence attached to an\n * api-only workflow.\n *\n * All verbs take a workflowId (not a raw apiSequenceId) to match the agent's\n * mental model: \"the sequence attached to this workflow\". The CLI resolves the\n * apiSequenceId via GET /api-sequences/by-workflow/:workflowId in one extra hop.\n *\n * Output auto-detects JSON (piped) vs text (TTY); --json/--text force either.\n *\n * @module WorkflowApiSequenceCmdsCLI\n */\n\nimport fs from 'node:fs/promises';\nimport process from 'node:process';\nimport { getArgValue, hasFlag } from './auth.js';\nimport { apiRequest } from './cli-helpers.js';\nimport { handleWorkflowGenerateApiSequence } from './workflow-api-sequence.js';\nimport { writeRawOutput } from './brand.js';\n\n/* ── Arg helpers ───────────────────────────────────────────────────────── */\n\nfunction getArg(argv: string[], key: string): string | undefined {\n const prefix = `${key}=`;\n const eq = argv.find((a) => a.startsWith(prefix));\n if (eq) return eq.slice(prefix.length);\n return getArgValue(argv, key);\n}\n\nfunction wantsJson(argv: string[]): boolean {\n if (hasFlag(argv, '--json')) return true;\n if (hasFlag(argv, '--text')) return false;\n return !process.stdout.isTTY;\n}\n\nfunction emit(argv: string[], textFallback: string, json: unknown): void {\n if (wantsJson(argv)) {\n writeRawOutput(JSON.stringify(json, null, 2));\n } else {\n console.log(textFallback);\n }\n}\n\nasync function readJsonInput(argv: string[]): Promise<unknown> {\n const fromFile = getArg(argv, '--from-file');\n let raw: string;\n if (fromFile) {\n raw = await fs.readFile(fromFile, 'utf-8');\n } else if (hasFlag(argv, '--from-stdin') || !process.stdin.isTTY) {\n raw = await readStdin();\n } else {\n throw new Error('Provide --from-file <path> or pipe JSON on stdin.');\n }\n try {\n return JSON.parse(raw);\n } catch {\n throw new Error('Invalid JSON input.');\n }\n}\n\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n process.stdin.on('data', (chunk) => {\n chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);\n });\n process.stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));\n process.stdin.on('error', reject);\n });\n}\n\n/* ── Types ─────────────────────────────────────────────────────────────── */\n\ninterface ApiSequenceStep {\n id?: string;\n endpointId?: string;\n method?: string;\n path?: string;\n [k: string]: unknown;\n}\n\ninterface ApiSequenceConfig {\n steps: ApiSequenceStep[];\n description?: string;\n stopOnFailure?: boolean;\n exports?: unknown[];\n}\n\ninterface ApiSequenceRecord {\n id: string;\n workflowId: string;\n orgId: string;\n credentialId: string | null;\n config: ApiSequenceConfig;\n status: string;\n guidancePrompt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface ByWorkflowResponse {\n ok: boolean;\n error?: string;\n code?: string;\n data?: ApiSequenceRecord | null;\n}\n\ninterface ExecuteResponse {\n ok: boolean;\n error?: string;\n data?: { runId: string; status: string };\n}\n\ninterface ValidationIssue {\n path: string;\n code: string;\n message: string;\n hint?: string;\n}\n\ninterface GenericResponse {\n ok: boolean;\n error?: string;\n code?: string;\n issues?: ValidationIssue[];\n data?: unknown;\n}\n\n/**\n * Handle an error response from an api-sequence mutation. If the server\n * returned API_SEQUENCE_INVALID, emit a dense, machine-parseable report\n * so a coding agent can iterate: JSON mode emits `{ok:false, error, code,\n * issues}` to stdout; text mode writes `path [CODE] :: message` lines to\n * stderr. Always exits 1.\n *\n * Returns without exiting for non-validation errors so the caller can\n * fall back to its own error formatting.\n */\nfunction reportAndMaybeExit(\n argv: string[],\n result: { ok: boolean; error?: string; code?: string; issues?: ValidationIssue[] },\n): void {\n if (result.ok) return;\n\n if (result.code === 'API_SEQUENCE_INVALID' && Array.isArray(result.issues)) {\n if (wantsJson(argv)) {\n // stdout, so agents piping to jq get the full structured payload.\n writeRawOutput(JSON.stringify(\n {\n ok: false,\n error: result.error ?? 'API sequence configuration is invalid',\n code: 'API_SEQUENCE_INVALID',\n issueCount: result.issues.length,\n issues: result.issues,\n },\n null,\n 2,\n ),\n );\n } else {\n console.error(`Error: ${result.error ?? 'API sequence configuration is invalid'}`);\n console.error(\n `Found ${result.issues.length} issue${result.issues.length === 1 ? '' : 's'}:`,\n );\n console.error('');\n // Dense form: one issue per line, `path [CODE] :: message` — grep/jq-friendly.\n for (const issue of result.issues) {\n console.error(` ${issue.path || '(root)'} [${issue.code}] :: ${issue.message}`);\n if (issue.hint) console.error(` hint: ${issue.hint}`);\n }\n console.error('');\n console.error(\n 'Re-run with --json for machine-readable output, or fix the listed fields and retry.',\n );\n }\n process.exit(1);\n }\n\n // Non-validation error — caller-provided formatting.\n return;\n}\n\n/* ── Dispatcher ────────────────────────────────────────────────────────── */\n\nexport async function handleWorkflowApiSequence(\n argv: string[],\n apiUrl: string,\n token: string,\n): Promise<void> {\n const [verb, ...rest] = argv;\n switch (verb) {\n case 'get':\n await handleGet(rest, apiUrl, token);\n break;\n case 'update':\n await handleUpdate(rest, apiUrl, token);\n break;\n case 'execute':\n case 'run':\n await handleExecute(rest, apiUrl, token);\n break;\n case 'delete':\n await handleDelete(rest, apiUrl, token);\n break;\n case 'set-api-only':\n await handleSetApiOnly(rest, apiUrl, token);\n break;\n case 'generate':\n await handleWorkflowGenerateApiSequence(rest, apiUrl, token);\n break;\n default:\n printHelp();\n process.exit(verb ? 1 : 0);\n }\n}\n\nfunction printHelp() {\n console.error(\n [\n 'Usage: canary workflow api-sequence <verb> <workflowId> [options]',\n '',\n 'Verbs:',\n ' get <wf> fetch the sequence attached to the workflow',\n ' update <wf> --from-file <f> replace config (steps, description, exports...); creates the sequence if the workflow has none',\n ' update <wf> --from-stdin replace config from piped JSON',\n ' execute <wf> run the sequence; returns { runId, status }',\n ' delete <wf> delete the api-sequence record (keeps workflow)',\n ' set-api-only <wf> [--off] toggle the workflow\\'s apiOnly flag',\n ' generate <wf> [--prompt ...] AI-generate a config (streams progress)',\n '',\n 'Global options:',\n ' --json force JSON output',\n ' --text force pretty-text output (default when stdout is a TTY)',\n '',\n 'Config shape (for update): { steps: [...], description?, stopOnFailure?, exports? }',\n 'Run \"canary workflow guide api-sequences\" for step shape and template syntax.',\n ].join('\\n'),\n );\n}\n\n/* ── Helpers ───────────────────────────────────────────────────────────── */\n\nasync function fetchSequenceByWorkflow(\n apiUrl: string,\n token: string,\n workflowId: string,\n): Promise<ApiSequenceRecord> {\n const res = await apiRequest<ByWorkflowResponse>(\n apiUrl,\n token,\n 'GET',\n `/api-sequences/by-workflow/${workflowId}`,\n );\n if (!res.ok) {\n console.error(`Error: ${res.error ?? 'Failed to fetch sequence'}`);\n process.exit(1);\n }\n if (!res.data) {\n console.error(`Error: Workflow ${workflowId} has no attached API sequence.`);\n console.error('Create one with: canary workflow create --api-only --name <n> --sequence-from-file seq.json');\n process.exit(1);\n }\n return res.data;\n}\n\n/* ── Handlers ──────────────────────────────────────────────────────────── */\n\nasync function handleGet(argv: string[], apiUrl: string, token: string): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n printHelp();\n process.exit(1);\n }\n const seq = await fetchSequenceByWorkflow(apiUrl, token, workflowId);\n emit(argv, renderSequence(seq), seq);\n}\n\nasync function handleUpdate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n printHelp();\n process.exit(1);\n }\n\n let parsed: unknown;\n try {\n parsed = await readJsonInput(argv);\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n const config = parsed as ApiSequenceConfig;\n if (!config || !Array.isArray(config.steps)) {\n console.error('Error: Input must have a \"steps\" array. Got: ' + JSON.stringify(config));\n process.exit(1);\n }\n\n // A workflow with no sequence yet gets one created from this config.\n const existing = await apiRequest<ByWorkflowResponse>(\n apiUrl,\n token,\n 'GET',\n `/api-sequences/by-workflow/${workflowId}`,\n );\n // The server answers 404 API_SEQUENCE_NOT_FOUND when the workflow has none.\n const absent = !existing.ok && existing.code === 'API_SEQUENCE_NOT_FOUND';\n if (!existing.ok && !absent) {\n console.error(`Error: ${existing.error ?? 'Failed to fetch sequence'}`);\n process.exit(1);\n }\n const seq = existing.data;\n\n const result = seq\n ? await apiRequest<GenericResponse>(\n apiUrl,\n token,\n 'PUT',\n `/api-sequences/${seq.id}/config`,\n { config },\n )\n : await apiRequest<GenericResponse>(apiUrl, token, 'POST', '/api-sequences/save', {\n workflowId,\n config,\n });\n\n reportAndMaybeExit(argv, result);\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Update failed'}`);\n process.exit(1);\n }\n\n emit(\n argv,\n seq\n ? `Updated api-sequence ${seq.id} (workflow ${workflowId}). Steps: ${config.steps.length}.`\n : `Created api-sequence for workflow ${workflowId}. Steps: ${config.steps.length}.`,\n result,\n );\n}\n\nasync function handleExecute(argv: string[], apiUrl: string, token: string): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n printHelp();\n process.exit(1);\n }\n\n const seq = await fetchSequenceByWorkflow(apiUrl, token, workflowId);\n\n const result = await apiRequest<ExecuteResponse>(\n apiUrl,\n token,\n 'POST',\n `/api-sequences/${seq.id}/execute`,\n );\n\n if (!result.ok || !result.data) {\n console.error(`Error: ${result.error ?? 'Execute failed'}`);\n process.exit(1);\n }\n\n emit(\n argv,\n `Run started: ${result.data.runId} (status: ${result.data.status})\\n` +\n `Inspect: canary workflow runs get ${workflowId} ${result.data.runId}`,\n result,\n );\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n printHelp();\n process.exit(1);\n }\n\n const seq = await fetchSequenceByWorkflow(apiUrl, token, workflowId);\n\n const result = await apiRequest<GenericResponse>(\n apiUrl,\n token,\n 'DELETE',\n `/api-sequences/${seq.id}`,\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Delete failed'}`);\n process.exit(1);\n }\n\n emit(argv, `Deleted api-sequence ${seq.id} (workflow ${workflowId}).`, result);\n}\n\nasync function handleSetApiOnly(\n argv: string[],\n apiUrl: string,\n token: string,\n): Promise<void> {\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: Missing workflow ID.');\n printHelp();\n process.exit(1);\n }\n\n const apiOnly = !hasFlag(argv, '--off');\n\n const result = await apiRequest<GenericResponse>(\n apiUrl,\n token,\n 'PUT',\n `/workflows/${workflowId}/api-only`,\n { apiOnly },\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Update failed'}`);\n process.exit(1);\n }\n\n emit(argv, `Workflow ${workflowId} apiOnly=${apiOnly}.`, result);\n}\n\n/* ── Rendering ─────────────────────────────────────────────────────────── */\n\nfunction renderSequence(seq: ApiSequenceRecord): string {\n const lines: string[] = [];\n lines.push(`API Sequence ${seq.id}`);\n lines.push(` Workflow: ${seq.workflowId}`);\n lines.push(` Status: ${seq.status}`);\n if (seq.credentialId) lines.push(` Credential: ${seq.credentialId}`);\n if (seq.config.description) lines.push(` Description: ${seq.config.description}`);\n lines.push(` stopOnFailure: ${seq.config.stopOnFailure ?? false}`);\n lines.push('');\n\n const steps = seq.config.steps ?? [];\n if (steps.length === 0) {\n lines.push(' (no steps — use `api-sequence update` to add)');\n } else {\n lines.push(` Steps (${steps.length}):`);\n steps.forEach((step, i) => {\n const method = String(step.method ?? '??').toUpperCase().padEnd(6);\n const path = step.path ?? '(no path)';\n const id = step.id ? ` [${step.id}]` : '';\n lines.push(` ${String(i + 1).padStart(2)}. ${method} ${path}${id}`);\n if (step.endpointId) lines.push(` endpointId: ${step.endpointId}`);\n });\n }\n\n const exports = seq.config.exports ?? [];\n if (exports.length > 0) {\n lines.push('');\n lines.push(` Exports: ${JSON.stringify(exports)}`);\n }\n\n return lines.join('\\n');\n}\n","/**\n * CLI Seed Workflow Creation\n *\n * Creates a seed workflow shell with outputs and an optional paired teardown.\n * Supports flag-based and JSON-based input.\n *\n * @module workflow-seed-create\n */\n\nimport fs from 'node:fs/promises';\nimport process from 'node:process';\nimport { getArgValue, hasFlag, resolveOrgAppUrl } from './auth.js';\nimport { apiRequest } from './cli-helpers.js';\nimport { writeRawOutput } from './brand.js';\n\n/* ── Types ────────────────────────────────────────────────────────────── */\n\ntype SeedOutput = {\n dataKey: string;\n name: string;\n displayLabel: string;\n description?: string;\n credentialOutput?: Record<string, unknown>;\n};\n\ntype SeedCreateInput = {\n name: string;\n description?: string;\n status?: 'draft' | 'approved';\n outputs?: SeedOutput[];\n};\n\ntype WorkflowResponse = {\n ok: boolean;\n error?: string;\n workflow?: { id: string; name: string; status: string; flowType: string };\n};\n\ntype WorkflowUpdateResponse = {\n ok: boolean;\n error?: string;\n workflow?: { id: string };\n};\n\n/* ── Helpers ──────────────────────────────────────────────────────────── */\n\nfunction getAllArgValues(argv: string[], flag: string): string[] {\n const values: string[] = [];\n for (let i = 0; i < argv.length; i++) {\n if (argv[i] === flag && i + 1 < argv.length) {\n values.push(argv[i + 1]!);\n i++;\n }\n }\n return values;\n}\n\n/**\n * Parse an --output flag value: \"dataKey:Name[:description]\"\n */\nfunction parseOutputFlag(value: string): SeedOutput {\n const parts = value.split(':');\n if (parts.length < 2) {\n throw new Error(\n `Invalid --output format: \"${value}\". Expected \"dataKey:Name\" or \"dataKey:Name:Description\".`\n );\n }\n const [dataKey, name, ...descParts] = parts;\n const description = descParts.length > 0 ? descParts.join(':') : undefined;\n return {\n dataKey: dataKey!.trim(),\n name: name!.trim(),\n displayLabel: name!.trim(),\n description: description?.trim() || undefined,\n };\n}\n\nasync function readFromStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n const stdin = process.stdin;\n\n if (stdin.isTTY) {\n throw new Error('No input on stdin. Pipe JSON or use --from-file.');\n }\n\n return new Promise((resolve, reject) => {\n stdin.on('data', (chunk) => {\n chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);\n });\n stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));\n stdin.on('error', reject);\n });\n}\n\nasync function readJsonInput(argv: string[]): Promise<SeedCreateInput> {\n let raw: string;\n\n const fromFile = getArgValue(argv, '--from-file');\n if (fromFile) {\n try {\n raw = await fs.readFile(fromFile, 'utf-8');\n } catch (err) {\n throw new Error(`Failed to read file ${fromFile}: ${err instanceof Error ? err.message : String(err)}`);\n }\n } else {\n raw = await readFromStdin();\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error('Invalid JSON input.');\n }\n\n const input = parsed as SeedCreateInput;\n if (!input.name || typeof input.name !== 'string') {\n throw new Error('JSON input must include a \"name\" string field.');\n }\n\n // Normalize outputs: default displayLabel to name if missing\n if (Array.isArray(input.outputs)) {\n for (const out of input.outputs) {\n if (!out.dataKey || !out.name) {\n throw new Error('Each output must have \"dataKey\" and \"name\" fields.');\n }\n if (!out.displayLabel) {\n out.displayLabel = out.name;\n }\n }\n }\n\n return input;\n}\n\nfunction resolveInput(argv: string[]): Promise<SeedCreateInput> | SeedCreateInput {\n const fromFile = getArgValue(argv, '--from-file');\n const fromStdin = hasFlag(argv, '--from-stdin');\n\n // JSON input mode\n if (fromFile || fromStdin) {\n return readJsonInput(argv);\n }\n\n // Flag-based input mode\n const name = getArgValue(argv, '--name');\n if (!name) {\n console.error('Error: --name is required (or use --from-stdin / --from-file for JSON input).');\n console.error('Usage: canary workflow seed create --name <name> [--output key:name[:desc]] ...');\n process.exit(1);\n }\n\n const description = getArgValue(argv, '--description');\n const status = getArgValue(argv, '--status') as 'draft' | 'approved' | undefined;\n\n // Parse --output flags\n const outputFlags = getAllArgValues(argv, '--output');\n const outputs: SeedOutput[] = outputFlags.map(parseOutputFlag);\n\n // Parse --outputs-json for complex outputs (credential configs etc.)\n const outputsJsonRaw = getArgValue(argv, '--outputs-json');\n if (outputsJsonRaw) {\n try {\n const parsed = JSON.parse(outputsJsonRaw) as SeedOutput[];\n if (!Array.isArray(parsed)) throw new Error('not an array');\n for (const out of parsed) {\n if (!out.dataKey || !out.name) {\n throw new Error('Each output must have \"dataKey\" and \"name\" fields.');\n }\n if (!out.displayLabel) out.displayLabel = out.name;\n }\n outputs.push(...parsed);\n } catch (err) {\n console.error(`Error: Invalid --outputs-json: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n }\n\n return { name, description: description || undefined, status, outputs };\n}\n\n/* ── Main Handler ────────────────────────────────────────────────────── */\n\nexport async function handleWorkflowSeedCreate(\n argv: string[],\n apiUrl: string,\n token: string,\n appSubdomain?: string | null\n): Promise<void> {\n if (hasFlag(argv, '--help', '-h')) {\n printSeedCreateHelp();\n return;\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const noTeardown = hasFlag(argv, '--no-teardown');\n\n let input: SeedCreateInput;\n try {\n input = await resolveInput(argv);\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n // 1. Create seed workflow\n const seedResult = await apiRequest<WorkflowResponse>(\n apiUrl,\n token,\n 'POST',\n '/workflows',\n {\n name: input.name,\n description: input.description,\n status: input.status ?? 'draft',\n flowType: 'seed',\n createdVia: 'cli',\n }\n );\n\n // Success = a workflow row came back. `POST /workflows` historically omitted\n // `ok` from its envelope, so gating on `ok` alone reported false failures even\n // though the seed was created; presence of `workflow` is the reliable signal.\n if (!seedResult.workflow) {\n if (jsonOutput) {\n writeRawOutput(JSON.stringify({ ok: false, error: seedResult.error ?? 'Failed to create seed workflow' }, null, 2));\n } else {\n console.error(`Error: ${seedResult.error ?? 'Failed to create seed workflow'}`);\n }\n process.exit(1);\n }\n\n const seedId = seedResult.workflow.id;\n const appUrl = resolveOrgAppUrl(apiUrl, appSubdomain);\n\n // 2. Set seed outputs if provided\n let outputsSaved = false;\n if (input.outputs && input.outputs.length > 0) {\n const outputsResult = await apiRequest<WorkflowUpdateResponse>(\n apiUrl,\n token,\n 'PUT',\n `/workflows/${seedId}`,\n { seedOutputsJson: input.outputs }\n );\n\n if (outputsResult.ok || outputsResult.workflow) {\n outputsSaved = true;\n } else {\n console.warn(`Warning: Seed created but failed to save outputs: ${outputsResult.error ?? 'Unknown error'}`);\n }\n }\n\n // 3. Create paired teardown (unless --no-teardown)\n let teardownId: string | undefined;\n let teardownName: string | undefined;\n if (!noTeardown) {\n const tdName = `Teardown: ${input.name}`;\n const tdResult = await apiRequest<WorkflowResponse>(\n apiUrl,\n token,\n 'POST',\n '/workflows',\n {\n name: tdName,\n description: `Cleans up seed data from \"${input.name}\"`,\n status: 'draft',\n flowType: 'teardown',\n createdVia: 'cli',\n }\n );\n\n if (tdResult.workflow) {\n teardownId = tdResult.workflow.id;\n teardownName = tdName;\n\n // 4. Link teardown to seed\n const linkResult = await apiRequest<WorkflowUpdateResponse>(\n apiUrl,\n token,\n 'PUT',\n `/workflows/${seedId}`,\n { teardownWorkflowId: teardownId }\n );\n\n if (!linkResult.ok && !linkResult.workflow) {\n console.warn(`Warning: Teardown created but failed to link to seed: ${linkResult.error ?? 'Unknown error'}`);\n }\n } else {\n console.warn(`Warning: Failed to create paired teardown: ${tdResult.error ?? 'Unknown error'}`);\n }\n }\n\n // 5. Output results\n if (jsonOutput) {\n const result: Record<string, unknown> = {\n ok: true,\n seed: {\n id: seedId,\n name: input.name,\n status: input.status ?? 'draft',\n flowType: 'seed',\n outputs: outputsSaved ? input.outputs : [],\n url: `${appUrl}/flows/${seedId}`,\n },\n };\n if (teardownId) {\n result.teardown = {\n id: teardownId,\n name: teardownName,\n status: 'draft',\n flowType: 'teardown',\n url: `${appUrl}/flows/${teardownId}`,\n };\n }\n writeRawOutput(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(`\\n\\u2713 Seed workflow created: ${input.name}`);\n console.log(` ID: ${seedId}`);\n console.log(` Status: ${input.status ?? 'draft'}`);\n if (input.outputs && input.outputs.length > 0) {\n const keys = input.outputs.map((o) => o.dataKey).join(', ');\n console.log(` Outputs: ${keys}${!outputsSaved ? ' (save failed)' : ''}`);\n }\n console.log(` URL: ${appUrl}/flows/${seedId}`);\n\n if (teardownId) {\n console.log(`\\n\\u2713 Teardown workflow created: ${teardownName}`);\n console.log(` ID: ${teardownId}`);\n console.log(` URL: ${appUrl}/flows/${teardownId}`);\n }\n}\n\nfunction printSeedCreateHelp(): void {\n console.log(\n [\n 'Usage: canary workflow seed create [options]',\n '',\n 'Create a seed workflow with declared outputs and an optional paired teardown.',\n '',\n 'Flag-based input:',\n ' --name <name> Seed workflow name (required)',\n ' --description <desc> Description',\n ' --output <key:name[:desc]> Declare an output (repeatable)',\n ' --outputs-json <json> Full outputs array as inline JSON (for credential configs)',\n ' --no-teardown Skip creating paired teardown workflow',\n ' --status <status> Initial status (default: draft)',\n ' --json Output raw JSON',\n '',\n 'JSON input:',\n ' --from-stdin Read full config from stdin',\n ' --from-file <path> Read full config from file',\n '',\n 'Examples:',\n ' canary workflow seed create --name \"Create Project\" --output \"project_id:Project ID\"',\n '',\n ' canary workflow seed create --from-stdin <<\\'EOF\\'',\n ' {',\n ' \"name\": \"Create Test User\",',\n ' \"outputs\": [{',\n ' \"dataKey\": \"user_cred\",',\n ' \"name\": \"Test User Credential\",',\n ' \"credentialOutput\": {',\n ' \"fieldMapping\": { \"username\": \"$generate.email\", \"password\": \"Test123!\" },',\n ' \"emailPrefix\": \"testuser\",',\n ' \"createInboxRecipient\": true',\n ' }',\n ' }]',\n ' }',\n ' EOF',\n ].join('\\n')\n );\n}\n","Workflows are visual test sequences that model user journeys through your application. Each workflow is a directed graph of nodes — login, navigate, action, assertion, wait, condition, seed, and more — connected to form a testable path.\n\nWhen to use workflows:\n\n- Critical paths: signup, checkout, billing, onboarding\n- High-risk areas: features that regress often or have complex logic\n- Multi-step journeys: flows spanning multiple pages or user roles\n\nFor visual regression coverage, add one Visual checkpoint for each meaningful\nstate. Seed the state in Sandboxes v2 before capturing it. See\n`cofactor workflow guide visual-checkpoints` for native and Playwright examples.\n\nFLOW TYPES\n\n standard The default. Models a single user journey end-to-end.\n Login → Navigate → Actions → Assertions → Cleanup.\n\n setup Deprecated. Formerly a prerequisite workflow referenced by a\n setup node; use a seed workflow for shared data and suite\n layers for ordering instead.\n\n seed A data-seeding workflow that generates test data and exports\n variables for downstream workflows. Seed outputs are declared\n in the workflow definition and available as $var.{dataKey}\n in any workflow that references the seed.\n\n teardown A cleanup workflow that runs after a seed workflow completes.\n Automatically invoked to remove data the seed created.\n\n eval A chat eval: one chat_scenario node holding a scripted\n conversation against a chat target, each reply graded by an\n LLM judge. Runs browserless. See the CHAT SCENARIO node type.\n\nEXECUTION MODEL\n\n 1. Login node provisions an authenticated browser session\n 2. Nodes execute in sequence (or branch at condition nodes)\n 3. Each action node interacts with the live application\n 4. Assertions verify expected outcomes\n 5. Additional login nodes switch to a different user — each starts a\n new segment with a fresh session (great for multi-role testing)\n 6. Wait nodes pause execution (minutes, hours, days) — also creating\n segments. After a wait, a login re-establishes the session.\n 7. On completion, the run is marked success or failure\n\nVERSION HISTORY\n\n Workflows maintain version history. Publishing creates a versioned\n snapshot. Previous versions can be previewed or restored to draft.\n Seed nodes reference a specific published version of the seed workflow.\n","Every workflow is built from nodes. Each node has a type, a title, a description,\nand type-specific configuration.\n\nDEACTIVATING A NODE (any type except condition)\n Set `deactivated: true` in the node's config to skip it during runs — the\n step records status `skipped` and execution continues with the next node.\n Useful for converging a flow node-by-node from the front, or parking a\n chronically failing step without deleting it. Toggle via the CLI\n (`workflow node deactivate|activate <workflowId> <nodeId>`) or the node's\n three-dot menu in the Flow Designer. Two rules: a run is blocked while a\n later step still references a `$var` that only a deactivated step produces,\n and condition nodes cannot be deactivated (skipping the branch decision\n would run both branches — deactivate the branch nodes instead).\n\nSTARTING NODE — pick the first node in this order\n The first node of a flow follows a strict hierarchy. Getting this wrong is the\n single most common authoring mistake (most often: opening with a navigate node).\n\n 1. SEED first — if the flow depends on pre-existing data, a `seed` node comes\n first. It provisions data in its own isolated context and exports\n $var.{dataKey} outputs the rest of the flow consumes.\n 2. Otherwise LOGIN first — for any authenticated flow, the first node is a\n `login` node that declares the ACTOR (who the journey runs as). This is the\n \"acting as\" step. Do NOT open an authenticated flow with a navigate node.\n 3. Navigate comes AFTER login — a navigate jumps to the test's entry point, but\n it follows the login; it is never the opening node of an authenticated flow.\n\n The only flows that may start with a navigate are UNauthenticated ones — signup,\n password reset, a public/marketing page, or a test of the login experience\n itself. For those, set the login node's `performLogin: false` (or omit the login\n node) and author the steps as the journey.\n\n LOGIN SUBSUMES LOGGING IN. A login node already provisions an authenticated\n session — it IS the act of logging in. Never emit a login node and then a\n \"navigate to /login\" → \"enter email/password\" → \"click Sign in\" sequence. Start\n with the login node and go straight to the first real action. The one exception\n is a flow whose explicit purpose is to test login (start logged out and make the\n login steps the journey).\n\nLOGIN\n Sets the user context. Select a credential to act as that user.\n The login node provisions an authenticated browser session — subsequent\n nodes start with the browser already logged in.\n\n Config:\n credentialId UUID of the credential to log in as. REQUIRED for the\n node to bind to a real credential. Without it the\n Flow Designer shows a red \"Select a credential\"\n warning even if credentialName is set.\n credentialName Human-readable name, used as the node title. Optional\n but recommended alongside credentialId.\n performLogin When true, the browser is authenticated automatically.\n\n Finding the credentialId:\n cofactor credential list [--env prod|dev]\n → prints \"ID: <uuid>\" under each credential name.\n Pick the ID whose property matches the environment the flow runs in.\n\n Ordering: login nodes should typically follow any seed nodes, not\n precede them. Seeds export variables (e.g. $var.workflow_id) that\n later nodes consume, so a seed-first / login-second order avoids\n wasted browser segments and lets login/navigate URLs reference\n seed outputs. See the SEED node type and the Node Ordering section\n of best-practices.\n\n - Workflows support multiple login nodes for multi-role testing.\n Each login node starts a new segment with a fresh browser session.\n Example: Login as Customer → place order → Login as Sales Rep → verify order.\n Great for two-sided apps, permission checks (member vs admin), and\n cross-role journeys.\n - Login nodes also appear after Wait nodes to re-establish the session.\n - A navigate node after login is optional but useful for jumping\n directly to the test's entry point.\n\nNAVIGATE\n Directs the browser to a specific path.\n\n Prefer relative paths (e.g. \"/flows\", \"/flows/$var.workflow_id\")\n over hard-coded absolute URLs. Relative paths let the same workflow\n run unchanged across environments (prod, dev, local, preview) — the\n base URL comes from the property/environment the run targets. A\n workflow that hard-codes \"https://app.dev.runcofactor.com/...\" will\n silently drive traffic against dev even when run against prod.\n\n Use an absolute URL only when the destination is genuinely off the\n application being tested (external identity provider, third-party\n checkout, docs site, etc.).\n\n - A navigate node after login is a great way to jump straight to the\n page where the test begins.\n - Select from discovered pages or enter a custom URL.\n\nACTION\n Performs a user interaction on the current page. Describe what the user\n should do (\"Create a new ticket\") and optionally provide input data via\n formFields.\n\n Every action node must have a title (customActionTitle). The title shows\n in the canvas, run timeline, failure reports, and issue tickets — an\n untitled action is nearly impossible to reason about after the fact.\n Keep titles short and intent-oriented: name the goal (and, where it helps,\n the purpose), e.g. \"Create a ticket\", \"Publish the flow\", or \"Click Start to\n open the run-config modal\". A title that names only the mechanics with no\n intent (\"Click the button\") is the thing to avoid.\n\n Keep actions focused on a single user goal — usually broader than one click,\n but a lone action that genuinely stands alone in the flow is a fine node:\n Good: \"Create a ticket with required fields\"\n Good: \"Click Start to open the run-config modal\" (single action — but it\n stands on its own and names its purpose)\n Bad: \"Click the button\" (mechanics only, no intent)\n Bad: \"Create a ticket, assign it, comment, upload, and verify\" (too stuffed)\n\n Aim for ~3–8 playbook steps per node; if a single outcome needs more, split it\n into sequential action nodes. See the Action Nodes section for the full\n altitude guidance (coherent step, assertion boundary, no hidden conditionals).\n\n Rule of thumb: if an action crosses multiple screens or changes multiple\n entities, split it. If it's a single user goal on a single screen, keep it.\n\n Actions can include:\n - customActionTitle: short intent-oriented title (required)\n - formFields: input data the action needs (name, email, etc.)\n - inlineAssertions: checks verified after the action completes (preferred\n over standalone assertion nodes — see Assertions section)\n - declaredOutputs: values to extract from the page for downstream use\n - customInstructions: additional guidance for the agent executing the step\n\nASSERTION\n Verifies expected outcomes. Define a condition to check.\n What happens on failure depends on the severity.\n\n Prefer inline assertions on action nodes over standalone assertion nodes.\n Inline assertions keep the test on track and produce cleaner failure\n reports. If verifying something requires significant interaction first,\n that's better modeled as an action node with inline assertions.\n\n Use standalone assertion nodes only when the check doesn't belong to\n any action — e.g., verifying a page state after navigation, or\n confirming data absence after a sequence of steps.\n\n Severity levels:\n fatal The test must end now — the run halts at this step.\n Use for preconditions later steps depend on.\n fail The test may continue — the run finishes marked failed,\n but later steps still run and produce signal.\n warn The test should continue — logged as a warning, run passes.\n\n Agentic assertions: for visual/layout checks that can't be mechanically\n validated, enable agent evaluation. These require the AI agent during\n replay and cannot be cached. Use for:\n - Timestamps or dates\n - Real-time data feeds\n - Content that changes between runs\n\nCONDITION\n Branches the workflow based on a runtime condition. Define a condition\n to evaluate, then connect separate paths for true and false outcomes.\n The condition is deterministic when it compares a $var or the acting-as\n identity (evaluated without the agent); otherwise the agent evaluates it\n against the live page.\n\n Reach for a condition node only when the branch is genuine. Conditional\n logic baked INTO an action node — \"if it isn't set to New York, set it\" /\n \"if patient X is missing, create X\" — is usually a sign the data wasn't\n staged, and it caches poorly. Prefer, in order: seed the precondition so\n the branch disappears; run an idempotent sequence unconditionally when the\n same steps reach the goal from any starting state; else a formal condition\n node. If a conditional must live inside an action node, set\n `alwaysUseAgent: true` on that node so the branch is reasoned about live and\n never mis-cached. See the Action Nodes section.\n\nWAIT\n Pauses execution for a specified duration (minutes, hours, or days).\n Creates a segmented flow — execution pauses, then resumes automatically.\n Add a Login node after the Wait to re-establish the browser session.\n\nSETUP (DEPRECATED)\n Referenced another published workflow as a prerequisite. Do not author\n new setup nodes. For shared data use a SEED node (below); for workflows\n that must run in order use suite layers (cofactor test-suite --layer).\n Existing specs that carry a setup node still parse.\n\nSEED\n Injects outputs from a seed workflow as variables. Seed workflows\n generate test data and export named values. Downstream workflows\n access these as $var.{dataKey}.\n\n Ordering: seed nodes should almost always come FIRST — before the\n login node. Seeds run in their own isolated context (usually via\n API sequence) and export variables into the workflow. Placing a\n login before the seed wastes a browser session, and any\n login/navigate node that references $var.{seed_output} must come\n after the seed that produces it.\n\n Typical pattern:\n Seed → Login → Navigate → ... action/assertion nodes\n\n Config:\n seedWorkflowId UUID of the seed workflow (required)\n seedWorkflowName Human-readable name (used as the node title)\n\n Seed workflows provision data that several tests share; data unique to\n one test is created inline. See the Seed Workflows section.\n\nAPI SEQUENCE\n Executes multiple API calls in sequence without a browser.\n Use for backend-only operations, webhooks, or API testing.\n\n API sequences are also used inside seed workflows — start with a\n browser-based seed to discover the right API calls, then convert\n to an API sequence for speed and reliability.\n\nSANDBOX ACTION\n Executes a sandbox action — a server-side script defined on the\n environment template — directly on the run environment's sandbox\n instance. No browser involved. The action's structured output is\n registered as workflow variables: each output key becomes\n $var.{key} for downstream steps.\n\n Config:\n actionSlug Slug of the action (required; discover via\n list_sandbox_actions)\n params Input values keyed by the action's inputSchema\n property names; values may use $var.{name} / macros\n outputKeys Output variable keys (defaults to the action's\n outputSchema keys)\n\n Output registration is allowlisted by declared intent: the action's\n outputSchema keys, else the node's outputKeys. If neither declares\n anything, NO result keys register — declare outputs explicitly for\n schema-less actions.\n\n Environment constraint: the action runs on the environment's\n backing sandbox instance. On a non-sandbox environment (static\n staging/prod) the node SKIPS with a warning and registers no\n variables — so workflows containing one are effectively\n sandbox-only.\n\n Seeds: a seed workflow whose body is a single sandbox action node\n is the fastest way to provision data — it runs entirely\n server-side (no browser session), and its outputs satisfy the\n seed's declared outputs like any captured value.\n\nMCP\n Drives an MCP-server application — an application (property) with type\n \"mcp\" — by letting an agent accomplish a plain-language goal through the\n server's tools. No browser involved. Use it to test an MCP server the org\n has registered as an application: exercising its tool surface, creating or\n mutating data through MCP tools, and capturing returned values as\n workflow variables.\n\n When to use: the step's target is the MCP server itself. To verify the\n EFFECT of the MCP work in the product UI, keep the MCP interaction in the\n mcp node and put the browser verification in SUBSEQUENT action/assertion\n nodes — an mcp node never drives the browser.\n\n Authoring fields (create_node / update_node):\n mcpApplicationName Name of the MCP application (required; discover via\n list_mcp_applications). Resolved to the stored\n application id at authoring time.\n mcpInstructions Plain-language goal (falls back to description).\n State ONE verifiable outcome and name the values to\n capture — \"Create a project named Acme via the\n create_project tool and capture its id as\n project_id\", not \"try out the project tools\".\n mcpPersona Persona (credential template name) supplying\n authentication, resolved against the application.\n Preferred over pinning a raw credential.\n mcpOutputs Variable names the node must produce; each becomes\n $var.{name} for downstream steps.\n mcpTools Optional allowlist restricting which server tools\n the agent may call; omit to allow all.\n\n Like action nodes, mcp nodes replay from cache first with agent fallback\n (set alwaysUseAgent in config to skip replay). Requires the mcp.testing\n feature flag for the organization.\n\nCHAT SCENARIO\n Runs a scripted conversation against a chat target — a saved description\n of how to talk to an AI chat — and grades each reply with an LLM judge.\n No browser involved. This is the node a chat eval is built around: a flow\n of flowType \"eval\" holds the conversation in one chat_scenario node, and\n may chain other nodes either side of it — an api_sequence before it to\n establish ground truth a rubric compares against, a call_flow after it to\n have a browser flow verify what the assistant claims it did.\n\n When to use: the thing under test is what an assistant SAYS. It suits\n binary invariants (\"declines a cross-org request\", \"says a capability is\n unavailable rather than inventing data\"), not scoring or benchmarking.\n\n Each turn sends one user message and judges the reply against that turn's\n assertions plus every global invariant declared on the chat target — one\n batched judge call per reply. An assertion is a plain-language rubric and\n the verdict is binary; severity decides whether a failure fails the step\n (\"fail\") or only warns (\"warn\").\n\n Config:\n chatTargetId Chat target to talk to (required). Manage targets under\n Test Data -> Applications -> <app> -> Chat.\n turns Ordered list, at least one. Each turn is\n { id, message, assertions: [{ id, rubric, severity }] }.\n\n Messages AND rubrics interpolate $var.{name}, so an upstream api_sequence\n node can establish ground truth and a rubric can compare against it —\n \"Reports a status matching $var.expected_status\". Rubrics resolve against\n non-credential variables only, so $var.credential.* can never reach the\n judge. A rubric still holding an unresolved $var after expansion is\n withheld from the judge and recorded as a failure naming the missing\n variable, rather than being graded as literal template text.\n\n One asymmetry: a message is expanded on the way OUT, but the transcript\n and the judge see it as authored — a bubble can read \"…order\n $var.order_id\" though the target got the value. The judge grades the\n RESPONSE, so this is usually cosmetic; when a rubric compares the reply\n against the message, put the $var in the rubric too.\n\n Chat scenarios are start-node eligible and run browserless, like mcp and\n api_sequence, so a [chat_scenario, call_flow] flow boots no browser of its\n own while the called child still drives a real one.\n\n The evals feature flag gates chat targets — creating, listing and editing\n them — so in practice an org needs it before a chat scenario has anything\n to point at.\n\nCALL FLOW\n Runs another flow from inside this one, passing arguments in and getting\n that flow's declared outputs back as variables. The child executes as its\n own nested run with its own environment, credentials and browser session,\n so a browserless parent can call a browser child and still watch it.\n\n When to use: a check you want to reuse. Unlike seed nodes —\n which are hoisted out of the chain and run before everything else — a\n call_flow node runs exactly where you put it, which is what makes it\n usable AFTER a chat_scenario or an action node.\n\n The flow picker in the designer lists only approved-and-promoted (or\n eligible) flows, so a draft is not offered — but that is a picker filter,\n not a runtime rule. Authoring a call_flow node directly against a draft's\n id, as `workflow create` can, is not blocked today; the handler only\n checks that the caller may read the flow.\n\n Arguments map to the child's declared value inputs by name, and an\n argument the child no longer declares fails the step rather than being\n silently dropped. Only outputs the child DECLARES cross the boundary.\n\n Config:\n flowId Flow to run (required). A flow cannot call itself.\n flowName Cached child name, used as the node title.\n snapshotVersion Pinned published version, or null for the live definition.\n inputValues Map of the child's declared input names to values.\n $var.{name} is interpolated here; macros pass through\n unresolved so the child's own macro context expands\n them and per-run uniqueness is preserved.\n environmentId Explicit environment override, or null to let the\n parent's environment apply when the child is eligible\n for it, else the child's own resolution.\n executionMode recommended | api | browser\n onFailure block (default) — a failed child fails this step;\n warn — a child that ran to completion and failed only\n warns. A child this step could not START — bad flowId,\n depth cap hit, an argument the child does not declare —\n fails either way: misconfiguration is never softened.\n\n Declared outputs arrive as both a bare $var.{key} and a namespaced\n $var.{Child_Flow_Name}.{key}, where the child's name is slugified —\n \"Verify checkout totals\" becomes $var.Verify_checkout_totals.{key}. Use\n the namespaced form when two called flows export the same key.\n\n Nesting is capped at 5 levels. Each level is a full run with its own\n browser session, so cost compounds.\n\nNOTIFICATION\n Sends notifications (Slack, email, etc.) at a point in the workflow.\n\nVISUAL CHECKPOINT\n Captures a meaningful screen state (whole page, or an element named by a\n plain-English target) and compares it with the rolling baseline. Fields:\n name, optional target, optional expected state, severity (record or fail).\n See `cofactor workflow guide visual-checkpoints`.\n\nEND\n Explicitly terminates the workflow. Use when a condition branch\n should stop execution rather than continue.","This is the exact syntax of a `.cofactor.md` spec file — what the parser actually matches, not\na loose description. A spec that reads as good prose but drifts from this grammar does NOT\nerror at parse time in most cases: the parser drops the line/bullet it can't match and reports\nonly a warn-severity issue. A spec can validate as \"ok\" while silently missing content the\nauthor wrote. When in doubt, match the grammar below character-for-character rather than\nwriting what merely reads naturally.\n\nFRONTMATTER\n\n A `---`-fenced YAML block, first thing in the file:\n\n ---\n name: Org onboarding — invite a member\n workflowId: <uuid> # present only once compiled; NEVER remove or edit it by hand\n status: draft # draft | approved\n flowType: standard # standard | seed | teardown | eval (setup is deprecated)\n actor: admin # persona name (or \"persona <role>\"), \"credential <name>\"\n # for one fixed account, or \"seed-output <dataKey>\" for a\n # seed's credential output — see ACTOR FORMS below\n authenticated: true\n tags: [smoke, p0]\n requirementRef: LIN-4421\n ---\n\n `workflowId` binds the file to a live workflow: present → `spec_compile` diffs/updates that\n workflow; absent → `spec_compile` creates a new one. If it's present, treat it as immutable —\n removing it turns your next compile into a duplicate-creating CREATE instead of an UPDATE.\n\nSECTION HEADINGS (H2, in this order)\n\n ## Spirit — one blockquote paragraph: the user-visible promise this flow proves.\n Becomes the workflow's description, so it carries no capability codes,\n preconditions, issue ids, status, step narration or raw IDs.\n ## Preflight — plain prose or bullets: non-seedable preconditions the environment must\n already satisfy, including pre-existing data the test reads but does not\n own, and external systems (flags, payments, third parties) it relies on.\n Becomes the workflow's preflight field. Name things, never IDs.\n ## Cleanup — plain prose or bullets: how the run's side effects get reset. Becomes\n the workflow's cleanup field.\n ## Inputs — bullets: `- <name>: <defaultValue>` or `- credential <name>: <value>`.\n ## Declared Outputs — seed flows only: `- <dataKey>` bullets with optional indented\n `- label:` / `- property:` / `- description:` sub-bullets. A\n credentialOutput block is NOT authorable here — it is preserved from\n the live seed (rendered as an HTML comment on pull) and set via the\n Flow Designer or `workflow seed create --from-file` / `workflow patch\n --seed-outputs-file` (see `workflow guide seed-users`).\n ## Scenarios — H3 sub-blocks per scenario: `### <Name> *(default)*` or `*(skip: <reason>)*`,\n with `- values: {...}` / `- credentials: {...}` YAML underneath.\n ## Journey — the linear sequence of nodes described below. Required — a spec with no\n Journey nodes fails to parse.\n\nJOURNEY LEAD-INS\n\n Every Journey line is either a bold lead-in (`**...**`) or a blockquote/bullet attached to\n the preceding lead-in. Blank lines between a lead-in, its description, and its bullets are\n fine — the parser skips them.\n\n **Navigate to** /path/here\n **Action — Fill out the signup form**\n **Assert** the confirmation toast is visible\n **Wait** 30s (also accepts 5m, 2h)\n **End** (add \"fail\" anywhere in the line for a failing End)\n **Seed** seed-workflow-name\n **Setup** setup-workflow-name (deprecated — still parses; author **Seed** instead)\n **Switch role to** admin (or **Switch role to admin** — both forms work)\n **Sandbox action — provision-org**\n **Api sequence — Create via API**\n **Visual checkpoint — Invoice list after seeding**\n **If** $var.status is \"blocked\"\n **Then:**\n <nested nodes, indented 2 spaces>\n **Else:**\n <nested nodes, indented 2 spaces>\n\n CRITICAL: for `Action`, `Sandbox action`, and `Api sequence`, the title goes AFTER an em-dash\n (`—`) or hyphen INSIDE the bold span: `**Action — Title**`. Writing `**Action** Title` (title\n outside the bold) used to silently lose the title; it is now tolerated as a fallback, but the\n em-dash-inside-bold form is canonical — use it. Do not invent a form for a lead-in not listed\n above (e.g. there is no `**Click**` or `**Type**` lead-in) — express it as an Action instead.\n\nACTOR FORMS (frontmatter `actor:` and `**Switch role to** <ref>` take the same forms)\n\n actor: Admin persona named \"Admin\" (default form)\n actor: persona Admin same, explicit\n actor: credential admin-bob one specific stored credential by name\n actor: seed-output new_user the credential output `new_user` of a **Seed** node\n earlier in the Journey (credentialSource: from_seed)\n\n `template <name>` is a legacy alias for `persona <name>`. `seed-output` binds to the\n nearest **Seed** node that precedes the login, so the Seed must come first in the\n Journey (for `actor:`, as the leading node); compile fails if no Seed precedes it.\n\nDESCRIPTION (optional, any lead-in)\n\n A blockquote line immediately after the lead-in (or after a blank line) becomes the node's\n description — free prose is fine and expected here:\n\n **Action — Create the org**\n > Fill the org form with orgName and plan, then submit.\n - field name: $orgName\n\nACTION BULLET GRAMMAR (exact — only these forms parse; everything else is DROPPED)\n\n - field <name> [(type)]: <value> e.g. - field plan (select): $plan\n - capture: <name> e.g. - capture: createdOrgId\n - assert (warn|fail|fatal[, agentic]): <condition>\n e.g. - assert (fail): URL ends with `/dashboard`\n e.g. - assert (warn, agentic): chart looks right\n - alwaysUseAgent: true\n - captureAudio: true\n - captureLabel: <label>\n - captureExtraMs: <number>\n\n A standalone `**Assert**` node takes its own kv option bullet the same way:\n\n - severity: warn|fail|fatal (assert nodes only; NOT `- severity: warn — text`,\n which is an unparseable kv bullet, not an assert)\n\n `Seed`/`Setup` bullets: `- version: latest`, `- mode: ...`, `- onFailure: block|warn`,\n `- input.<name>: <value>`. `Sandbox action` bullets: `- label: ...`, `- outputs: a, b`,\n `- param.<name>: <value>`. `Visual checkpoint` bullets: `- target: <plain-English element>`,\n `- expected: <visible expected state>`, and `- severity: record|fail`.\n\nCOMPLETE MINIMAL EXAMPLE\n\n ---\n name: Login smoke\n actor: admin\n authenticated: true\n requirementRef: LIN-101\n ---\n\n ## Spirit\n > A returning admin can sign in and reach the dashboard.\n\n ## Inputs\n - adminEmail: $EMAIL()\n\n ## Journey\n\n **Navigate to** `/login`.\n\n **Action — Sign in**\n > Enter email and password, submit.\n - field email: $adminEmail\n - field password: $CREDENTIAL\n - assert (fail): URL ends with `/dashboard`\n\n **End**.\n\nCOMMON MISTAKES (each of these compiles into an empty or half-empty node — no parse error)\n\n - A free-text bullet (\"- Should reach the dashboard eventually\") is not `field`/`capture`/\n `assert (...)`/a known kv key — it is DROPPED. Put prose in the `>` description instead of\n inventing a bullet shape.\n - `- severity: warn — should show a toast` is a kv bullet with key `severity`; it is not a\n recognized action option, so it is DROPPED. Use `- assert (warn): should show a toast`.\n - `**Action** Do the thing` (title outside the bold) is tolerated but non-canonical — prefer\n `**Action — Do the thing**`.\n - Any Journey line that doesn't start with a recognized bold lead-in is DROPPED with only a\n warn-severity \"Unexpected line in Journey\" issue — it will not error your compile.\n - After authoring or editing a spec, always run `spec_validate` and inspect its\n `droppedContent` field. Non-empty `droppedContent` means real content is about to be lost —\n treat it as a blocking error, not a warning, even though its underlying severity is `warn`.\n","WHAT A STRONG ACTION NODE LOOKS LIKE\n\n Action nodes are the workhorse of a flow — and they are also the unit the\n cache stores and replays. Sizing them well is what makes a flow both fast\n (cacheable sooner) and durable (resistant to benign UI churn). Five things\n separate a strong action node from a weak one.\n\n 1. IT READS AS ONE COHERENT STEP\n\n A good node has a title you could read aloud as a single instruction to a\n teammate: \"Create a ticket\", \"Fill out the subscription form\", \"Click Start\n to open the run-config modal\". The title names a goal — and, where it helps,\n the purpose of the step — not raw mechanics.\n\n A node is usually broader than a single click, but not always: a lone action\n that genuinely stands on its own in the flow is a fine node (\"Click Start to\n open the modal\"). The extremes to avoid are a purely mechanical title with no\n intent (\"Click the button\") and a node stuffed with several unrelated\n outcomes (\"Create a ticket, assign it, comment, and upload\"). When in doubt,\n err toward clearer, more discrete steps over one overloaded node.\n\n 2. IT HAS ROUGHLY 3–8 PLAYBOOK STEPS\n\n Each playbook step is one atomic intent executed in one tool call, bounded\n by stable page states. Fuse actions coupled through ephemeral UI state — an\n opener and a target that exists only while its menu is open — into that\n call. Split unrelated intents and every stable intermediate. A healthy node\n lands around 3–8 steps:\n\n click → fill_form → click (good — open, fill, submit)\n click → click → fill_form → click (good)\n 27 clicks (bad — that's several outcomes)\n\n \"Meaningful\" is the operative word. Incidental events collapse into the\n nearest step (a focus-click before a fill is part of the fill), and a whole\n form-fill is ONE fill_form step, not one step per field. If a single outcome\n would need more than ~8 steps, that's the signal to split it into sequential\n action nodes (\"Fill customer details\" → \"Fill billing details\" → \"Review &\n submit\") rather than grow one megastep.\n\n This ~3–8 is the STEP count inside one action node — not a cap on how many\n NODES a flow has. A flow is as long as its coherent journey needs (see Best\n Practices on flow scope).\n\n Interaction recipes are property-scoped, reusable interaction mechanics.\n A recipe invocation appears as one `call` step for its whole transaction,\n not as separate steps for the browser actions inside it.\n\n 3. IT HAS A CLEAR ASSERTION BOUNDARY\n\n A strong node ends at a checkpoint you can assert on: a modal disappeared,\n the URL changed, a row appeared, a toast fired. Put that check inline on the\n node (see the Assertions section) so the node's success is observable and the\n run gets a real progress marker at each step. State the behavior promised\n by the requirement, not DOM attributes, SVG details, or an arbitrary\n measurement threshold discovered during exploration. Keep observation\n mechanics in executable code and chosen interaction inputs in the action.\n\n Inline assertions verify the END STATE after the action. They can be relative\n or temporal (\"the row count dropped by 2\"), but only if the baseline was\n captured upstream — write `current row count = $var.captured_row_count - 2`,\n never \"the count dropped by 2\". The reason: an action may replay from cache\n while its assertion is judged live by the agent, which does NOT have the\n action's execution context. A self-contained assertion (absolute values, or\n values bound to captured variables) survives that split; one that silently\n assumes \"before\" state does not.\n\n 4. IT IS NOT CONDITIONAL\n\n Avoid baking branching into an action node — \"if the location isn't New York,\n set it to New York\", \"if patient X isn't in the table, create patient X\". A\n conditional in a node usually means the data wasn't staged properly, and it\n caches poorly (the cached path and the live path diverge).\n\n Prefer, in order:\n - Seed the precondition so the branch never exists (\"patient X always\n present\" → seed patient X). See Seed Workflows.\n - If the action is idempotent — the same sequence reaches the desired state\n regardless of where it started (re-selecting \"New York\" works whether or\n not it was already set) — just run the sequence unconditionally. No branch\n needed.\n - If the branch is genuine, use a formal CONDITION node (deterministic when\n the check is a $var / identity comparison; agentic otherwise), which keeps\n the branch explicit and cacheable per path.\n\n If a conditional truly must live inside a node, set `alwaysUseAgent: true` on\n it so the branch is reasoned about live every run and never mis-cached.\n\n 5. ITS PROSE IS SHORT\n\n The description is what a tester would say out loud — two to four plain\n sentences: what to click, what should happen, what state to leave behind.\n Playbook targets name controls by their visible text (\"'Create copy' menu\n item\", \"QA Policy row checkbox\"). Exact strings belong in the\n assertions only when they are required by the spec, not merely locator\n details. The readable condition must remain about the product behavior.\n\n Good: \"Search for QA Carrier, tick the QA Policy A and\n QA Policy B row checkboxes, and click the 'Create policies'\n toolbar icon. Review the preview, then click 'Cancel'. Leave both\n rows selected.\"\n Bad: a paragraph that restates hover/retry mechanics, quotes request\n URLs and response bodies, or narrates a bug with its ticket id\n and repro steps.\n\n Do not restate the same mechanics in every node (\"hover the row so its\n controls appear — they render only while hovered — then click …\"); say it\n once in a short phrase or leave it to the agent. Known failures go in a\n warn-severity assertion that cites the ticket id in one clause, with the\n ticket attached to the flow (status event / comment), never as an essay\n inside the node. If a description needs more than four sentences, the node\n is doing more than one thing — split it (point 1).\n\n WHY THIS MATTERS\n\n The node is the atomic cache unit. The smaller and more reliable each node is,\n the sooner the flow caches and the faster it replays. But because the node is\n also the unit of specificity, the more a node pins to incidental detail (exact\n button text, a precise field order), the more a benign change breaks it.\n Nailing the altitude — coherent goal, ~3–8 meaningful steps, a clean assertion\n boundary, no hidden branches, short prose — is what buys both speed and\n reliability at once.\n","A playbook is a sequence of human-readable steps that describe the actions\ntaken during a workflow node's execution. Playbooks bridge the gap between\nhigh-level node descriptions (\"Create a ticket\") and the low-level browser\ninteractions that fulfill them.\n\nWHAT A PLAYBOOK CONTAINS\n\n Each playbook is an ordered list of PlaybookSteps:\n\n order Step sequence number\n action What to do: click, fill, fill_form, select, navigate,\n wait, scroll, hover, upload, verify, handle_native_dialog,\n toggle, press_key, focus, drag, resize, capture,\n extract_table, python_execute, verify_download,\n verify_download_content, screenshot, agent_loop, call\n target The element or area being acted on\n params Key-value parameters for the action\n note Human-readable description of the step\n\n Each step is one atomic intent executed in one tool call, bounded by stable\n page states. Fuse actions coupled through ephemeral UI state — opening a\n transient menu and choosing its item, for example — into that call. Split\n unrelated intents and every stable intermediate into separate steps.\n\n Example playbook for \"Create a ticket\":\n 1. click \"New Ticket\" button\n 2. fill_form Title: \"QA Test — Billing Bug\", Priority: \"High\"\n 3. click \"Submit\" button\n 4. verify Success toast appears\n\nHOW PLAYBOOKS ENABLE CACHE REPLAY\n\n When a workflow runs for the first time, the AI agent explores the\n application, performs actions, and generates a playbook for each node.\n The raw browser actions (clicks, keystrokes, waits) are cached alongside\n the playbook steps.\n\n On subsequent runs, the system uses playbook-step-driven replay:\n\n 1. Load the playbook steps from the node config\n 2. For each step, look up the cached browser actions\n 3. Replay the cached actions directly (no AI agent needed)\n 4. If a step's cache misses or fails, the AI agent heals that step\n\n This means most runs execute instantly via cache, with the agent only\n invoked for steps that have changed or broken.\n\nCOMPILED ENTRIES\n\n The cache maps playbook steps to cached action indices:\n\n cached Playbook step has matching cached actions — replayed directly\n gap No cache for this step — agent performs it fresh\n\n A fully cached node replays in seconds. A node with gaps falls back to\n agent execution only for the missing steps.\n\nVERIFY STEPS & ASSERTIONS\n\n A `verify` (or `verify_download`/`verify_download_content`) step names the\n inline assertion it proves via `assertionId` — the assertion's UUID from\n the node's inlineAssertions, or `'completion'` for the step that closes\n out the node's job-to-be-done. The step sits at the position in the flow\n where the check actually happened, not appended at the end.\n\n A verify step whose assertionId matches a recorded assertion compiles into\n the cache at that position, alongside the other steps. An assertion the\n agent didn't place in the flow gets a synthesized trailing verify step\n instead.\n\n Agentic assertions (agent-evaluated, not mechanically checkable) never get\n a verify step — they can't compile and are judged live during replay.\n\n See assertions.txt for how inline assertions are authored, severities, and\n when to use agentic evaluation.\n\nINTERACTION RECIPES\n\n Interaction recipes are property-scoped, reusable interaction mechanics.\n Calling one executes its transaction atomically and appears in the playbook\n as one `call` step, with a human-readable target and the recipe arguments.\n\nPLAYBOOK HEALTH\n\n Each cached node tracks playbook health:\n\n verified Cache is working correctly across recent runs\n degraded Some steps have failures — cache still used but monitored\n stale Cache is no longer reliable — full agent re-execution needed\n\n Step-level failure counts track which specific steps break most often,\n guiding targeted cache healing.\n\nWHY PLAYBOOKS MATTER FOR AUTHORING\n\n When you build a workflow, the quality of your node descriptions directly\n affects playbook quality. Clear, intent-focused descriptions produce\n better playbooks, which produce more reliable cache replay.\n\n Good: \"Create a ticket with title 'QA Test' and priority 'High'\"\n → Clean playbook: fill_form with clear fields, click submit\n\n Bad: \"Do the thing on the page\"\n → Vague playbook: agent guesses at actions, cache breaks easily\n\n The playbook is the semantic contract between your intent and the\n execution engine. Write nodes that describe what a human would do,\n and the playbook will faithfully capture and replay it.\n","EXPLORE BEFORE AUTHORING\n\n Read the intended journey and relevant product-map capability. Use a\n cofactor session with the intended credential and application environment\n to explore the real UI before choosing targets. Confirm the signed-in user\n and role during this preflight, not as an extra runtime requirement unless\n authentication or identity is what the test covers.\n\n Discover named data candidates yourself, then confirm with the user which\n existing fixtures are reliable for repeated tests. Ask about genuinely\n ambiguous behavior or data stability, not labels or URLs you can discover.\n If shared data is unsuitable, agree on test-owned setup.\n\nSCOPE: ONE COHERENT USER JOURNEY\n\n A workflow should test one job-to-be-done, not multiple unrelated tasks.\n Many steps are fine if they're all part of the same flow (an action and\n everything it is meant to cause). Stop when the goal is accomplished.\n\n Good — multi-role journey:\n Login as Customer → Place an order →\n Login as Sales Rep → Verify the order appears in the queue\n\n Good — single-entity journey:\n Login → Navigate to projects → Create project → Edit name →\n Assert name updated → Cleanup: delete project\n\n Good — read-only flow:\n Login → Navigate to dashboard → Assert widgets visible\n\n Bad — multiple unrelated journeys:\n Dashboard → Create item → Manage users → Generate report\n (These are separate jobs — create separate workflows)\n\n Rule: \"Is this step dependent on or naturally connected to the previous\n steps?\" If no, you're starting a new journey — stop.\n\n A coherent flow can be long or short — there is no target node count. If a\n flow grows very long, ask whether it is really several INDEPENDENT journeys:\n splitting them into separate tests lets them run in parallel and fail\n independently. Keep a single coherent journey together — don't split mid-flow.\n\nTEST THE SEAMS: FOLLOW THE ACTION TO ITS EFFECT\n\n CRUD rarely breaks on its own. The seams between features break: the place\n where one action is supposed to cause something somewhere else. Creating a\n ticket is not the point. The point is what the ticket does: notify the\n assignee, land in Support's queue, bump a count on the dashboard, sync to\n an integration.\n\n Before writing a flow, ask: \"When this action succeeds, what is supposed to\n happen next, and where would a user see it?\" When there's an answer, the\n stronger journey follows the action to that effect:\n\n Weaker — stops at the write:\n Login → Create ticket assigned to Support → Assert ticket in my list\n\n Stronger — crosses the seam:\n Login as Customer → Create ticket assigned to Support →\n Login as Support → Confirm the assignment email in Support's inbox →\n Verify the ticket is in the Support queue\n\n Common seams to look for:\n - Another screen or view (a list, dashboard, report, activity feed)\n - Another role or user (a queue, an approval, a shared record)\n - A message (email, in-app notification; for email, see EXTERNAL\n DEPENDENCIES in cofactor workflow guide data-lifecycle)\n - A downstream state change (status, count, permission)\n\n Create → edit → delete is mostly data management: the test makes what it\n needs and cleans it up (see MAKE EACH TEST SELF-SUFFICIENT). It is a fine\n flow for a page whose writes have no effect elsewhere. But when the action\n is meant to trigger something, the effect is what's worth proving.\n\n This is a preference, not a requirement. Some seams can't be observed from\n the test (a third-party system with no readable surface, a side effect with\n no UI). Assert what you can see and move on. When authoring from a\n recording, apply this only within what was captured — don't add steps\n the recording never performed.\n\nWRITE STEPS AS HUMAN INTENT\n\n A workflow should read like instructions you'd explain to a teammate:\n - \"Create a ticket assigned to Support.\"\n - \"Submit the ticket and confirm it appears in the list.\"\n - \"Change the ticket status to Closed.\"\n\n Capture the \"why\" and the \"what\" — not UI mechanics.\n\nCHOOSE THE RIGHT GRANULARITY\n\n Too granular:\n - \"Click New\"\n - \"Type title\"\n - \"Type description\"\n - \"Click Save\"\n\n Too stuffed:\n - \"Create a ticket, assign it, comment, upload, and verify in three views\"\n\n Good:\n - \"Create a ticket with required fields\"\n - \"Assign the ticket to Support\"\n - \"Verify the ticket appears in the queue\"\n\n Sizing rule: a node is a single coherent goal of roughly 3–8 playbook steps\n (one meaningful action each — a whole form-fill is ONE fill_form step). The\n \"too granular\" list above is about splitting one goal into a node per keystroke\n or writing mechanics-only titles — NOT a ban on single-action nodes: a lone\n action that stands on its own (\"Click Start to open the modal\") is fine. This\n ~3–8 is per action node (its playbook STEPS); it is NOT a cap on how many NODES\n a flow has — flow length follows the journey (see SCOPE above). See the Action\n Nodes section.\n\n If an action crosses multiple screens or changes multiple entities, split it.\n If it's a single user goal on a single screen, keep it as one action.\n\nMAKE EACH TEST SELF-SUFFICIENT\n\n A strong test is idempotent, controls its own data, and is isolated. The\n full rules and their sanctioned workarounds are the \"STRONG TESTS\" block of\n the Test Data Lifecycle guide (cofactor workflow guide data-lifecycle).\n In short:\n\n - Create the data the test operates on, inline, with macros ($EMAIL(),\n $UUID(), etc.) so reruns don't collide\n - Use a seed workflow only for data that several tests share\n - Pre-existing data the test only READS is fine — declare it in\n ## Preflight (the workflow's preflight field, not its description)\n and never mutate it\n - Tests that must run in order go in suite layers, never rely on\n implicit ordering\n\n This keeps runs deterministic and prevents cascading failures.\n\nVERIFY THE SPECIFIED BEHAVIOR\n\n Verify each meaningful product claim, without adding implementation-only\n checks. Assertions express the required outcome; replay code supplies DOM\n evidence and measurements. Chosen scroll distances and viewport sizes are\n action/setup inputs, not acceptance thresholds unless the spec says so.\n Do not assert ARIA values, SVG paths, or a signed-in user merely because\n exploration exposed them.\n\n Before recording a step, verify its expected outcome:\n\n - Form submissions: confirm acceptance (success message, redirect, new item in list)\n - Data creation: navigate to where the record should appear and confirm\n - Data modification: reload and confirm the change persisted\n - Deletions: confirm the item is gone (a toast alone is not enough)\n - Side effects: where an action is meant to cause something elsewhere,\n check it there when you can (see TEST THE SEAMS)\n - Navigation: confirm the expected page loaded\n\n If verification fails, debug the issue — don't record and move on.\n\nKEEP DESCRIPTIONS CLEAR\n\n Node titles should be short and action-oriented:\n Good: \"Create a support ticket\"\n Bad: \"Step 3 - ticket creation process\"\n\n Node descriptions should add detail the title can't carry:\n Good: \"Fill the form with a QA Test subject and High priority, then submit\"\n Bad: \"Do the thing\"\n\n The workflow description gives the spirit of the whole test in one or two\n plain sentences: what it does and why it matters. Capability codes,\n preconditions, issue ids, status and step narration do not belong there:\n preconditions go in ## Preflight, and the rest lives with the product-map\n link, the linked issue, the run history and the nodes.\n\n People read description, preflight and cleanup, so write preflight and\n cleanup as short markdown bullet lists and never put a raw ID in any of\n them (no UUID or UUID prefix, no wf_/prule_ or other prefixed id, no issue\n or run id). Name the seed workflow, teardown, connection or record instead.\n\nNODE ORDERING\n\n The start-of-workflow order is a strict hierarchy (see \"STARTING NODE\"\n in the Node Types guide):\n\n Seed (if needed) → Login → Navigate → ...\n\n The first node is the ACTOR, not a navigate: an authenticated flow opens\n with a `login` node (or a `seed`, if it needs data first) — never with a\n navigate node. A navigate jumps to the test's entry point AFTER login.\n Only unauthenticated flows (signup, password reset, public pages, or a\n login test) may start with a navigate.\n\n Seed nodes should come first. Seeds run in their own isolated context\n (usually via API sequence) and export variables the rest of the flow\n consumes. Putting a login before the seed wastes a browser segment,\n and any login/navigate that references $var.{seed_output} must come\n after the seed that produced it.\n\n Only skip the seed-first rule if the seed itself genuinely depends on\n a browser session created earlier in the same workflow (rare — in\n that case, prefer a separate browser-based seed workflow and reference\n it here).\n\nLOGIN BEST PRACTICES\n\n - Most workflows start with a login node. Workflows can also start\n with a seed node or API sequence when no browser session is needed yet.\n - Login SUBSUMES logging in. A login node already provisions an\n authenticated session — it IS the act of logging in. Never follow a\n login node with \"navigate to /login\" / \"enter email + password\" /\n \"click Sign in\" steps. Start with the login node and go straight to\n the first real action. (Only exception: a flow whose purpose is to\n test login — start logged out and make the login steps the journey.)\n - Login nodes require a credentialId (UUID), not just a credentialName.\n Without a credentialId the Flow Designer flags the node as invalid.\n Find credential IDs with: cofactor credential list [--env prod|dev]\n - Use multiple login nodes for multi-role testing — each login starts\n a new segment with a fresh session as that user\n - Don't test login itself (unless that's the explicit goal)\n - A navigate node after login is a great way to jump directly to the\n test's entry point\n\nPREFER INLINE ASSERTIONS\n\n Attach assertions to action nodes using inlineAssertions rather than\n adding standalone assertion nodes. Inline assertions keep the test\n focused and produce clearer failure reports. See the Assertions section\n for details.","Macros generate fresh, unique data every time a workflow runs. Variables let\nyou reference shared values across nodes. Both use the $ prefix.\n\nAVAILABLE MACROS\n\n $EMAIL() Unique test email test-a1b2@example-test.com\n $FIRST_NAME() Random first name Jordan\n $LAST_NAME() Random last name Chen\n $PHONE() Random US phone +1-555-382-7491\n $UUID() Random UUID v4 a1b2c3d4-e5f6-...\n $NOW() ISO 8601 timestamp 2026-02-19T14:30:00.000Z\n $NOW(+5m) Shifted ISO timestamp $NOW(-2h), $NOW(30s), $NOW(1d)\n $NOW(+5m, \"fmt\") Shifted time, UTC fmt $NOW(+5m, \"m H * * *\") = 35 14 * * *\n $TODAY() Current date 2026-02-19\n $DATE(N) Date offset by N days $DATE(7) = next week\n $TIMESTAMP() Unix timestamp (ms) 1771520400000\n $RANDOM_INT(min,max) Random integer $RANDOM_INT(1,100) = 42\n $RANDOM_STRING(len) Random alphanumeric $RANDOM_STRING(6) = xK9mQ4\n $SEQUENCE(name) Auto-incrementing $SEQUENCE(order) = 1, 2, 3...\n\n$NOW FORMATS\n\n The optional second argument renders the time in UTC. Tokens: YYYY MM DD\n HH mm ss (zero-padded) and H m (unpadded hour and minute); everything else\n is literal, except that a bare H or m is always a token (there is no escape). Use $NOW(, \"fmt\") to format the current time with no shift.\n A format cannot contain commas or parentheses. Quote it with single or\n double quotes (or not at all); inside a JSON string such as an API\n sequence bodyTemplate use single quotes.\n\n $NOW(, \"YYYY-MM-DD HH:mm\") 2026-02-19 14:30\n $NOW(+5m, \"m H * * *\") daily cron that first fires in ~5 minutes\n\nSYNTAX\n\n Macros follow the format $MACRO_NAME() or $MACRO_NAME(args).\n They can appear standalone or inline within a larger string:\n\n Standalone: $EMAIL()\n Inline: user-$UUID()@corp.com\n Escaped: \\$EMAIL() produces the literal text $EMAIL()\n\n Each run resolves macros independently — every execution gets fresh values.\n\nVARIABLES\n\n Variables reference values set during a workflow run. When an action has\n input fields or extracts data, those become $var.{name} references.\n\n Sources:\n Input A value entered in an action's field $var.company\n Macro A macro expression in a field $var.email\n Extracted Data extracted from the page $var.order_id\n Credential Values from the login credential $var.username\n\n Use $var.{name} in subsequent step formFields and descriptions.\n Don't re-hardcode values — reference the variable from the earlier step.\n\nHOW VARIABLES GET BOUND\n\n Two distinct paths create $var.{name} bindings. Picking the wrong one is a\n common foot-gun.\n\n 1. Typed input (auto-promote)\n\n Add an entry to inputValues on an action node:\n\n inputValues: { company: \"$RANDOM_STRING(8)\" }\n\n The key \"company\" auto-promotes to $var.company for every downstream\n node. Do NOT also list it in declaredOutputs — the input itself IS the\n binding.\n\n 2. DOM capture (declaredOutputs + playbook capture)\n\n For values that only exist after the page renders (URL fragment, badge\n text, generated ID in the breadcrumb), declare them upfront and capture\n them inside the playbook:\n\n declaredOutputs: [\"order_id\"]\n playbookSteps: [\n { order: N, action: \"capture\", target: \"<selector or rule>\",\n outputKey: \"order_id\" }\n ]\n\n The capture step writes into $var.order_id at runtime. Without\n declaredOutputs the downstream resolver won't recognize the binding.\n\n Rule of thumb: if you can type the value into a field before the run, it's\n an input. If the value only exists after something happens in the browser,\n it's a captured output.\n\nSEED VARIABLES\n\n When seed workflows are configured, their outputs are available as\n $var.{dataKey} references. If a seed provides data you need (a project ID,\n a user record), use the seed variable — don't create that data again.\n\nCOMMON PATTERNS\n\n Unique user registration:\n Email: $EMAIL()\n Name: $FIRST_NAME() $LAST_NAME()\n\n Numbered items:\n $SEQUENCE(\"orders\") → 1, 2, 3... (resets each run, independent per name)\n\n Date-relative testing:\n $DATE(30) for 30 days out, $DATE(-7) for last week, $TODAY() for now\n\n Unique identifiers:\n $UUID() for globally unique, $RANDOM_STRING(8) for shorter strings\n Combine with text: order-$RANDOM_STRING(6)\n\nBEST PRACTICES\n\n - Use $EMAIL() instead of hardcoded addresses for uniqueness\n - Use $SEQUENCE(\"name\") when you need predictable ordering within a run\n - Prefer $DATE(days) over fixed dates so tests stay valid over time\n - Always include a value for every formField — don't leave fields empty","Seed workflows provision test data that several tests share. A seed\nworkflow creates data and exports named variables that downstream\nworkflows can reference. Data unique to one test is created inline in\nthat test, not seeded (see the Test Data Lifecycle section).\n\nWHY USE SEEDS\n\n - Reusable — the qualifying condition: one seed serves many test workflows\n - Fast: seeds can use API sequences instead of slow browser interactions\n - Clean: paired teardown workflows handle cleanup automatically, on\n pass and fail\n - Isolated: each run gets its own fresh data via macros\n\nHOW SEEDS WORK\n\n 1. Create a workflow with flowType \"seed\"\n 2. Define seedOutputs — the named values the seed exports\n (e.g., project_id, user_email, order_number)\n 3. The seed creates data and captures those values during execution\n 4. Downstream workflows add a Seed node that references this seed\n 5. The seed's outputs are available as $var.{dataKey} in the test\n\n Example:\n Seed \"Create Test Project\" exports: project_id, project_name\n Test workflow references the seed, then uses:\n Navigate to $var.project_id\n Assert page title contains $var.project_name\n\nCREATING SEEDS\n\n A seed workflow shell needs a name, declared outputs, and usually a paired\n teardown. Outputs are the contract downstream workflows depend on; define\n them before building the seed body so every node captures the right values.\n\n Simple data outputs need:\n - dataKey: stable variable name, used as $var.{dataKey}\n - name: human label\n - description: optional context for builders and reviewers\n\n Credential outputs additionally define credentialOutput — the field\n mapping (\"$generate.email\" for a minted address), inbox behavior, and\n loginUrl. The full recipe for a seeded user, from declaration to the\n consumer's from_seed login and teardown, is the Seeding a Test User\n section (`cofactor workflow guide seed-users`).\n\n After creating the shell, add nodes through the Flow Designer, workflow sync,\n or API, then publish once the seed and paired teardown both pass.\n\n CLI users: see `cofactor workflow guide cli-seeds` for command usage.\n\nBUILDING A SEED: START WITH THE BROWSER\n\n The easiest way to build a seed is to start with browser-based steps:\n\n 1. Create a seed workflow (flowType: seed)\n 2. Add a login node with credentials that have permission to create data\n 3. Add action nodes that create the data through the UI\n - Use macros for all names and identifiers ($EMAIL(), $RANDOM_STRING(6), etc.)\n 4. Add declaredOutputs on action nodes to capture generated values\n (IDs, URLs, confirmation numbers)\n 5. Define seedOutputs on the workflow to export those captured values\n 6. Test and publish the seed\n\n This approach lets you discover exactly what steps and data are needed\n by interacting with the real application.\n\nCONVERTING TO API SEQUENCES\n\n Once a browser-based seed works reliably, convert it to an API sequence\n for speed and reliability. Cofactor can do this automatically.\n\n Auto-conversion from a workflow run:\n 1. Open the seed workflow in the Flow Designer\n 2. Add an api_sequence node\n 3. In the node config, choose \"Generate from workflow run\"\n 4. Select a completed run of the browser-based seed\n 5. The AI agent analyzes the network requests captured during\n that run and generates an equivalent API sequence automatically\n 6. The agent tests each step against the live API to verify it works\n 7. Review the generated sequence and publish\n\n The AI agent has access to your application's API catalog and can:\n - Search for endpoints by keyword\n - Inspect request/response schemas\n - Test individual API calls to verify they work\n - Compose a multi-step sequence with variable passing between steps\n - Validate the full sequence end-to-end before finalizing\n\n You can also generate an API sequence from a prompt — describe what\n data to create and the agent will find the right endpoints and build\n the sequence.\n\n API sequences support two kinds of dynamic values:\n - Step references: {{stepId.response.path.to.value}} to pass data\n between steps (e.g., use the project ID from step 1 in step 2)\n - Macros: $EMAIL(), $UUID(), $RANDOM_STRING(6), etc. for fresh\n unique data each run\n\n Exports map response fields to seed output variables:\n - stepId: which step to extract from\n - responsePath: dot notation path (e.g., \"data.id\")\n - variableName: the $var.{name} downstream workflows will use\n\nEXECUTION MODES\n\n Seeds automatically choose the best execution mode:\n\n browser Runs through the browser like a normal workflow\n api Runs the API sequence directly — no browser needed\n recommended Uses the API sequence if one exists, otherwise browser\n\n Once you've added an API sequence to a seed, it will automatically\n run via API — faster, cheaper, and more reliable than browser execution.\n\n Not all seeds can be converted — some data creation flows require\n browser interaction (file uploads, complex wizards, third-party\n integrations). Keep those as browser-based seeds.\n\nAPI CALL TIMEOUT\n\n When a seed runs in API mode (executionMode \"api\", or \"recommended\"\n resolving to API), each HTTP call uses a 2-minute (120s) timeout by\n default. Seeds/teardowns that hit slow provisioning endpoints can raise\n this per seed node via apiTimeoutSeconds — it applies to both the seed\n and its paired teardown. Ignored for browser-mode seeds.\n\n Set it three equivalent ways:\n - Flow Designer: the \"API call timeout (seconds)\" field on the Seed node\n - .cofactor.md: a \"- apiTimeoutSeconds: 300\" bullet under the Seed node\n - workflow JSON (create / sync): on the seed node's configJson, e.g.\n { \"nodeType\": \"seed\",\n \"configJson\": { \"seedExecutionMode\": \"api\", \"apiTimeoutSeconds\": 300 } }\n\n Leave it unset to keep the 120s default; an invalid value falls back to\n the default rather than erroring.\n\nTEARDOWN WORKFLOWS\n\n Every seed can have a paired teardown workflow that cleans up the\n data it created. Teardowns run automatically after the seed's\n downstream workflows complete — whether they passed or failed.\n\n - Set flowType to \"teardown\" and link it to the seed\n - The teardown receives the same $var.{dataKey} variables the seed exported\n - Use those variables to find and delete the created data\n\n Teardowns are the cleanest way to handle cleanup — they keep cleanup\n logic separate from test logic and run automatically.\n\nSANDBOX-ACTION-BACKED SEEDS\n\n When the property has a verified sandbox template with actions, a seed\n workflow can provision data by running a SANDBOX ACTION node instead of\n driving the UI or composing API calls. The seed's body is a single\n sandbox_action node (plus End); the action's outputs register as\n $var.{key} and satisfy the seed's declared outputs directly.\n\n - Fastest seed form: runs entirely server-side, no browser session\n - Discover actions with list_sandbox_actions; outputs come from the\n action's outputSchema\n - Constraint: consuming workflows become sandbox-only — on a\n non-sandbox environment the action node skips with a warning and\n produces no variables\n - Teardown is usually unnecessary: sandbox environments are destroyed\n after the suite, taking provisioned data with them\n\nSEED BEST PRACTICES\n\n - Use macros in all created data ($EMAIL(), $RANDOM_STRING(6), etc.)\n so each run gets unique, non-conflicting data\n - Keep seeds focused — one seed per logical dataset\n (e.g., \"Create Project with Members\" not \"Create Everything\")\n - Export only what downstream workflows need — don't over-export\n - Start with browser-based seeds, then use auto-conversion to generate\n an API sequence from a completed run\n - For sandbox-backed properties, prefer a sandbox-action-backed seed\n (see above) — server-side, fast, and reliable\n - Pair seeds with teardown workflows for automatic cleanup\n - To share seed data across several workflows in one test suite,\n reference the same seed from each; order dependent workflows with\n suite layers (setup nodes are deprecated)\n","A seeded user is a brand-new account minted for one run, created in the\napplication by a seed workflow, and handed to the tests that consume that\nseed as a login credential plus $var values. This section is the recipe for\nconfiguring one. The general seed model (outputs, execution modes,\nteardowns) is in the Seed Workflows section; this only covers the user case.\n\nWHEN TO SEED A USER (AND WHEN NOT TO)\n\n Use a persona (actor: Admin) when the test only needs SOME logged-in\n account of a role. Personas resolve per environment, need no seed, and are\n the default for every authenticated test.\n\n Seed a user when the test needs a NEW account it owns:\n - signup, invite acceptance, onboarding, first-login flows\n - anything that mutates or deletes the account itself (profile, MFA\n enrolment, password change, leave org, delete account)\n - a fresh inbox: verification codes, invite links, magic links\n - a user with no history, so counts/empty states are deterministic\n\n The seed-only-when-reused rule still applies: one seed serves every test\n that needs \"a fresh user\", so this is exactly the case a seed is for. Do\n not create a per-test copy — reference the same seed from each test.\n\n On sandbox environments the account can come from a sandbox action bound\n to a persona instead (see SANDBOX ALTERNATIVE at the end). This section\n covers the environment-agnostic seed-workflow path first.\n\nHOW IT WORKS (PLATFORM SIDE)\n\n A seed output with a credentialOutput block is a CREDENTIAL output. At the\n start of every run that references the seed, before the seed body runs,\n the platform:\n\n 1. Mints an email address from emailPrefix + the run's execution id:\n <emailPrefix>+<8 hex chars>@<test-user inbox domain>\n e.g. testuser+3fa92c1b@testuser.runcofactor.com\n 2. Resolves fieldMapping — \"$generate.email\" becomes that address,\n \"$generate.phone\" reserves an SMS number, any other value is a\n literal — and creates an ephemeral credential\n (\"[Ephemeral] <dataKey> (<first 8 chars of exec id>)\") on the\n credentialOutput's property, with the mapped fields as its login data.\n 3. Creates an inbox recipient for the address when\n createInboxRecipient is true, so the seed and its consumers can read\n mail sent to it.\n 4. Injects the mapped fields into the seed body as\n $var.<dataKey>.<field> e.g. $var.new_user.username\n $var.credential.<field> (alias; only unambiguous with one\n credential output)\n 5. Binds the credential to any downstream login node that references\n the seed output (credentialSource: from_seed), and deletes the\n credential after the suite finishes — or on seed failure — with a\n 24-hour age sweep as backstop.\n\n Minting the credential does NOT create the account in your application.\n That is the seed body's job (next section). A credential output with an\n empty seed body is a login that will fail.\n\nSTEP 1 — DECLARE THE CREDENTIAL OUTPUT\n\n Create the seed shell with the outputs declared up front; the\n credentialOutput block is only settable through JSON (CLI --from-file /\n --outputs-json, workflow patch --seed-outputs-file, or the Flow Designer\n output editor — .cofactor.md's ## Declared Outputs cannot author it, only\n preserve it on round-trip).\n\n {\n \"name\": \"Create invited user\",\n \"description\": \"Fresh org + admin invite for a seed-minted email\",\n \"outputs\": [\n {\n \"dataKey\": \"new_user\",\n \"name\": \"Invited User\",\n \"credentialOutput\": {\n \"propertyId\": \"<uuid of the application under test>\",\n \"loginUrl\": \"https://app.example.com/login\",\n \"emailPrefix\": \"qa-invite\",\n \"fieldMapping\": {\n \"username\": \"$generate.email\",\n \"password\": \"QaTest-Passw0rd!\"\n },\n \"createInboxRecipient\": true,\n \"loginInstructions\": \"Email/password form at /login.\"\n }\n },\n { \"dataKey\": \"invite_token\", \"name\": \"Invite token\" },\n { \"dataKey\": \"organization_id\", \"name\": \"Organization ID\" }\n ]\n }\n\n cofactor workflow seed create --from-file seed.json\n\n credentialOutput fields:\n propertyId REQUIRED. The application the credential belongs\n to; without it the output is skipped with a\n warning and downstream logins fail.\n fieldMapping REQUIRED. Credential field → value. Use\n \"$generate.email\" for the minted address (usually\n username, and email too if the login form wants\n both). Every other value is a literal stored\n verbatim — macros are NOT expanded here — so the\n password is exactly what you write; pick one your\n app's password policy accepts. Uniqueness comes\n from the email, not the password.\n emailPrefix Local-part prefix; defaults to \"testuser\". Use\n something that names the seed so inbox traffic is\n attributable.\n createInboxRecipient true whenever the flow must read a message sent to\n the user (verification code, invite link, magic\n link). Without it the address exists but nothing\n captures its mail.\n provisionPhoneNumber true (or a \"$generate.phone\" mapping) to reserve an\n SMS-capable number for OTP flows.\n loginUrl Where the login agent goes to sign in as this user.\n loginInstructions Extra guidance for the login agent (form location,\n SSO button to avoid, post-login landing).\n provisioningInstructions Only if the account needs a manual step before\n first login; marks the credential as not yet\n provisioned.\n\n Keep plain data outputs alongside the credential output for every id the\n consumers or the teardown will need (org id, user id, invite token). Declare\n ONLY what the seed body actually exports — a declared-but-unexported output\n shows up as \"missing\" on every run.\n\nSTEP 2 — MAKE THE SEED BODY CREATE THE ACCOUNT\n\n The body turns the minted email into a real account. Prefer an API\n sequence; fall back to browser nodes only when no API exists.\n\n Typical shapes:\n - Invite: admin/superadmin creates (or picks) an org → POST invite for\n $var.new_user.username → export the invite token. The consumer\n test then completes signup through the invite link.\n - Direct: POST /users or /signup with $var.new_user.username and\n $var.new_user.password → export the user id. The account is\n ready to log in.\n - Verify: if the app emails a verification code on signup, the seed can\n read it too (the inbox exists already) — but usually leave the\n verification step to the consumer test when that step IS what\n the test proves.\n\n Reference: the cofactor org's \"Create org & copy invite\" seed — an\n api_sequence of createOrg → switchOrg → createInvite (body\n {\"email\": \"$var.credential.username\", \"role\": \"admin\"}) exporting\n organization_id and invite_key, consumed by \"Create & Delete Org Property\".\n\n Rules for the api_sequence steps:\n - Authenticate as a persona (credentialTemplateId), never a hardcoded\n credentialId — the persona resolves per environment and is minted\n just-in-time on a fresh sandbox.\n - Target $var.ENV.api_url/..., never a baked host, so the same seed runs\n on dev, prod, and every sandbox.\n - Use $var.<dataKey>.username for the email. $var.credential.username\n also works but stops being unambiguous the moment a second credential\n output is added.\n - Export every id the teardown needs.\n\nSTEP 3 — CONSUME THE USER IN A TEST\n\n In the consuming workflow:\n\n 1. Add a Seed node referencing the seed (the seed's outputs become\n $var.<key> and $var.<Seed_Name>.<key>).\n 2. Point the login node at the seed's credential output:\n credentialSource: \"from_seed\"\n seedCredentialRef: { \"seedWorkflowId\": \"<seed uuid>\",\n \"dataKey\": \"new_user\" }\n performLogin: false when the test performs signup/first login\n itself (invite acceptance, onboarding)\n performLogin: true when the account is ready and the test starts\n logged in\n Both fields are required at run time, but you rarely write\n seedWorkflowId yourself: the Flow Designer's \"Acting as → from seed\"\n picker sets both, and the compile path (create-with-nodes, which\n .cofactor.md specs and raw JSON both go through) fills it from the\n nearest preceding Seed node when only dataKey is given. In a spec, put\n the **Seed** node first and write `actor: seed-output new_user` (or\n `**Switch role to** seed-output new_user` mid-journey).\n 3. Use the credential's fields in steps as $var.new_user.username and\n $var.new_user.password (signup forms, \"confirm password\", etc.), and\n the plain outputs as $var.invite_token etc.\n 4. Email steps: describe what to read — \"open the verification email\n sent to $var.new_user.username and follow the accept-invite link\".\n The agent has an inbox tool scoped to the credential's recipient. Do\n NOT hardcode a code value in the node's inputs; it is different every\n run.\n\n Several tests can reference the same seed; each run mints its own user, so\n they run in parallel without colliding. Order tests that must reuse ONE\n user across flows as suite layers instead.\n\nSTEP 4 — TEARDOWN\n\n Pair the seed with a teardown (created by default by `workflow seed\n create`). The teardown receives the same $var values and should delete the\n account through the API — the org if the seed created one, otherwise the\n user — using the exported ids. Same rules: persona auth, $var.ENV.api_url.\n The ephemeral credential and inbox recipient are removed by the platform;\n only your application's rows need the teardown.\n\n A seed that runs daily without a working teardown leaves one orphan user\n (or org) per run. Check once after publishing that the object is gone.\n\nCHECKLIST\n\n [ ] credentialOutput.propertyId set; fieldMapping has \"$generate.email\"\n [ ] createInboxRecipient: true if any step reads mail\n [ ] seed body creates the account and exports every id the teardown needs\n [ ] api_sequence steps use credentialTemplateId + $var.ENV.api_url\n [ ] declared outputs == exported outputs (no \"missing\" on the run)\n [ ] consumer login: from_seed with dataKey, and a Seed node before it\n (seedWorkflowId auto-fills from that Seed node at compile)\n [ ] no hardcoded verification codes in consumer inputs\n [ ] teardown deletes the app-side account/org; verified once by hand\n [ ] seed + teardown published (approved) before consumers are promoted\n\nSANDBOX ALTERNATIVE — ACTION-MINTED PERSONA\n\n On a sandbox template, a sandbox action with a credentialOutputConfig and\n a credentialTemplateId mints the account server-side and binds it to a\n PERSONA (e.g. provision-tenant → \"Admin\"). Tests then just say\n actor: Admin; the persona is provisioned just-in-time on each fresh\n instance and no seed node is needed. A second human member for \"act on\n someone else\" tests comes from a follow-up action (e.g. add-org-member,\n keyed to $var.USER.org_id). Constraint: consuming tests become\n sandbox-only, and no teardown is needed because the instance is destroyed.\n Prefer this on sandbox-backed properties; use the seed-workflow path\n everywhere else.\n","Test data discipline keeps workflows reliable and concurrent-safe.\n\nSTRONG TESTS: DEFAULTS AND THEIR WORKAROUNDS\n\n These are strong defaults, not absolutes. A test may deviate when the\n application makes a rule impossible — but it defaults to the rule, uses the\n workaround named here, and says so in ## Preflight / ## Cleanup so the\n deviation is visible, never silent.\n\n ## Preflight and ## Cleanup are the workflow's own preflight and cleanup\n notes (the spec sections of those names, or the workflow's preflight and\n cleanup fields), never the workflow description. People read them in the\n web UI: write them as short markdown bullet lists and name seeds,\n teardowns, connections and records, never raw IDs.\n\n 1. IDEMPOTENT — running the test again, including after a FAILED run,\n passes without a manual reset. Unique-name macros (\"QA Test —\n $RANDOM_STRING(6)\", $EMAIL()) make this true even when cleanup never\n happened.\n Workaround: if the app forbids duplicates (a singleton setting, one\n config record), revert the change in ## Cleanup and say so.\n\n 2. CONTROLS ITS OWN DATA — the test creates every record it operates on.\n Inline creation is the normal case: if the data is unique to this test,\n create it in the test. Use a seed workflow only when the data is (or\n should be) reused across several tests — a seed with one consumer is\n overhead, not hygiene. (Setup nodes are deprecated; do not use them.)\n Workaround: depending on data that already exists on the environment\n is fine AS LONG AS the test only reads it and never mutates it —\n confirm with the user that the discovered fixture is reliable for\n repeated runs, then declare it in ## Preflight (\"Property 'Acme Demo' exists with ≥1\n issue\"). A test that must mutate pre-existing data creates its own\n copy first, or states in Preflight why it can't.\n\n 3. ISOLATED — the test works only on data it created and never modifies\n shared resources as a side effect (billing, integrations, API keys, org\n config). Match the isolation level to the blast radius:\n record-level unique-id macros in a shared tenant — ordinary CRUD\n tenant/org-level a seeded org — the test mutates org-wide state\n application-level an ephemeral env / sandbox — it mutates global state\n Workaround: tests that genuinely depend on one another run as ordered\n LAYERS in a test suite (cofactor test-suite ... --layer, optionally\n --failure-mode stop_on_layer_failure). Layers run sequentially; members\n within a layer run in parallel. Never rely on implicit ordering between\n standalone flows.\n\n 4. CLEANUP SURVIVES FAILURE — a fatal assertion halts the run, so trailing\n inline cleanup nodes do NOT run. Seed-paired teardown workflows run on\n both pass and fail. Inline cleanup is therefore best-effort and pairs\n with unique naming (\"QA Test\" prefix + macro) so orphans are harmless\n and identifiable. When a record MUST be removed even after a failure\n (quota-bound, billed, visible to real users), that is the reason to move\n it into a seed + teardown pair.\n\n 5. EXTERNAL DEPENDENCIES ARE DECLARED OR CAPTURED — email delivery: give a\n seed credential output \"Create email inbox\" (the Email Inbox feature,\n /settings/inbox) so the flow can read the message. Payments, third-party\n APIs, feature flags: declare them in ## Preflight (cofactor feature-flag\n list --env <env> for exact flag names). Never assume an external\n system's state silently.\n\nSEED ONLY WHAT IS REUSED\n\n A seed workflow runs before your test, creates data, and exports variables\n downstream workflows reference as $var.{dataKey}. Reach for one when the\n same data serves several tests. When it does, you also get:\n - Faster setup — API sequences instead of browser interactions\n - Cleaner separation of setup and test logic\n - Paired teardown that runs on pass AND fail\n\n If only this test needs the data, create it inline (see CREATING TEST\n DATA below). See the Seed Workflows section for how to build seeds.\n\nSANDBOX BASE-SEED DATA ($var.SEED.*)\n\n On a sandbox environment, core baseline data (the application/property, a\n credential, sometimes a starter workflow) is provisioned automatically by a\n base seed and exposed as $var.SEED.{key} — e.g. $var.SEED.property_id.\n\n Prefer these over hardcoded names when you need a core entity that already\n exists on every tenant:\n Good: \"Open the property $var.SEED.property_id\"\n\n Base seeds are core-only. Anything test-specific (an issue, a notification,\n run history) is NOT in the base seed — create it yourself (see below) or via\n a per-test seed/custom action.\n\nTHE DATA OWNERSHIP PRINCIPLE\n\n Own your data:\n - Data you create → clean it up when the workflow finishes\n - Settings you modify → revert them when the workflow finishes\n - Data that was already there → never delete it\n\n It's fine to depend on pre-existing data (existing integrations, org\n settings, reference data) as long as the test only reads it — declare\n it in ## Preflight (rule 2 above). Create everything the test mutates.\n\nCREATING TEST DATA\n\n If the test operates on a record (edit, delete, archive), create that\n record as an early step. Operating on a record that already existed is\n a documented deviation, not the default (rule 2 above).\n\n Never reference \"any\" resource:\n Bad: \"Pick a project from the list\" (which one? may not exist)\n Good: \"Create a project named 'QA Test — $RANDOM_STRING(6)'\"\n Good: \"Use the seed output $var.project_id\"\n\n Use macros in newly created names to ensure uniqueness across parallel runs:\n Bad: \"Test Item\" (generic, will collide with other runs)\n Bad: \"QA Test Project\" (still collides if two runs overlap)\n Good: \"QA Test — $RANDOM_STRING(6)\" (unique every run)\n Good: \"QA Test $FIRST_NAME() $LAST_NAME()\" (unique and readable)\n\n After creating data, verify it exists before continuing.\n\nNAMING CONVENTION\n\n All test data should follow this pattern:\n\n Name/Title: \"QA Test $FIRST_NAME() $LAST_NAME()\"\n Email: \"$EMAIL()\"\n Phone: \"$PHONE()\"\n Project/Item: \"QA Test — $RANDOM_STRING(6)\"\n Unique ID: \"QA$TIMESTAMP()\"\n\n The \"QA Test\" prefix makes test data instantly recognizable. The macro\n suffix ensures every run creates unique data that won't collide with\n other runs or leftover data from previous executions.\n\nCLEANING UP (STRONGLY RECOMMENDED)\n\n Workflows that create data should include cleanup steps at the end.\n Workflows that modify settings should revert them.\n\n This isn't strictly required, but it's strongly recommended:\n - Cleanup prevents data accumulation over time\n - It keeps the test environment clean for other workflows\n - The \"QA Test\" naming convention makes orphaned data identifiable\n even when cleanup is skipped or fails\n\n Inline cleanup is best-effort: a fatal assertion halts the run before the\n cleanup nodes execute. Seed-paired teardowns run on pass and fail. Don't\n over-engineer inline cleanup — \"navigate to the item and delete it\" is\n enough; if a record must be gone even after a failure, provision it from a\n seed and let its teardown remove it (rule 4 above).\n\nWHAT NOT TO TOUCH\n\n - Don't create users, roles, or org-level config unless that's the goal\n - Don't modify shared resources (billing, integrations, API keys) as a side effect\n - Don't delete or modify data not owned by this workflow\n\nAVOIDING COLLISIONS WITH MACROS\n\n Use macros for newly created test names, emails, and identifiers. Keep\n confirmed existing reference names and captured identities intact. When every run generates unique values,\n there's no risk of conflicting with parallel runs or leftover data:\n\n $EMAIL() Unique email every run\n $RANDOM_STRING(6) Short unique suffix for names\n $UUID() Globally unique identifier\n $TIMESTAMP() Unique-per-millisecond numeric ID\n\n Combined with the \"QA Test\" prefix, this means you never need to\n worry about whether data from a previous run still exists. Each run\n creates its own isolated dataset.\n\nREAD-ONLY FLOWS\n\n Workflows that only read data (verify dashboard loads, check reports)\n don't need record creation or deletion. Restore any view state the journey\n changes. The presence of unrelated create/edit/delete controls does not\n expand the test's scope: exercise the specified behavior. A journey that\n tests writes owns those records and verifies their lifecycle. Only create\n what the test specifically requires.","Assertions verify that the application behaves as expected. There are two\nways to add assertions: inline on action nodes, or as standalone assertion\nnodes. Inline assertions are strongly preferred.\n\nINLINE ASSERTIONS (PREFERRED)\n\n Attach assertions directly to action nodes using the inlineAssertions\n field. These are verified immediately after the action completes and\n cached for fast replay.\n\n Inline assertions are the best way to verify outcomes because they:\n - Keep the test on track — verification happens right where the action is\n - Produce clean failure reports — each assertion is tied to the step that caused it\n - Are cacheable — fast replay on subsequent runs\n\n Each non-agentic inline assertion is proved by exactly one `verify` step in\n the playbook, bound to it by the assertion's id (see playbook.txt). That\n binding is what lets the check compile and replay at the point in the flow\n where it was actually verified, instead of trailing at the end of the node.\n\n Example — after submitting a form:\n Action: \"Submit the support ticket\"\n Inline assertions:\n - \"Success toast appears\" (severity: warn)\n - \"Ticket appears in the ticket list\" (severity: fail)\n - \"Form is no longer visible\" (severity: fatal)\n\n Severity levels — what a failure means for the run:\n fatal The test must end now. The run halts at this step.\n Use when continuing is pointless: login succeeded, the page\n loaded, a precondition every later step depends on.\n Example: \"User is logged in and the dashboard is visible\"\n fail The test may continue. The step is marked failed and the run\n finishes marked failed, but later steps still execute and\n produce signal.\n Use for independent checks: data saved, expected row present,\n error absent.\n Example: \"The new record appears in the table\"\n warn The test should continue. The failure is recorded as a warning\n and the run still passes.\n Use for cosmetic or non-critical checks: toast appeared,\n animation completed.\n Example: \"Success toast appears\"\n\n Choosing a severity: ask \"if this is wrong, is there any value in\n running the rest of the test?\" No → fatal. \"Does this being wrong mean\n the feature is broken?\" Yes → fail. Otherwise → warn. When unsure,\n prefer fatal for preconditions and fail for feature claims. Always set\n a severity explicitly — don't leave it unspecified.\n\n If verifying something requires significant interaction (scrolling,\n navigating, expanding sections), model that as an action node with\n inline assertions — not a detailed standalone assertion node.\n\nSTANDALONE ASSERTION NODES (USE SPARINGLY)\n\n Use dedicated assertion nodes only when the check doesn't belong to\n any action:\n\n - Verifying a final page state after navigation (no action to attach to)\n - Checking that data was NOT modified (absence checks after a sequence)\n - Confirming a state visible only after a wait or page transition\n\n A typical workflow has 0-1 standalone assertion nodes. If you find\n yourself writing a complex assertion node that requires multiple steps\n to verify, consider whether it should be an action node with inline\n assertions instead.\n\nAGENTIC ASSERTIONS\n\n For visual or layout checks that can't be mechanically validated,\n enable agent evaluation. These require the AI agent during replay\n and cannot be cached.\n\n Use for:\n - Screenshots that should \"look correct\"\n - Charts or graphs rendering properly\n Changing content, timestamps, and measurable layout can still be checked\n deterministically against current-run inputs and captured baselines.\n Cached assertions replay verification code, never an earlier verdict.\n\n Standard assertions are preferred — only use agentic when the\n check needs subjective judgment.\n\nWRITING GOOD CONDITIONS\n\n Assertions describe codified, user-visible behavior, not the mechanics\n used to observe it. Derive the expected result from the specification,\n product-map requirement, or confirmed user intent. Browser exploration\n discovers how to exercise and measure the behavior; it does not invent\n new acceptance requirements.\n\n Good: \"The named column stays fixed while level columns scroll.\"\n Good: \"After unpinning, the named column scrolls with the grid.\"\n Bad: \"aria-pressed=false and the SVG has an outlined path.\"\n Bad: \"Horizontal scroll increases at least 80 pixels.\" (unless required)\n\n A scroll distance or viewport size chosen for the test belongs in setup\n or the action. Measurements and comparison tolerances belong in replay\n code. Confirm the intended user during browser preflight; do not add a\n signed-in-user assertion unless identity/authentication is the journey.\n\n Assertions must be specific and observable:\n\n Good:\n - \"The status badge shows 'Active'\"\n - \"The table contains a row with name 'Test Record'\"\n - \"Error message is not visible\"\n - \"The page title is 'Dashboard'\"\n\n Bad:\n - \"The page looks correct\"\n - \"The action was successful\"\n - \"Everything works\"\n\n Start with what's observable: \"The page displays...\", \"The table\n contains...\", \"The field shows...\". Include the specific value\n you expect when the requirement specifies it. Do not assert exact\n incidental copy, attributes, or dimensions simply because they were observed.\n\nASSERTION BOUNDARIES & SELF-CONTAINED CHECKS\n\n Each action node should end at a checkpoint you can assert on — a modal\n disappeared, the URL changed, a row appeared, a toast fired. These boundaries\n double as the run's progress markers, so prefer a concrete end-state check\n to a vague one.\n\n Make every assertion SELF-CONTAINED. An action may replay from cache while\n its assertion is judged live by the agent, which does not have the action's\n execution context — so an assertion that silently assumes \"before\" state is\n unreliable. Relative or temporal checks are fine, but only when the baseline\n was captured upstream and referenced by variable:\n\n Good: \"current row count = $var.captured_row_count - 2\"\n Bad: \"the row count dropped by 2\" (no captured baseline — the live\n evaluator can't know the old count)\n\n Capture the baseline with declaredOutputs / a capture on the upstream node,\n then reference it as $var.<name> in the assertion.\n\nASSERTION PLACEMENT\n\n Place assertions at critical verification points:\n\n 1. After data creation: verify the record exists (inline on the create action)\n 2. After data modification: verify the change persisted (inline on the edit action)\n 3. After deletion: verify the item is gone (inline on the delete action)\n 4. At the goal completion point: verify the journey succeeded\n\n Don't assert everything — focus on the claims that matter.\n A focused assertion that proves the test's core claim is better\n than a dozen checks on every UI element.","API Sequences are the API-only counterpart to browser workflows. Instead of\ndriving a browser node-by-node, an API sequence is a single node\n(nodeType: \"api_sequence\") inside an api-only workflow that executes an\nordered list of HTTP calls, chaining outputs from one step into the inputs\nof the next.\n\nWHEN TO USE\n\n - Exercise an API without a UI (integration tests, fixture setup).\n - Seed or tear down state via API before/after a browser run.\n - Fast, deterministic smoke test of a critical flow.\n\nCONFIG SHAPE (ApiSequenceConfig)\n\n {\n \"steps\": [ ... ], // ordered; required\n \"description\": \"...\", // optional\n \"stopOnFailure\": true, // default: true\n \"exports\": [ ... ] // optional; see below\n }\n\nSTEP SHAPE (ApiSequenceStep)\n\n The authoritative type is in packages/types/src/api-sequence.ts. Key fields:\n\n {\n \"stepId\": \"createProject\", // optional; defaults to \"step{index}\"\n \"apiRequestId\": \"<catalog id>\", // required — points to api_requests row\n \"credentialId\": \"<uuid>\" | null, // null = unauthenticated\n \"credentialTemplateId\": \"<uuid>\" | null, // auth by persona/template (per-env); wins over credentialId\n \"credentialTemplateName\": \"<persona>\", // author-friendly alias for the above; resolved to the id on save\n \"method\": \"POST\", // optional; falls back to catalog default\n \"urlTemplate\": \"/projects/{{createProject.response.id}}\",\n \"queryParams\": [ { \"key\": \"limit\", \"value\": \"10\" } ],\n \"bodyTemplate\": \"{\\\"name\\\": \\\"$EMAIL()\\\"}\", // STRING (JSON), not object\n \"headersTemplate\": { \"X-Trace\": \"$UUID()\" }, // optional\n \"responseVariableName\": \"createProject\", // optional alias for stepId\n \"expectedStatusCodes\": [200, 201], // step fails if status is outside\n \"description\": \"...\", // optional UI label\n \"validations\": [ ... ], // assertions against the response\n \"validationMode\": \"all\" // \"all\" (default) or \"any\" validation must pass\n }\n\n CREDENTIAL ROLES — `credentialId` is overloaded; two distinct uses exist:\n\n - Step-level `credentialId` (and a top-level/default credential on the\n sequence) is AUTH: it's what the api-sequence runner uses to\n authenticate each HTTP call. Editing this changes who is calling.\n\n - Step-level `credentialTemplateId` is AUTH-by-persona: instead of a fixed\n credential id, name a credential template/persona and the runner resolves\n it to the credential bound for the run's environment (mirrors a login\n node's from_template). Takes precedence over `credentialId`. Use this when\n the same sequence must run across environments (e.g. Dev + a sandbox that\n mints its own per-instance credential) rather than a single static id.\n\n - `credentialId` appearing INSIDE a step's `bodyTemplate` JSON string is\n DATA: it gets written into the request body and becomes part of the\n provisioned resource (e.g. the credential a created workflow logs in\n with). Editing this changes what the call creates.\n\n The two are independent. Swapping the auth credential won't change what\n the call provisions; swapping the body credential won't change auth.\n Mixing them up silently produces confusing test failures.\n\n `apiRequestId` references a row in the `api_requests` table. Discover IDs\n from the API catalog for the target property. If `urlTemplate`, `method`,\n or `bodyTemplate` are omitted, they are backfilled from the catalog entry's\n defaults at execution time. A custom step that calls a URL directly uses\n `\"apiRequestId\": \"\"` and sets `method` and `urlTemplate` itself.\n\n `bodyTemplate` is a JSON *string*, not a JSON object — templates and macros\n are interpolated into it as raw text before parsing.\n\n MULTIPART UPLOADS — to send multipart/form-data instead of a raw body, set\n `formParts` on the step and omit `bodyTemplate`. The two are mutually\n exclusive; there is no separate mode field, a step is multipart exactly when\n `formParts` is present. Each part is either text or file:\n\n \"formParts\": [\n { \"kind\": \"text\", \"name\": \"projectId\", \"value\": \"$var.project_id\" },\n { \"kind\": \"file\", \"name\": \"file\", \"attachmentId\": \"<uuid>\" }\n ]\n\n A text part's `value` supports the same macro/variable/step-reference syntax\n as `bodyTemplate`. A file part names an attachment by UUID; add `filename`\n to override the name sent in Content-Disposition, otherwise the\n attachment's own filename is used. Don't set a `Content-Type` header on a\n multipart step: the transport generates its own boundary-bearing header at\n request time, so any author-supplied `Content-Type` is stripped rather than\n allowed to shadow it with a stale or missing boundary.\n\n API LOGIN CREDENTIALS — use these for token exchanges that precede the\n sequence request. POST bodies support application/json,\n application/x-www-form-urlencoded, and text/xml. With no body template,\n form fields are URL-encoded automatically. JSON token responses use normal\n dot paths such as access_token; XML/SOAP responses are parsed with namespace\n prefixes removed, so a Salesforce session path is\n Envelope.Body.loginResponse.result.sessionId. Keep returned tokens inside\n the Credential boundary — do not export them as workflow variables. Token\n request headers (for example Salesforce SOAPAction=login) are encrypted with\n the Credential and apply only to the token exchange.\n\nTEMPLATE SYNTAX\n\n Three ways to inject dynamic values. All three can appear in the same\n string (urlTemplate, bodyTemplate, headersTemplate values, or queryParams\n values).\n\n 1. STEP REFERENCES — outputs of prior steps.\n\n {{stepId.response.path.to.value}}\n\n The `.response.` segment is REQUIRED. This is the most common foot-gun:\n\n ✓ {{createProject.response.data.id}}\n ✗ {{createProject.data.id}} — missing .response., will warn at\n runtime and resolve to undefined\n ✗ {{projectId}} — no step reference at all\n\n The executor logs a warning for malformed references but does NOT\n block execution — a malformed template resolves to an empty string and\n the request goes out anyway. Always run once and check the run log.\n\n 2. MACROS — dynamic data generated fresh per run.\n\n $UUID() Random UUID v4\n $NOW() ISO 8601 timestamp (UTC)\n $NOW(+5m) ISO timestamp shifted by +5m / -2h / 30s / 1d\n $NOW(+5m, 'm H * * *') Shifted time rendered in UTC (see macros guide);\n single-quote the format inside a JSON bodyTemplate\n $TODAY() YYYY-MM-DD\n $DATE(N) Date offset by N days\n $TIMESTAMP() Unix ms\n $RANDOM_INT(min,max) Random integer in range\n $RANDOM_STRING(N) Alphanumeric string of length N\n $EMAIL() test-<rand>@example-test.com\n $FIRST_NAME() Random first name\n $LAST_NAME() Random last name\n $PHONE() +1-555-...\n $SEQUENCE(\"name\") Per-run auto-increment counter\n\n Each run resolves macros independently. $SEQUENCE counters persist\n across steps within a single run.\n\n 3. WORKFLOW VARIABLES — values injected by the workflow runtime.\n\n $var.<name>\n\n These come from two places:\n\n a) Upstream credential variables — pre-provisioned before the\n sequence runs. Typical names: `$var.credential.username`,\n `$var.credential.password`, `$var.credential.email`. If the\n workflow has a credential, USE these for the matching fields\n instead of `$EMAIL()` / `$RANDOM_STRING(6)` — the values must\n match the already-provisioned account.\n\n b) Upstream exports — values exported by earlier nodes in the same\n workflow (e.g. a seed step produced `$var.project_id`).\n\n Naming convention for exported variables: `resource_field` with\n underscores (e.g. `project_id`, `user_email`).\n\nEXPORTS\n\n After all steps finish, the sequence can register values from the final\n state into the workflow variable registry for downstream nodes:\n\n {\n \"exports\": [\n {\n \"variableName\": \"project_id\", // appears as $var.project_id\n \"stepId\": \"createProject\",\n \"responsePath\": \"data.id\",\n \"source\": \"response\", // \"response\" (default) | \"request\"\n \"description\": \"...\" // optional UI label\n }\n ]\n }\n\n Only export fields downstream nodes actually need. Use the\n `resource_field` naming convention.\n\nVALIDATIONS\n\n `validationMode` is \"all\" by default: every configured validation must pass.\n Set it to \"any\" to require at least one configured validation. The expected\n HTTP status requirement must still pass independently. Individual validation\n results retain their pass/fail values even when another alternative passes.\n\n Per-step assertions against the response. Each validation:\n\n {\n \"left\": \"createProject.response.data.status\", // \"stepId.path\" form\n \"operator\": \"equals\", // see list\n \"right\": \"active\", // omit for is_set/is_not_set\n \"description\": \"...\"\n }\n\n Operators: equals, not_equals, gt, lt, gte, lte, contains, not_contains,\n is_set, is_not_set.\n\nWHAT IS VALIDATED AT COMMIT TIME\n\n Save/update routes reject malformed step fields, unknown validation modes,\n invalid HTTP status codes, duplicate step IDs, invalid step references,\n unknown macros, and invalid exports. `validationMode` accepts only \"all\"\n or \"any\"; omitting it keeps all-checks behavior.\n\n Saving does not call the target API or prove its response. Smoke-test the\n sequence before relying on it in a workflow.\n\n CLI users: see `cofactor workflow guide cli-api-sequences` for command usage.\n\nEXAMPLE (3-step sequence, correct shape)\n\n {\n \"description\": \"Create an item, fetch it, delete it\",\n \"stopOnFailure\": true,\n \"steps\": [\n {\n \"stepId\": \"create\",\n \"apiRequestId\": \"<POST /items id>\",\n \"credentialId\": null,\n \"method\": \"POST\",\n \"bodyTemplate\": \"{\\\"name\\\": \\\"item-$RANDOM_STRING(6)\\\"}\",\n \"expectedStatusCodes\": [201]\n },\n {\n \"stepId\": \"fetch\",\n \"apiRequestId\": \"<GET /items/:id id>\",\n \"credentialId\": null,\n \"method\": \"GET\",\n \"urlTemplate\": \"/items/{{create.response.id}}\",\n \"expectedStatusCodes\": [200],\n \"validations\": [\n { \"left\": \"fetch.response.name\", \"operator\": \"is_set\" }\n ]\n },\n {\n \"stepId\": \"remove\",\n \"apiRequestId\": \"<DELETE /items/:id id>\",\n \"credentialId\": null,\n \"method\": \"DELETE\",\n \"urlTemplate\": \"/items/{{create.response.id}}\",\n \"expectedStatusCodes\": [200, 204]\n }\n ],\n \"exports\": [\n { \"variableName\": \"item_id\", \"stepId\": \"create\", \"responsePath\": \"id\" }\n ]\n }\n\nTIPS\n\n - Give every step a short, stable `stepId`. Later steps and exports\n reference it; the default `stepN` label is brittle to reordering.\n - Always include `.response.` in step references. The runtime won't\n error out, but values will silently resolve to empty strings.\n - Prefer `$EMAIL()`, `$UUID()`, `$RANDOM_STRING(6)` for fields that must\n be unique per run — unless the workflow has an upstream credential,\n in which case use `$var.credential.username` / `.password` / `.email`.\n - Set `expectedStatusCodes` on every step so unexpected 4xx/5xx fails\n the step instead of silently flowing into the next template.\n - `bodyTemplate` is a JSON STRING. Escape inner quotes.\n - `workflow api-sequence generate` can AI-draft a config from a prompt\n or a prior browser run; refine with `update`. The generated output is\n just JSON — review it before committing.\n","Use this section when you need to create or inspect seed workflows from the\nCofactor CLI. The conceptual model lives in `seed-workflows`; this section is\nonly command orientation. Prefer each command's `--help` output for the\ncurrent flag list.\n\nCREATE A SIMPLE SEED SHELL\n\n For simple data outputs, create the seed shell with repeatable output\n declarations:\n\n cofactor workflow seed create \\\n --name \"Create Test Project\" \\\n --description \"Provisions a test project with default settings\" \\\n --output \"project_id:Project ID:The created project's UUID\" \\\n --output \"project_name:Project Name\"\n\n This creates a draft seed workflow and, by default, a paired teardown\n workflow linked to the seed.\n\nCREATE A COMPLEX SEED SHELL\n\n For credential outputs or larger configs, put the full seed definition in a\n JSON file and create from that file:\n\n cofactor workflow seed create --from-file seed.json\n\n Keep generated credential fields in credentialOutput, and keep exported data\n fields in outputs. Downstream workflows consume both through $var.{dataKey}.\n `--outputs-json '<array>'` is the inline equivalent; to change the outputs\n of an existing seed use `cofactor workflow patch <id> --seed-outputs-file\n seed-outputs.json`. The credentialOutput shape and the end-to-end recipe\n are in `cofactor workflow guide seed-users`.\n\nAFTER CREATION\n\n Add the seed body through the Flow Designer or workflow sync, test both the\n seed and teardown, then publish. If the seed can be API-backed, generate or\n attach an API sequence after the browser version is proven.\n\nREFERENCE\n\n - Seed command help: `cofactor workflow seed --help`\n - Workflow sync help: `cofactor workflow sync --help`\n","Use this section when you need to drive API sequence authoring from the\nCofactor CLI. The conceptual model lives in `api-sequences`; this section is\nonly command orientation. Prefer each command's `--help` output for the\ncurrent flag list.\n\nCOMMON FLOW\n\n 1. Inspect the API catalog for candidate endpoints.\n\n cofactor api-catalog sources list\n cofactor api-catalog endpoints list --search <keyword>\n cofactor api-catalog endpoints get <apiRequestId>\n\n 2. Compose a sequence JSON file locally. Reference endpoints by\n apiRequestId and chain steps with {{stepId.response.path}}.\n\n 3. Create an API-only workflow from the sequence file.\n\n cofactor workflow create --api-only --name \"smoke: create project\" \\\n --sequence-from-file seq.json\n\n The command returns the workflow, sequence, and node IDs.\n\n To attach a sequence to an existing workflow that has none, run\n `cofactor workflow api-sequence update <workflowId> --from-file seq.json`;\n it creates the sequence when absent and replaces the config otherwise.\n\n 4. Execute immediately to surface template warnings and API failures.\n\n cofactor workflow api-sequence execute <workflowId>\n\n 5. Inspect the run and iterate on the sequence file.\n\n cofactor workflow runs list <workflowId> --side api\n cofactor workflow runs get <workflowId> <runId>\n cofactor workflow runs get <workflowId> <runId> --step <runStepId> --api-call <apiStepId>\n Add --json for JSON; the flags print stored (capped) request/response bodies.\n Get <runStepId> from runs get <workflowId> <runId> --json (steps[].id).\n cofactor workflow api-sequence update <workflowId> --from-file seq.json\n\nREFERENCE\n\n - Command help: `cofactor workflow api-sequence --help`\n - Workflow creation help: `cofactor workflow create --help`\n - API catalog help: `cofactor api-catalog --help`\n","Use this section to author a chat eval from the Cofactor CLI. The conceptual\nmodel lives in the CHAT SCENARIO and CALL FLOW node types; this section is only\ncommand orientation. Prefer each command's `--help` output for the current flag\nlist.\n\nAn eval is a workflow of flowType \"eval\" built around one chat_scenario node.\nIt needs a chat target first — the saved description of how to talk to the AI\nchat under test. Both require the `evals` feature flag.\n\nCREATE THE CHAT TARGET\n\n A chat target is application-scoped like a credential, and describes one\n endpoint: how to send a message, how to read the reply, who to send it as.\n\n cofactor chat-target create \\\n --application \"Acme App\" --environment \"Staging\" \\\n --credential \"Support Agent\" \\\n --name \"Acme support assistant\" \\\n --config ./target.json \\\n --invariant \"No cross-org data=Never reveals another organization's data.\"\n\n `--config` takes a file or `-` for stdin, holding `message` (method,\n urlTemplate, historyMode, bodyTemplate, optional headersTemplate) and\n `response` (transport `ai-sdk-v5`, or `sse` with deltaPath, or `json` with\n textPath).\n\n Only three slots are substituted per turn: {{message}}, {{messages}} and\n {{conversationId}}. There is NO {{baseUrl}} slot — write the endpoint as a\n literal URL.\n\n `$var.ENV.<name>` also resolves in a urlTemplate, which lets one target\n follow whichever environment a run picks. But it resolves only during a\n RUN: the live-chat path behind `chat-target chat` supplies no workflow\n variables, so a target written that way cannot be smoke-tested with the\n command below. Prefer a literal URL unless you need one target across\n several environments, and know the tradeoff if you do.\n\n `--invariant` is repeatable and declares a rubric judged against EVERY reply\n in every scenario run against this target — the cheapest coverage available.\n Severity defaults to fail; append `:warn` to the name to soften one.\n\nPROVE THE TARGET BEFORE BUILDING ON IT\n\n cofactor chat-target chat \"Acme support assistant\" --message \"What can you do?\"\n\n This sends one real turn down the same executor path a scenario uses, so a\n reply here is evidence the config, credential binding and transport all work.\n Expect 10-30s for a credentialed target — each message resolves an\n authenticated session server-side. A failed turn exits non-zero.\n\nAUTHOR AND RUN THE EVAL\n\n Author it like any other flow — `cofactor workflow create --from-file eval.json`\n with `\"flowType\": \"eval\"` and one `chat_scenario` node whose configJson holds\n `chatTargetId` and `turns` (see the CHAT SCENARIO entry for the shape).\n\n Put an api_sequence node BEFORE the chat node to establish ground truth and\n reference its exports from a rubric — \"Reports a count matching\n $var.expected_count\". Put a call_flow node AFTER it to have a browser flow\n verify something the assistant claims it did.\n\n Watch the two path forms in an api_sequence: a `validations` entry's `left`\n is step-qualified (`myStep.response.items.0.name`), while an `exports`\n entry's `responsePath` is relative to that step's response body\n (`items.0.name`) because it already names its `stepId`. Carrying the\n `response.` prefix into an export silently yields nothing — the step still\n passes, and the failure only surfaces later as a rubric that references a\n variable no step produced.\n\n Give the ground-truth step a `validations` entry as well as an export. An\n export that resolves to nothing does not fail the step, so without a\n validation the first sign of trouble is a withheld rubric further down.\n\n cofactor workflow run <workflowId>\n cofactor workflow runs get <runId>\n\n Per-turn judge verdicts persist on the chat_scenario step as\n `metadataJson.chatTranscript`, so the graded transcript is readable without\n opening the browser.\n\nREFERENCE\n\n - Chat target help: `cofactor chat-target --help`\n - Node config shapes: `cofactor workflow guide node-types`\n","Use this section to author a test straight from the CLI: plan the journey, check\nfor duplicates, create or update the workflow, run it, and hand back its URL.\nNo spec files are needed.\n\nAUTHORING LOOP\n\n 1. Understand the requirement. Read the ticket, PRD, or the user's intent, and\n explore the real UI first (see `best-practices` and `cofactor session guide`).\n 2. Avoid duplicates:\n cofactor workflow list --search \"<keywords>\"\n If a workflow already covers the journey, update it instead of creating one.\n 3. Create it (JSON on stdin or from a file; shapes are in `node-types`):\n cofactor workflow create --from-file test.json\n cofactor workflow create --from-file test.json --tags \"p0,checkout\"\n Input: { \"name\": \"...\", \"nodes\": [{ \"nodeType\": \"...\", \"configJson\": {...} }] }\n 4. Change an existing workflow:\n cofactor workflow get <workflowId> (read it first)\n cofactor workflow sync <workflowId> --from-file test.json (replace all nodes)\n cofactor workflow node patch <workflowId> <nodeId> --set-input key=value\n cofactor workflow patch <workflowId> --name \"...\" --description \"...\"\n cofactor workflow patch <workflowId> --preflight @preflight.md --cleanup @cleanup.md\n Reuse each existing node `id` in sync to keep a minimal diff. Add --propose\n to sync to open a proposal for review instead of applying directly.\n 5. Run it and look at the result:\n cofactor workflow run <workflowId> --stream\n cofactor workflow runs list <workflowId>\n cofactor workflow debug <runId> (when a run fails)\n 6. Return the workflow URL printed by the CLI to the user verbatim. Never\n build the URL yourself.\n\n Approving a test asserts that a human verified it checks the right thing. Do\n not pass --yes to `workflow approve` until the user has confirmed.\n\nTHE RUBRIC: EVERY TEST MUST SATISFY ALL OF THESE\n\n 1. One coherent journey per workflow\n One user objective, possibly with several verifications along the way.\n \"Atomic\" means coherent, not minimal. If isolating a check would force you\n to duplicate most of another test's setup, fold it in as an inline\n assertion on the larger journey.\n Good: create org -> invite a user -> claim invite -> land on dashboard.\n Good: submit a ticket and confirm it appears in the queue.\n Bad: submit a ticket, edit a user, generate a report (three journeys,\n three workflows).\n Split only when the setup is genuinely different or the failure modes are\n independent. A long single journey stays together; independent journeys\n become separate workflows so they run in parallel and fail independently.\n\n 2. Specific, observable expected results\n Every assertion is something a stranger could verify without judgement,\n and comes from the requirement or confirmed user intent, not incidental\n DOM details seen while exploring. Keep conditions about user-visible\n behavior; do not invent ARIA/SVG checks or pixel thresholds.\n Good: \"URL ends with /dashboard.\" \"A row named X appears in the table.\"\n Bad: \"The page looks correct.\" \"It works.\"\n Attach assertions inline to the action that produced the result (see\n `assertions`). Pick severity deliberately: fatal ends the run (gating\n preconditions), fail marks the run failed but continues (feature claims),\n warn records without failing (cosmetics). A test with no run-failing\n assertion proves nothing.\n Relative checks (\"the count dropped by 2\") must reference a value captured\n upstream and used via $var.<name>, never rely on memory of the earlier state.\n\n 3. Idempotent, self-owned, isolated\n - Rerunning passes without a manual reset: use macros ($EMAIL(), $UUID(),\n \"QA Test $RANDOM_STRING(6)\") for anything that must be unique (see `macros`).\n - The test creates the records it operates on, inline. A seed workflow is\n for data that several tests share; a seed with one consumer is overhead.\n Data the test only reads may pre-exist, but never mutate it.\n - Never modify shared resources (billing, integrations, API keys, org\n config) as a side effect.\n - Tests that depend on one another run as ordered suite layers, never by\n implicit ordering.\n - A fatal assertion halts the run before trailing cleanup. Anything that\n must be gone after a failure belongs in a seed with a teardown (see\n `seed-workflows`, `data-lifecycle`).\n\n 4. Traceable\n Link the test to the product-map capability it proves:\n cofactor product-map link <CAP-code> <workflowId>\n Traceability comes from that link, not from text: do not write capability\n codes, ticket ids or requirement references into the name or description.\n If no capability covers the test, tell the user; untraceable tests rot.\n\n 5. Risk-prioritized\n Tag each test p0, p1, or p2 with --tags / --tags-add:\n p0 happy path of the core promise; if it breaks the feature is broken\n p1 primary edge cases, validation, role variants, common error states\n p2 rare conditions, visual or agentic checks, low-frequency edges\n\n 6. Preconditions, data, and cleanup are explicit\n Auth and role: use a persona (cofactor persona list --application \"<app>\")\n rather than raw usernames and passwords. Shared setup: a seed node, placed\n before login. Test data: workflow inputs with macros. Anything else the\n test depends on (pre-existing data it reads, flags, third-party systems)\n goes in the workflow's preflight, and how its side effects get reset goes\n in its cleanup. Write each as a short markdown bullet list:\n cofactor workflow patch <workflowId> --preflight @preflight.md\n cofactor workflow patch <workflowId> --cleanup @cleanup.md\n\n 7. The description says what the test is for\n Read together with the name, the description gives the spirit of the\n test: what we are doing and why it matters, in one or two plain\n sentences. It never holds capability codes, preconditions, issue ids,\n status (\"expected red\", \"blocked\"), step narration, endpoints, payloads,\n timings or cache details. Each of those lives elsewhere: the product-map\n link, the preflight, the linked issue, the run history, the nodes.\n People read the description, preflight and cleanup in the web UI, so\n never put a raw ID in them: no UUID, UUID prefix, wf_/prule_ or other\n prefixed id, issue id or run id. Name the thing instead (the seed\n workflow's name, the teardown's name, the connection's name, the\n record's name).\n Good: name \"Invite a teammate to Acme\"\n description \"An admin invites a new teammate by email and the\n teammate can sign in. Growing a team depends on invites\n reaching people.\"\n Bad: description \"CAP-ORG-004. Needs seed org + admin persona. Steps:\n open /settings/team, POST /api/invites, wait 5s, check inbox.\n Expected red until ISSUE-812 ships. Cache warm.\"\n Bad preflight:\n Seed 5e055090 creates an empty layer. Paired teardown d9a44386\n deletes the flow.\n Good preflight:\n - The \"Acme empty layer\" seed creates an empty layer\n - Its paired teardown, \"Acme empty layer teardown\", deletes the flow\n\n 8. Written as human intent, not UI mechanics\n Action titles say what the user is trying to do (\"Assign the ticket to\n Support\"), not click-by-click steps. Each action is one coherent,\n assertable step: usually broader than one click, ends at a visible\n boundary (modal gone, URL changed, row appeared), and has no conditionals\n inside it. If the data might not exist, seed it instead of branching.\n\nCHOOSING VALUES\n\n - Names existing data in the target app (a property, persona, credential, a\n seeded record): do not guess. Look it up with `cofactor property list`,\n `cofactor persona list --application \"<app>\"`, or\n `cofactor workflow list --search <term>`, and ask the user when several\n candidates fit.\n - Synthesizable (email, UUID, throwaway string, date): use a macro and move on.\n - Auth or role: prefer a persona over a raw credential.\n\nCOVERAGE CHECKLIST\n\n Before handing work back, for each item either include a test or say why it\n does not apply: happy path (p0); primary edges and boundary inputs; negative\n paths and validation errors; permission and role variants; empty, loading,\n and error states; cross-entity side effects (does this change something\n visible elsewhere?); cleanup or undo.\n\n Aim for the smallest set that proves the feature works. Five sharp tests beat\n twenty fuzzy ones.\n","Use this section to prove a change to the application with Cofactor tests, so a\npull request carries the tests that cover it and merging it adds them to the\nregression suite.\n\nTHE RULE\n\n If a test already walks the journey, edit it (through a fork). Never add a new\n test for a changed filter, column or field: the suite fills with near-duplicates.\n\nTHE LOOP\n\n 1. Find coverage first:\n cofactor workflow list --search \"<words>\"\n cofactor workflow get <workflowId> --format markdown (read its assertions)\n 2. Choose:\n A test covers the journey -> fork it, edit the fork, never the original:\n cofactor workflow fork fork <workflowId>\n Nothing covers it, or it needs its own data or role -> write a new test\n (see `write-a-test`, `data-lifecycle`, `assertions`).\n No test is possible -> say so (step 5).\n 3. Run it on a sandbox of your change until it passes. After your last change,\n run it once more: that passing run is your proof, and the command prints its\n run id (a uuid or wrun_...; either works):\n cofactor sandbox claim --application <app> --wait\n cofactor sandbox sync <id> [--build]\n cofactor workflow run <fork> --sandbox <id> --stream\n 4. Push and open a draft pull request.\n 5. List each test with the run of it that passed. Print the block, never\n hand-format it:\n cofactor proofs block <workflowId> <runId> [<workflowId> <runId> ...]\n or, when no test is possible, say why and what would make one possible:\n cofactor proofs block --none \"<reason>\"\n Paste the printed block into the pull request description:\n <!-- cofactor:proofs -->\n - wf_... <run id> <name> (new | fork of <original>)\n <!-- /cofactor:proofs -->\n A listed test must be a new draft test or a fork of an approved test; an\n approved test cannot be changed by listing it directly.\n 6. Cofactor does not run the tests again. It checks that each listed run\n exists, belongs to its test, passed and ran the test as it is now (an edit\n after the run makes it no proof), and reports one `cofactor / proofs` check.\n It does not check which commit the run was against, so run the test after\n your last change. The check is evaluated again when you push, edit the\n description or press \"Re-run all checks\", and once more at merge. See what a\n pull request lists:\n cofactor proofs status --application <app> --pr <pr>\n 7. Merge. Merging is the approval: a new test whose run is proof is approved\n (\"approved by merge of #N by @login\") and added to suite runs, and a fork\n whose run is proof is merged into its original (added to suite runs if it was\n not) and deleted, unless the original changed after the fork was\n taken: then the proposal is left open in the original's proposals and the pull\n request gets a comment. A test whose run is not proof is left as a draft and\n runs in no suite. Cofactor does not require the check; it blocks a merge only\n if the repository makes it a required check.\n\n Closing the pull request without merging promotes nothing. The drafts and forks\n it lists are archived 14 days later (undoable); reopening it within that window\n keeps them.\n\nRECORD WHAT WAS UNCLEAR\n\n In the pull request description add `## Proof notes`: each decision you were\n unsure about (fork or new, what to assert, what you left uncovered) and why you\n chose as you did.\n","Visual checkpoints capture a meaningful screen state and compare it with the\nrolling baseline for that checkpoint. Add one checkpoint at each state whose\nappearance matters to the user; avoid taking several screenshots of the same\nstate just because the journey has several steps.\n\nNATIVE WORKFLOW CHECKPOINTS\n\n Checkpoints run in Sandboxes v2. Seed the sandbox into the exact state to\n compare, then capture it. A standalone visual regression test is a short\n workflow that prepares one state and takes its checkpoint. Examples include\n seeding a populated list before capturing it, or submitting invalid input and\n capturing the resulting validation error.\n\n The `target` is optional plain English describing an element, such as\n `the invoices table`; omit it to capture the whole page. Never put a CSS,\n XPath, or Playwright selector in `target`.\n\n `expected` is optional plain language describing the correct visible state.\n It guides the AI in deciding whether the current state is correct and whether\n a visual change is real or can be healed. Use a specific observable\n description, for example, \"Three invoices are listed, each marked Paid, with\n no error banner.\"\n\n `record` is the default. It records visual findings without changing the\n workflow result, and compares after the suite finishes. Choose `fail` when an\n unresolved visual change should fail this workflow step; it compares inline.\n Under either severity, a `target` that cannot be found is reported as a\n checkpoint that could not be compared, and under `fail` it fails the step.\n Both severities appear in Visual results.\n\n Dynamic text is masked automatically. If the AI heals a difference, it saves\n an element mask and its reason on the checkpoint. The review shows the heal;\n a reviewer can revert the mask or mark the change as a regression. Masks are\n automatic or healed; never author mask rules yourself.\n\nSTANDALONE VISUAL REGRESSION SPECS\n\n These complete `.cofactor.md` examples use the current spec grammar. Replace\n the illustrative seed name, persona, and routes with the published seed,\n persona, and paths used by your application. In each, prepare one meaningful\n state and capture it. Sandboxes v2 supplies the run.\n\n Seed a populated invoice list, then checkpoint it:\n\n ---\n name: Invoice list visual regression\n actor: admin\n authenticated: true\n ---\n\n ## Spirit\n > An admin can see the seeded invoices and their payment status.\n\n ## Journey\n\n **Seed** invoice-list-state\n\n **Navigate to** `/invoices`\n\n **Visual checkpoint — Populated invoice list**\n - target: the invoices table\n - expected: Three invoices are listed, each marked Paid, with no error banner.\n - severity: fail\n\n **End**.\n\n Submit invalid form data and checkpoint the validation state:\n\n ---\n name: Signup validation visual regression\n authenticated: false\n ---\n\n ## Spirit\n > A visitor sees clear validation feedback when required signup fields are missing.\n\n ## Journey\n\n **Navigate to** `/signup`\n\n **Action — Submit the empty signup form**\n > Submit without entering any values so the required-field messages appear.\n - assert (fail): A required-field validation message is visible.\n\n **Visual checkpoint — Required-field validation**\n - target: the signup form\n - expected: Required fields have clear validation messages and the form has not been submitted.\n - severity: record\n\n **End**.\n\nPLAYWRIGHT ATTACHMENT CHECKPOINTS\n\n In an external Playwright suite running on Sandboxes v2, an attached PNG is a\n visual checkpoint:\n\n await testInfo.attach(name, { body: await page.screenshot({ mask }), contentType: 'image/png' })\n\n Its identity is the spec file, test title, and attachment name. Keep masking\n in the test code with Playwright's `mask` option. The service explains and\n reports Playwright changes but never fails the Playwright test. Failure\n screenshots, trace frames, and `toHaveScreenshot` actuals are excluded. Do\n not use `toHaveScreenshot` for this feature; attach the screenshot instead.\n\nREVIEW RESULTS\n\n Review changes and comparisons on the Visual page. From the CLI, use\n `cofactor visual list` to find captures. Mark or clear a regression with\n `cofactor visual regression <captureId>` or\n `cofactor visual regression <captureId> --clear`.\n","import type { GuideSection } from '../types.js';\n\nimport overview from './overview.txt';\nimport nodeTypes from './node-types.txt';\nimport specGrammar from './spec-grammar.txt';\nimport actionNodes from './action-nodes.txt';\nimport playbook from './playbook.txt';\nimport bestPractices from './best-practices.txt';\nimport macros from './macros.txt';\nimport seedWorkflows from './seed-workflows.txt';\nimport seedUsers from './seed-users.txt';\nimport dataLifecycle from './data-lifecycle.txt';\nimport assertions from './assertions.txt';\nimport apiSequences from './api-sequences.txt';\nimport cliSeeds from './cli-seeds.txt';\nimport cliApiSequences from './cli-api-sequences.txt';\nimport cliChatEvals from './cli-chat-evals.txt';\nimport writeATest from './write-a-test.txt';\nimport proveChanges from './prove-changes.txt';\nimport visualCheckpoints from './visual-checkpoints.txt';\n\nexport const WORKFLOW_GUIDE_CONCEPT_SECTIONS: GuideSection[] = [\n { title: 'Workflow Overview', slug: 'overview', content: overview },\n { title: 'Node Types', slug: 'node-types', content: nodeTypes },\n { title: 'Spec file grammar (.cofactor.md)', slug: 'spec-grammar', content: specGrammar },\n { title: 'Action Nodes', slug: 'action-nodes', content: actionNodes },\n { title: 'Playbooks & Cache', slug: 'playbook', content: playbook },\n { title: 'Best Practices', slug: 'best-practices', content: bestPractices },\n { title: 'Macros & Variables', slug: 'macros', content: macros },\n { title: 'Seed Workflows', slug: 'seed-workflows', content: seedWorkflows },\n { title: 'Seeding a Test User', slug: 'seed-users', content: seedUsers },\n { title: 'Test Data Lifecycle', slug: 'data-lifecycle', content: dataLifecycle },\n { title: 'Assertions', slug: 'assertions', content: assertions },\n { title: 'API Sequences', slug: 'api-sequences', content: apiSequences },\n { title: 'Visual Checkpoints', slug: 'visual-checkpoints', content: visualCheckpoints },\n];\n\nexport const WORKFLOW_GUIDE_CLI_SECTIONS: GuideSection[] = [\n { title: 'CLI: Seed Workflows', slug: 'cli-seeds', content: cliSeeds },\n { title: 'CLI: API Sequences', slug: 'cli-api-sequences', content: cliApiSequences },\n { title: 'CLI: Chat Evals', slug: 'cli-chat-evals', content: cliChatEvals },\n { title: 'Write a Test from the CLI', slug: 'write-a-test', content: writeATest },\n { title: 'Prove a Change with Tests', slug: 'prove-changes', content: proveChanges },\n];\n\nexport const WORKFLOW_GUIDE_SECTIONS: GuideSection[] = [\n ...WORKFLOW_GUIDE_CONCEPT_SECTIONS,\n ...WORKFLOW_GUIDE_CLI_SECTIONS,\n];\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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AA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,mCAAmC,oBAAoB,KAAK,IAAI,CAAC;AAAA,MACjE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,oDAAoD,aAAa;AAAA,MACjE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,uCAAuC,oBAAoB,KAAK,IAAI,CAAC;AAAA,MACrE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA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","names":["fs","process","readFromStdin","fs","process","process","fs","process","process","process","process","process","process","process","process","result","fs","process","edges","fs","process","raw","result","process","process","fs","process","process","fs","fs","process","readFromStdin","process","readJsonInput","fs","process","fs","getAllArgValues"]}
|