@runcofactor/cli 0.28.0 → 0.29.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.
Files changed (115) hide show
  1. package/dist/{account-6FPITX2M.js → account-QWQP6YCY.js} +3 -3
  2. package/dist/{alert-PWERXHCP.js → alert-65FH7P74.js} +4 -4
  3. package/dist/{api-catalog-HCSSHOFY.js → api-catalog-WM6R37CA.js} +3 -3
  4. package/dist/{attachment-A7JAZWWH.js → attachment-FTQTZUTA.js} +3 -3
  5. package/dist/{augmentor-MIEBKJUK.js → augmentor-IQMT6NFX.js} +3 -3
  6. package/dist/{chunk-3VHY375S.js → chunk-3VIBXXNX.js} +2 -2
  7. package/dist/{chunk-IFZ72FZV.js → chunk-3X3TSH2B.js} +2 -2
  8. package/dist/{chunk-ZP3RP4IK.js → chunk-6AJLNMHB.js} +2 -2
  9. package/dist/{chunk-44NI5IDC.js → chunk-6QGUAITE.js} +15 -1
  10. package/dist/{chunk-44NI5IDC.js.map → chunk-6QGUAITE.js.map} +1 -1
  11. package/dist/{chunk-5N4OZPFQ.js → chunk-DECTGV4O.js} +2 -2
  12. package/dist/{chunk-6BAMC77N.js → chunk-E22PSTUP.js} +2 -2
  13. package/dist/{chunk-4ZNTGBJR.js → chunk-EHKHZ5UR.js} +23 -23
  14. package/dist/chunk-EHKHZ5UR.js.map +1 -0
  15. package/dist/{chunk-DHL4O7MG.js → chunk-MBMFYGKN.js} +2 -2
  16. package/dist/{chunk-YBX5BIKL.js → chunk-PK5UICGR.js} +2 -2
  17. package/dist/{chunk-4SV3CGNM.js → chunk-SFRUUIIC.js} +2 -2
  18. package/dist/{chunk-LSL2M7O6.js → chunk-WTMSRIDK.js} +2 -2
  19. package/dist/{credential-KSLGCJU7.js → credential-CKO4ZBMU.js} +3 -3
  20. package/dist/{credential-template-WECUNR4X.js → credential-template-XOZ2FJ6Z.js} +3 -3
  21. package/dist/{dist-5PKCAL5N.js → dist-YPK2RMUK.js} +3 -3
  22. package/dist/{docs-PRUI4LAD.js → docs-WZCQ6GP7.js} +3 -3
  23. package/dist/{environment-ATT4UQCY.js → environment-KO3JUX3V.js} +3 -3
  24. package/dist/{feature-flag-MWIHVJER.js → feature-flag-4YPPF27F.js} +63 -5
  25. package/dist/feature-flag-4YPPF27F.js.map +1 -0
  26. package/dist/index.js +38 -38
  27. package/dist/{init-QBMKWGHZ.js → init-RXWDJV5I.js} +3 -3
  28. package/dist/{install-BHYIXK6G.js → install-Z7EGAEEW.js} +3 -3
  29. package/dist/{issues-JO3OVOV7.js → issues-XOU54YKP.js} +3 -3
  30. package/dist/{knobs-4LLJ4LCU.js → knobs-7MB2O5SW.js} +3 -3
  31. package/dist/{list-JVJSIK52.js → list-5CJZY5BC.js} +3 -3
  32. package/dist/{local-VCZGHODB.js → local-XLBE4JIT.js} +5 -5
  33. package/dist/{login-UBNUPK2H.js → login-6GDATX4X.js} +3 -3
  34. package/dist/{mcp-2BBNDVZI.js → mcp-52UNMEF3.js} +4 -4
  35. package/dist/{metrics-4YOSDGIG.js → metrics-4Z5IJZ7U.js} +3 -3
  36. package/dist/{product-T2PVBVZ4.js → product-N2R3MWZS.js} +3 -3
  37. package/dist/{prompts-MI4QK2ZM.js → prompts-X6FNI6NZ.js} +3 -3
  38. package/dist/{property-EKASZCO7.js → property-VUKL5IFR.js} +3 -3
  39. package/dist/{record-Z4NY75FM.js → record-AVGKVJK7.js} +4 -4
  40. package/dist/{release-Z7WKFMBS.js → release-4QOZ4IP6.js} +3 -3
  41. package/dist/{sandbox-YOODBA5Q.js → sandbox-4ZR6XRIQ.js} +14 -3
  42. package/dist/sandbox-4ZR6XRIQ.js.map +1 -0
  43. package/dist/{scenarios-ABYCUJ4O.js → scenarios-UZBDO3XR.js} +3 -3
  44. package/dist/{schedule-ZRHOCT5Q.js → schedule-XCSZ6NLT.js} +4 -4
  45. package/dist/{session-T7BV73AC.js → session-QXHDS5GP.js} +5 -5
  46. package/dist/{skill-VLCWQJHG.js → skill-FXNE77RE.js} +166 -159
  47. package/dist/skill-FXNE77RE.js.map +1 -0
  48. package/dist/{spec-QPWXRPAG.js → spec-TOUOP4TC.js} +3 -3
  49. package/dist/{src-BH5O6Z3E.js → src-YZGG5ZSL.js} +3 -3
  50. package/dist/{start-5BADZ65B.js → start-JDLIIBPC.js} +3 -3
  51. package/dist/{tag-CIR6U5LL.js → tag-LSS3IOUA.js} +4 -4
  52. package/dist/{task-4YKONXJI.js → task-KCNDIT4A.js} +3 -3
  53. package/dist/{test-suite-PRJ2PGMN.js → test-suite-MOVN2XL5.js} +5 -5
  54. package/dist/{trace-XVB47RLY.js → trace-7OZNMAKV.js} +4 -4
  55. package/dist/{triage-L5WR65KW.js → triage-BRSUW4Z7.js} +4 -4
  56. package/dist/{utilities-LBKWREPU.js → utilities-TXQGGH37.js} +3 -3
  57. package/dist/{workflow-GCZCXPGA.js → workflow-2TVSFQXK.js} +310 -302
  58. package/dist/workflow-2TVSFQXK.js.map +1 -0
  59. package/dist/{workflow-cache-XWTLXIHE.js → workflow-cache-LRH5CAPS.js} +6 -6
  60. package/dist/{workflow-debug-XHR4552F.js → workflow-debug-IWXZXSL2.js} +5 -5
  61. package/dist/{workflow-proposals-VWLKW352.js → workflow-proposals-76D2MM6G.js} +3 -3
  62. package/package.json +1 -1
  63. package/dist/chunk-4ZNTGBJR.js.map +0 -1
  64. package/dist/feature-flag-MWIHVJER.js.map +0 -1
  65. package/dist/sandbox-YOODBA5Q.js.map +0 -1
  66. package/dist/skill-VLCWQJHG.js.map +0 -1
  67. package/dist/workflow-GCZCXPGA.js.map +0 -1
  68. /package/dist/{account-6FPITX2M.js.map → account-QWQP6YCY.js.map} +0 -0
  69. /package/dist/{alert-PWERXHCP.js.map → alert-65FH7P74.js.map} +0 -0
  70. /package/dist/{api-catalog-HCSSHOFY.js.map → api-catalog-WM6R37CA.js.map} +0 -0
  71. /package/dist/{attachment-A7JAZWWH.js.map → attachment-FTQTZUTA.js.map} +0 -0
  72. /package/dist/{augmentor-MIEBKJUK.js.map → augmentor-IQMT6NFX.js.map} +0 -0
  73. /package/dist/{chunk-3VHY375S.js.map → chunk-3VIBXXNX.js.map} +0 -0
  74. /package/dist/{chunk-IFZ72FZV.js.map → chunk-3X3TSH2B.js.map} +0 -0
  75. /package/dist/{chunk-ZP3RP4IK.js.map → chunk-6AJLNMHB.js.map} +0 -0
  76. /package/dist/{chunk-5N4OZPFQ.js.map → chunk-DECTGV4O.js.map} +0 -0
  77. /package/dist/{chunk-6BAMC77N.js.map → chunk-E22PSTUP.js.map} +0 -0
  78. /package/dist/{chunk-DHL4O7MG.js.map → chunk-MBMFYGKN.js.map} +0 -0
  79. /package/dist/{chunk-YBX5BIKL.js.map → chunk-PK5UICGR.js.map} +0 -0
  80. /package/dist/{chunk-4SV3CGNM.js.map → chunk-SFRUUIIC.js.map} +0 -0
  81. /package/dist/{chunk-LSL2M7O6.js.map → chunk-WTMSRIDK.js.map} +0 -0
  82. /package/dist/{credential-KSLGCJU7.js.map → credential-CKO4ZBMU.js.map} +0 -0
  83. /package/dist/{credential-template-WECUNR4X.js.map → credential-template-XOZ2FJ6Z.js.map} +0 -0
  84. /package/dist/{dist-5PKCAL5N.js.map → dist-YPK2RMUK.js.map} +0 -0
  85. /package/dist/{docs-PRUI4LAD.js.map → docs-WZCQ6GP7.js.map} +0 -0
  86. /package/dist/{environment-ATT4UQCY.js.map → environment-KO3JUX3V.js.map} +0 -0
  87. /package/dist/{init-QBMKWGHZ.js.map → init-RXWDJV5I.js.map} +0 -0
  88. /package/dist/{install-BHYIXK6G.js.map → install-Z7EGAEEW.js.map} +0 -0
  89. /package/dist/{issues-JO3OVOV7.js.map → issues-XOU54YKP.js.map} +0 -0
  90. /package/dist/{knobs-4LLJ4LCU.js.map → knobs-7MB2O5SW.js.map} +0 -0
  91. /package/dist/{list-JVJSIK52.js.map → list-5CJZY5BC.js.map} +0 -0
  92. /package/dist/{local-VCZGHODB.js.map → local-XLBE4JIT.js.map} +0 -0
  93. /package/dist/{login-UBNUPK2H.js.map → login-6GDATX4X.js.map} +0 -0
  94. /package/dist/{mcp-2BBNDVZI.js.map → mcp-52UNMEF3.js.map} +0 -0
  95. /package/dist/{metrics-4YOSDGIG.js.map → metrics-4Z5IJZ7U.js.map} +0 -0
  96. /package/dist/{product-T2PVBVZ4.js.map → product-N2R3MWZS.js.map} +0 -0
  97. /package/dist/{prompts-MI4QK2ZM.js.map → prompts-X6FNI6NZ.js.map} +0 -0
  98. /package/dist/{property-EKASZCO7.js.map → property-VUKL5IFR.js.map} +0 -0
  99. /package/dist/{record-Z4NY75FM.js.map → record-AVGKVJK7.js.map} +0 -0
  100. /package/dist/{release-Z7WKFMBS.js.map → release-4QOZ4IP6.js.map} +0 -0
  101. /package/dist/{scenarios-ABYCUJ4O.js.map → scenarios-UZBDO3XR.js.map} +0 -0
  102. /package/dist/{schedule-ZRHOCT5Q.js.map → schedule-XCSZ6NLT.js.map} +0 -0
  103. /package/dist/{session-T7BV73AC.js.map → session-QXHDS5GP.js.map} +0 -0
  104. /package/dist/{spec-QPWXRPAG.js.map → spec-TOUOP4TC.js.map} +0 -0
  105. /package/dist/{src-BH5O6Z3E.js.map → src-YZGG5ZSL.js.map} +0 -0
  106. /package/dist/{start-5BADZ65B.js.map → start-JDLIIBPC.js.map} +0 -0
  107. /package/dist/{tag-CIR6U5LL.js.map → tag-LSS3IOUA.js.map} +0 -0
  108. /package/dist/{task-4YKONXJI.js.map → task-KCNDIT4A.js.map} +0 -0
  109. /package/dist/{test-suite-PRJ2PGMN.js.map → test-suite-MOVN2XL5.js.map} +0 -0
  110. /package/dist/{trace-XVB47RLY.js.map → trace-7OZNMAKV.js.map} +0 -0
  111. /package/dist/{triage-L5WR65KW.js.map → triage-BRSUW4Z7.js.map} +0 -0
  112. /package/dist/{utilities-LBKWREPU.js.map → utilities-TXQGGH37.js.map} +0 -0
  113. /package/dist/{workflow-cache-XWTLXIHE.js.map → workflow-cache-LRH5CAPS.js.map} +0 -0
  114. /package/dist/{workflow-debug-XHR4552F.js.map → workflow-debug-IWXZXSL2.js.map} +0 -0
  115. /package/dist/{workflow-proposals-VWLKW352.js.map → workflow-proposals-76D2MM6G.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/skill.ts","../src/skill-identity.ts","../src/skill-install-helpers.ts","../src/skill-templates/issue-log-xref.ts","../src/skill-templates/browser-testing/current-workflow-authoring.ts","../src/skill-templates/browser-testing/render-sections.ts","../src/skill-templates/browser-testing/shared-session-sections.ts","../src/skill-templates/browser-testing/shared-workflow-sections.ts","../src/skill-templates/browser-testing-current.ts","../src/skill-templates/browser-testing/v1-workflow-authoring.ts","../src/skill-templates/browser-testing-v1-0-0.ts","../src/skill-templates/browser-testing.ts","../src/skill-templates/agent-tasks.ts","../src/skill-templates/canary-basic.ts","../src/skill-templates/test-cases-current.ts","../src/skill-templates/test-cases-v2-3-0.ts","../src/skill-templates/test-cases.ts","../src/skill-templates/debug-run.ts","../src/skill-templates/sandbox.ts","../src/skill-templates/index.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { brandSkillContentFor, command } from \"./brand.js\";\nimport {\n applyInstallIdentity,\n installedSourceKey,\n} from \"./skill-identity.js\";\nimport {\n detectAgent,\n formatInstallWriteFailure,\n isAgentType,\n isValidInstallName,\n resolveInstallDir,\n SUPPORTED_AGENTS,\n} from \"./skill-install-helpers.js\";\nimport { SKILL_TEMPLATES } from \"./skill-templates/index.js\";\nimport type { AgentType } from \"./skill-install-helpers.js\";\n\nexport {\n applyInstallIdentity,\n installedSourceKey,\n SKILL_SOURCE_KEY,\n} from \"./skill-identity.js\";\nexport {\n detectAgent,\n formatInstallWriteFailure,\n isInstallPermissionError,\n isValidInstallName,\n resolveInstallDir,\n} from \"./skill-install-helpers.js\";\nexport type { AgentType, InstallWriteFailureContext } from \"./skill-install-helpers.js\";\n\n/**\n * Render a skill template for the active brand. Install/output go through here\n * so a `cofactor` binary writes cofactor-branded skill files while `canary`\n * stays byte-for-byte identical. Authored-content tooling (`diff`, `versions`)\n * stays raw so it compares the source, not the per-brand presentation.\n */\nfunction renderForActiveBrand(template: { render: () => string }): string {\n return brandSkillContentFor(template.render(), command);\n}\n\nfunction printSkillHelp() {\n const lines = [\n \"Usage:\",\n \" canary skill <name> Output skill template to stdout\",\n \" canary skill install <name> Install skill (auto-detects agent)\",\n \" canary skill install <name> --agent codex Install for a specific agent\",\n \" canary skill install <name> --personal Install to ~/.<agent>/skills/\",\n \" canary skill install <name> --name <as> Install under a custom skill name\",\n \" canary skill install <name> --force Overwrite a name held by another skill\",\n \" canary skill list List available skill templates\",\n \" canary skill sync Print manifest + instructions for the\",\n \" agent to version-compare and update\",\n \" installed skills\",\n \" canary skill diff <name> [--from V] [--to V] Unified diff between two versions of\",\n \" a skill (defaults: previous → current)\",\n \" canary skill versions <name> List all known versions of a skill\",\n \"\",\n \"Agent auto-detection:\",\n \" The install command detects which AI agent is running and writes the\",\n \" SKILL.md to the correct location:\",\n \"\",\n \" Agent Project path Personal path\",\n \" ───── ──────────── ─────────────\",\n \" claude .claude/skills/<name>/ ~/.claude/skills/<name>/\",\n \" codex .codex/skills/<name>/ ~/.codex/skills/<name>/\",\n \" copilot .github/skills/<name>/ ~/.copilot/skills/<name>/\",\n \"\",\n \" Detection checks (in order):\",\n \" 1. CLAUDE env var → claude\",\n \" 2. CODEX_* env vars → codex\",\n \" 3. GITHUB_COPILOT env var → copilot\",\n \" 4. .claude/.codex/.github dirs → whichever single one exists\",\n \" 5. If ambiguous, use --agent to specify explicitly\",\n \"\",\n \"Custom skill names (--name):\",\n \" By default a skill installs under its template name. Pass --name to install\",\n \" it under a name of your choosing — useful when you want every Canary-provided\",\n \" skill namespaced (e.g. canary-browser-testing) to avoid colliding with your\",\n \" own skills. --name sets both the install directory and the SKILL.md\",\n \" frontmatter name: (agents require those to match), and records the source\",\n \" template in a skill-source: field so `sync` and `diff` keep tracking updates\",\n \" even under the renamed install.\",\n \"\",\n \" canary skill install browser-testing --name canary-browser-testing\",\n \"\",\n \" Installing a different skill onto an existing custom name is refused unless\",\n \" you pass --force. When an agent installs skills on your behalf, it should\",\n \" follow your naming convention.\",\n \"\",\n \"Available templates:\",\n ];\n\n for (const [key, template] of Object.entries(SKILL_TEMPLATES)) {\n lines.push(\n ` ${key.padEnd(24)} v${template.version.padEnd(7)} ${template.description}`\n );\n }\n\n console.log(lines.join(\"\\n\"));\n}\n\nfunction compareSemver(a: string, b: string): number {\n const pa = a.split(\".\").map((n) => parseInt(n, 10) || 0);\n const pb = b.split(\".\").map((n) => parseInt(n, 10) || 0);\n for (let i = 0; i < 3; i++) {\n const d = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (d !== 0) return d < 0 ? -1 : 1;\n }\n return 0;\n}\n\nfunction knownVersions(name: string): string[] {\n const t = SKILL_TEMPLATES[name];\n if (!t) return [];\n const all = new Set<string>([t.version, ...Object.keys(t.previousVersions ?? {})]);\n return [...all].sort(compareSemver);\n}\n\nfunction renderAtVersion(name: string, version: string): string | null {\n const t = SKILL_TEMPLATES[name];\n if (!t) return null;\n if (version === t.version) return t.render();\n const prev = t.previousVersions?.[version];\n return prev ? prev() : null;\n}\n\nfunction parseFlagArgs(argv: string[]): {\n positional: string[];\n flags: Record<string, string | true>;\n} {\n const positional: string[] = [];\n const flags: Record<string, string | true> = {};\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a.startsWith(\"--\")) {\n const key = a.slice(2);\n const next = argv[i + 1];\n if (next !== undefined && !next.startsWith(\"--\")) {\n flags[key] = next;\n i++;\n } else {\n flags[key] = true;\n }\n } else {\n positional.push(a);\n }\n }\n return { positional, flags };\n}\n\nfunction runVersions(argv: string[]) {\n const [name] = argv;\n if (!name || !SKILL_TEMPLATES[name]) {\n console.error(`Usage: canary skill versions <name>`);\n process.exit(1);\n }\n const versions = knownVersions(name);\n const current = SKILL_TEMPLATES[name].version;\n for (const v of versions) {\n console.log(v === current ? `${v} (current)` : v);\n }\n}\n\nfunction jsUnifiedDiff(\n a: string,\n b: string,\n labelA: string,\n labelB: string\n): string {\n const aLines = a.split(\"\\n\");\n const bLines = b.split(\"\\n\");\n const n = aLines.length;\n const m = bLines.length;\n const dp: number[][] = Array.from({ length: n + 1 }, () =>\n Array.from<number>({ length: m + 1 }).fill(0)\n );\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n dp[i][j] =\n aLines[i] === bLines[j]\n ? dp[i + 1][j + 1] + 1\n : Math.max(dp[i + 1][j], dp[i][j + 1]);\n }\n }\n const out: string[] = [`--- ${labelA}`, `+++ ${labelB}`];\n let i = 0;\n let j = 0;\n while (i < n && j < m) {\n if (aLines[i] === bLines[j]) {\n out.push(` ${aLines[i]}`);\n i++;\n j++;\n } else if (dp[i + 1][j] >= dp[i][j + 1]) {\n out.push(`-${aLines[i++]}`);\n } else {\n out.push(`+${bLines[j++]}`);\n }\n }\n while (i < n) out.push(`-${aLines[i++]}`);\n while (j < m) out.push(`+${bLines[j++]}`);\n return out.join(\"\\n\") + \"\\n\";\n}\n\nfunction runDiff(argv: string[]) {\n const { positional, flags } = parseFlagArgs(argv);\n const [name] = positional;\n\n if (!name) {\n console.error(\n \"Usage: canary skill diff <name> [--from <version>] [--to <version>]\"\n );\n process.exit(1);\n }\n\n const template = SKILL_TEMPLATES[name];\n if (!template) {\n console.error(`Unknown skill \"${name}\".`);\n process.exit(1);\n }\n\n const versions = knownVersions(name);\n const to =\n typeof flags.to === \"string\" ? flags.to : template.version;\n const from =\n typeof flags.from === \"string\"\n ? flags.from\n : versions.filter((v) => v !== to).slice(-1)[0];\n\n if (!from) {\n console.error(\n `No prior version of \"${name}\" to diff against. Only known version: ${template.version}.`\n );\n process.exit(1);\n }\n\n const fromContent = renderAtVersion(name, from);\n const toContent = renderAtVersion(name, to);\n\n if (fromContent === null) {\n console.error(\n `Version \"${from}\" of skill \"${name}\" is not in the CLI. Known: ${versions.join(\", \")}.`\n );\n process.exit(1);\n }\n if (toContent === null) {\n console.error(\n `Version \"${to}\" of skill \"${name}\" is not in the CLI. Known: ${versions.join(\", \")}.`\n );\n process.exit(1);\n }\n\n if (from === to) {\n console.log(`(no diff — both sides are v${from})`);\n return;\n }\n\n process.stdout.write(\n jsUnifiedDiff(fromContent, toContent, `${name}@${from}`, `${name}@${to}`)\n );\n}\n\nfunction runSync() {\n const manifest = Object.entries(SKILL_TEMPLATES).map(([key, t]) => ({\n name: key,\n version: t.version,\n description: t.description,\n knownVersions: knownVersions(key),\n installedPaths: {\n claudeProject: `.claude/skills/${key}/SKILL.md`,\n claudePersonal: join(homedir(), \".claude\", \"skills\", key, \"SKILL.md\"),\n codexProject: `.codex/skills/${key}/SKILL.md`,\n codexPersonal: join(homedir(), \".codex\", \"skills\", key, \"SKILL.md\"),\n copilotProject: `.github/skills/${key}/SKILL.md`,\n copilotPersonal: join(homedir(), \".copilot\", \"skills\", key, \"SKILL.md\"),\n },\n }));\n\n const instructions = `# Canary Skill Sync — Instructions for the Agent\n\nYou are an AI coding agent (Claude, Codex, Copilot, etc.). The user ran \\`canary skill sync\\`\nto bring their installed Canary skill templates up to date. Follow these steps:\n\n## Step 1 — Discover installed skills (including renamed ones)\n\nSkills can be installed under a **custom name** (\\`canary skill install <name> --name <as>\\`),\nso do not rely only on the canonical \\`installedPaths\\` below. List every \\`SKILL.md\\`\nunder your agent's skills directory — both project and personal:\n\n .claude/skills/*/SKILL.md and ~/.claude/skills/*/SKILL.md (claude)\n .codex/skills/*/SKILL.md and ~/.codex/skills/*/SKILL.md (codex)\n .github/skills/*/SKILL.md and ~/.copilot/skills/*/SKILL.md (copilot)\n\nFor each file, read its frontmatter and resolve which manifest skill it came from:\n- If a \\`skill-source: <key>\\` line is present, that \\`<key>\\` is the template name\n (the skill was installed under a custom \\`--name\\`). The install directory is the\n custom name; remember it for Step 5.\n- Otherwise the \\`name:\\` value is the template name (a default install, where the\n install name equals the template key).\n\nMatch that resolved key against the manifest \\`name\\` field. Ignore any \\`SKILL.md\\`\nwhose resolved key is not in the manifest (it isn't a Canary skill).\n\n## Step 2 — Read the version of each installed skill\n\nThe \\`SKILL.md\\` frontmatter contains a \\`version: X.Y.Z\\` line. Parse that value.\nIf the frontmatter has no \\`version:\\` field, treat the installed version as \\`0.0.0\\`.\n\n## Step 3 — Compare semver\n\nFor each installed skill, compare \\`installedVersion\\` to the \\`version\\` in the manifest:\n- If \\`installedVersion < manifestVersion\\` → the skill is **outdated**, update it.\n- If equal or greater → leave it alone.\n\n## Step 4 — For each outdated skill, inspect what changed\n\nBefore overwriting, read the diff so you know what's new. Diff by the **template\nkey** you resolved in Step 1 (not the custom install name) — the diff compares\nsource renders and is independent of how the skill was named on disk:\n\n canary skill diff <templateKey> --from <installedVersion>\n\nThe CLI retains past renders of each skill in \\`previousVersions\\`, so this prints a\nunified diff from the user's installed version → the current version. Only versions\nlisted in \\`knownVersions\\` in the manifest can be diffed; if \\`installedVersion\\` is\nolder than the oldest known version, diff against the oldest known version instead\nand warn the user that the older content is no longer reproducible.\n\nUse the diff to:\n- Summarize what changed for the user (new sections, removed guidance, renamed commands).\n- Decide whether any user-local edits to the installed SKILL.md would be clobbered —\n if the user appears to have edited their local copy, surface that and ask before\n overwriting.\n\n## Step 5 — Update outdated skills\n\nRe-install with the template key, preserving both the location AND the custom name\nit was installed under (the install directory name from Step 1):\n\n canary skill install <templateKey> # default-named project install\n canary skill install <templateKey> --personal # default-named personal install\n canary skill install <templateKey> --name <installDir> # custom-named project install\n canary skill install <templateKey> --name <installDir> --personal\n\nPreserve whichever location and name it was already installed in — if it lived in\n\\`canary-browser-testing/\\`, re-install with \\`--name canary-browser-testing\\` so the\nupdate lands in place rather than creating a second default-named copy. Do NOT install\nskills that weren't already installed — sync only updates existing installs. When the\nuser has a naming convention, keep installing under their chosen names on their behalf.\n\n## Step 6 — Report\n\nPrint a concise summary: which skills were updated (old → new version), which were\nalready current, and which were not installed (skipped).\n\n## Manifest\n\n\\`\\`\\`json\n${JSON.stringify({ skills: manifest }, null, 2)}\n\\`\\`\\`\n`;\n\n process.stdout.write(instructions);\n}\n\nfunction parseInstallArgs(argv: string[]): {\n /** The registry/template key (positional argument). */\n templateName: string | undefined;\n /** Directory + frontmatter name to install under (defaults to templateName). */\n installName: string | undefined;\n agent: AgentType | undefined;\n personal: boolean;\n force: boolean;\n} {\n let templateName: string | undefined;\n let installName: string | undefined;\n let agent: AgentType | undefined;\n let personal = false;\n let force = false;\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === \"--agent\" && i + 1 < argv.length) {\n const val = argv[++i];\n if (!isAgentType(val)) {\n console.error(\n `Unknown agent \"${val}\". Supported agents: ${SUPPORTED_AGENTS.join(\", \")}`\n );\n process.exit(1);\n }\n agent = val;\n } else if (arg === \"--name\" && i + 1 < argv.length) {\n const val = argv[++i];\n if (!isValidInstallName(val)) {\n console.error(\n `Invalid skill name \"${val}\". Use letters, digits, hyphens, or underscores (e.g. canary-browser-testing).`\n );\n process.exit(1);\n }\n installName = val;\n } else if (arg === \"--personal\") {\n personal = true;\n } else if (arg === \"--force\" || arg === \"-f\") {\n force = true;\n } else if (!arg.startsWith(\"-\") && !templateName) {\n templateName = arg;\n }\n }\n\n return { templateName, installName: installName ?? templateName, agent, personal, force };\n}\n\nasync function runInstall(argv: string[]) {\n const {\n templateName,\n installName,\n agent: explicitAgent,\n personal,\n force,\n } = parseInstallArgs(argv);\n\n if (!templateName || !installName) {\n console.error(\"Missing skill name.\\n\");\n console.error(\n `Usage: canary skill install <name> [--name <install-name>] [--agent ${SUPPORTED_AGENTS.join(\"|\")}] [--personal] [--force]`\n );\n process.exit(1);\n }\n\n const template = SKILL_TEMPLATES[templateName];\n if (!template) {\n console.error(`Unknown skill template \"${templateName}\".\\n`);\n console.error(\"Available templates:\");\n for (const [key, t] of Object.entries(SKILL_TEMPLATES)) {\n console.error(` ${key.padEnd(24)} ${t.description}`);\n }\n process.exit(1);\n }\n\n // Resolve agent type\n const agent = explicitAgent ?? detectAgent();\n if (!agent) {\n console.error(\n \"Could not auto-detect the AI agent. Use --agent to specify:\\n\"\n );\n console.error(\n \" canary skill install <name> --agent claude # Claude Code\"\n );\n console.error(\n \" canary skill install <name> --agent codex # OpenAI Codex\"\n );\n console.error(\n \" canary skill install <name> --agent copilot # GitHub Copilot\"\n );\n process.exit(1);\n }\n\n const dir = resolveInstallDir(installName, agent, personal);\n const filePath = join(dir, \"SKILL.md\");\n\n // Collision guard: refuse to clobber a SKILL.md installed under this name from\n // a DIFFERENT template (e.g. collapsing multiple skills onto one name) unless\n // --force is passed. Updating the same skill in place is always allowed.\n if (existsSync(filePath) && !force) {\n const existingSource = installedSourceKey(readFileSync(filePath, \"utf-8\"));\n if (existingSource && existingSource !== templateName) {\n console.error(\n `✗ ${installName} already holds '${existingSource}'. Pass --force to overwrite.`\n );\n process.exit(1);\n }\n }\n\n // Write the file (brand-aware: cofactor binary writes cofactor-branded text),\n // rewriting the frontmatter identity when installing under a custom name.\n const content = applyInstallIdentity(\n renderForActiveBrand(template),\n installName,\n templateName\n );\n try {\n mkdirSync(dir, { recursive: true });\n writeFileSync(filePath, content, \"utf-8\");\n } catch (error) {\n console.error(\n formatInstallWriteFailure({\n cwd: process.cwd(),\n templateName,\n installName,\n agent,\n personal,\n dir,\n filePath,\n error,\n })\n );\n process.exit(1);\n }\n\n const relPath = personal ? filePath : filePath.replace(process.cwd() + \"/\", \"\");\n const named = installName === templateName ? \"\" : ` as ${installName}`;\n console.log(`Installed ${templateName} skill for ${agent}${named} → ${relPath}`);\n}\n\nexport async function runSkill(argv: string[]) {\n const [sub] = argv;\n\n if (!sub || sub === \"help\" || sub === \"--help\" || sub === \"-h\" || sub === \"list\") {\n printSkillHelp();\n return;\n }\n\n // canary skill install <name> [--agent ...]\n if (sub === \"install\") {\n await runInstall(argv.slice(1));\n return;\n }\n\n // canary skill sync — print instructions for the agent\n if (sub === \"sync\") {\n runSync();\n return;\n }\n\n if (sub === \"diff\") {\n runDiff(argv.slice(1));\n return;\n }\n\n if (sub === \"versions\") {\n runVersions(argv.slice(1));\n return;\n }\n\n // canary skill <name> — output to stdout (backward compatible)\n const template = SKILL_TEMPLATES[sub];\n if (!template) {\n console.error(`Unknown skill template \"${sub}\".\\n`);\n printSkillHelp();\n process.exit(1);\n }\n\n process.stdout.write(renderForActiveBrand(template));\n}\n","/**\n * Skill frontmatter identity helpers.\n *\n * These helpers keep custom-named installs traceable to their source template\n * without coupling that parsing/writing logic to the skill command runner.\n */\n\n/**\n * Brand-neutral frontmatter key that records which template a SKILL.md was\n * rendered from. Stamped only when a skill is installed under a custom name\n * (`--name`), so `sync`/`diff` can map a renamed install back to its template\n * for version-compare and update.\n */\nexport const SKILL_SOURCE_KEY = \"skill-source\";\n\n/**\n * Split a SKILL.md into its leading YAML frontmatter block and the body. The\n * frontmatter is the block between the first `---` line and the next `---`\n * line. Returns `null` when the content has no recognizable frontmatter, so\n * callers can skip identity rewriting rather than corrupt the file.\n */\nfunction splitFrontmatter(\n content: string\n): { frontmatter: string; body: string } | null {\n const lines = content.split(\"\\n\");\n if (lines[0] !== \"---\") return null;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i] === \"---\") {\n return {\n frontmatter: lines.slice(1, i).join(\"\\n\"),\n // Keep the closing `---` and everything after it in the body so a\n // round-trip with `applyInstallIdentity` reproduces the file exactly.\n body: lines.slice(i).join(\"\\n\"),\n };\n }\n }\n return null;\n}\n\n/**\n * Read a single `key: value` field out of a frontmatter block. Returns `null`\n * when the key is absent. Used to recover an installed skill's `name:` /\n * `skill-source:` for the collision guard.\n */\nfunction readFrontmatterField(frontmatter: string, key: string): string | null {\n for (const line of frontmatter.split(\"\\n\")) {\n const match = line.match(/^([A-Za-z0-9_-]+):\\s*(.*)$/);\n if (match && match[1] === key) return match[2].trim();\n }\n return null;\n}\n\n/**\n * Derive the template key an already-installed SKILL.md was rendered from:\n * the `skill-source:` stamp when present (custom-named install), otherwise the\n * `name:` field (a default install, where name === template key). `null` when\n * neither is present.\n */\nexport function installedSourceKey(content: string): string | null {\n const parts = splitFrontmatter(content);\n if (!parts) return null;\n return (\n readFrontmatterField(parts.frontmatter, SKILL_SOURCE_KEY) ??\n readFrontmatterField(parts.frontmatter, \"name\")\n );\n}\n\n/**\n * Rewrite a rendered SKILL.md so it installs cleanly under `installName`:\n * the frontmatter `name:` is set to `installName` (agents require `name:` to\n * match the install directory), and — only when the name differs from the\n * template key — a `skill-source: <templateKey>` line is stamped so\n * `sync`/`diff` can still track the install.\n */\nexport function applyInstallIdentity(\n content: string,\n installName: string,\n templateKey: string\n): string {\n if (installName === templateKey) return content;\n\n const parts = splitFrontmatter(content);\n if (!parts) return content;\n\n const out: string[] = [];\n let wroteName = false;\n let wroteSource = false;\n for (const line of parts.frontmatter.split(\"\\n\")) {\n const match = line.match(/^([A-Za-z0-9_-]+):\\s*(.*)$/);\n const key = match?.[1];\n if (key === \"name\") {\n out.push(`name: ${installName}`);\n out.push(`${SKILL_SOURCE_KEY}: ${templateKey}`);\n wroteName = true;\n wroteSource = true;\n } else if (key === SKILL_SOURCE_KEY) {\n // Re-stamp from the template key rather than trusting a stale value.\n if (!wroteSource) {\n out.push(`${SKILL_SOURCE_KEY}: ${templateKey}`);\n wroteSource = true;\n }\n } else {\n out.push(line);\n }\n }\n // Defensive: frontmatter missing `name:` / `skill-source:` still gets them.\n if (!wroteName) out.unshift(`name: ${installName}`);\n if (!wroteSource) {\n const nameIdx = out.findIndex((l) => l.startsWith(\"name:\"));\n out.splice(nameIdx >= 0 ? nameIdx + 1 : 0, 0, `${SKILL_SOURCE_KEY}: ${templateKey}`);\n }\n\n // Reassemble: leading `---`, rewritten frontmatter, then the original body\n // (which already starts with its own closing `---` fence).\n return `---\\n${out.join(\"\\n\")}\\n${parts.body}`;\n}\n","/**\n * Skill install path, agent detection, and write-error helpers.\n *\n * The command runner performs template lookup and filesystem writes; this\n * module owns the pure-ish install support logic that is easiest to test in\n * isolation.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { command } from \"./brand.js\";\n\nexport type AgentType = \"claude\" | \"codex\" | \"copilot\";\n\nexport const SUPPORTED_AGENTS: AgentType[] = [\"claude\", \"codex\", \"copilot\"];\n\ntype DetectAgentOptions = {\n cwd?: string;\n env?: NodeJS.ProcessEnv;\n exists?: (path: string) => boolean;\n};\n\ntype InstallPathOptions = {\n cwd?: string;\n home?: string;\n};\n\nexport function isAgentType(value: string): value is AgentType {\n return value === \"claude\" || value === \"codex\" || value === \"copilot\";\n}\n\n/**\n * Detect which AI agent is currently running based on environment variables\n * and project directory structure.\n */\nexport function detectAgent(options: DetectAgentOptions = {}): AgentType | null {\n const env = options.env ?? process.env;\n const cwd = options.cwd ?? process.cwd();\n const pathExists = options.exists ?? existsSync;\n\n if (env.CLAUDE) return \"claude\";\n\n if (\n env.CODEX ||\n env.CODEX_CI ||\n env.CODEX_THREAD_ID ||\n env.CODEX_MANAGED_PACKAGE_ROOT ||\n env.AGENT_MODE === \"codex\"\n )\n return \"codex\";\n\n if (\n env.GITHUB_COPILOT ||\n env.COPILOT_AGENT ||\n env.AGENT_MODE === \"copilot\"\n )\n return \"copilot\";\n\n const foundAgents = SUPPORTED_AGENTS.filter((agent) =>\n pathExists(join(cwd, agent === \"copilot\" ? \".github\" : `.${agent}`))\n );\n\n if (foundAgents.length === 1) return foundAgents[0] ?? null;\n return null;\n}\n\n/**\n * Resolve the install directory for a skill based on agent type.\n */\nexport function resolveInstallDir(\n skillName: string,\n agent: AgentType,\n personal: boolean,\n options: InstallPathOptions = {}\n): string {\n const base = personal\n ? (options.home ?? homedir())\n : (options.cwd ?? process.cwd());\n\n switch (agent) {\n case \"claude\":\n return join(base, \".claude\", \"skills\", skillName);\n case \"codex\":\n return join(base, \".codex\", \"skills\", skillName);\n case \"copilot\":\n return personal\n ? join(base, \".copilot\", \"skills\", skillName)\n : join(base, \".github\", \"skills\", skillName);\n }\n}\n\nexport type InstallWriteFailureContext = {\n cwd: string;\n templateName: string;\n installName: string;\n agent: AgentType;\n personal: boolean;\n dir: string;\n filePath: string;\n error: unknown;\n};\n\nfunction errorField(error: unknown, key: string): string | undefined {\n if (typeof error !== \"object\" || error === null) return undefined;\n const value = (error as Record<string, unknown>)[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nexport function isInstallPermissionError(error: unknown): boolean {\n const code = errorField(error, \"code\");\n return code === \"EACCES\" || code === \"EPERM\" || code === \"EROFS\";\n}\n\nfunction formatErrorSummary(error: unknown): string {\n const code = errorField(error, \"code\");\n const message = errorField(error, \"message\");\n if (code && message) return `${code}: ${message}`;\n if (message) return message;\n if (error instanceof Error) return error.message;\n return String(error);\n}\n\nexport function formatInstallWriteFailure(\n context: InstallWriteFailureContext\n): string {\n const lines = [\n `Could not install ${context.templateName} skill for ${context.agent} at ${context.filePath}.`,\n \"\",\n isInstallPermissionError(context.error)\n ? \"The destination is not writable from the current shell.\"\n : \"The CLI could not create or write the destination file.\",\n `Failure: ${formatErrorSummary(context.error)}`,\n \"\",\n ];\n const nameFlag =\n context.installName === context.templateName\n ? \"\"\n : ` --name ${context.installName}`;\n\n if (context.personal) {\n lines.push(\n `Personal installs write under your home directory. Check permissions for ${context.dir}.`,\n \"\",\n \"Try again after fixing permissions:\",\n ` ${command} skill install ${context.templateName}${nameFlag} --agent ${context.agent} --personal`,\n \"\",\n \"Or run from a writable project directory and install without --personal.\"\n );\n } else {\n lines.push(\n `Project installs write under the current directory (${context.cwd}).`,\n \"Run from a writable project folder, or use --personal to install under your home directory.\",\n \"\",\n \"Try:\",\n \" cd <writable-project>\",\n ` ${command} skill install ${context.templateName}${nameFlag} --agent ${context.agent}`,\n ` ${command} skill install ${context.templateName}${nameFlag} --agent ${context.agent} --personal`\n );\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * A custom install name becomes a directory segment and the frontmatter\n * `name:`, so it must be a single safe path component: word characters and\n * hyphens only, no separators, no `..`, no leading dot.\n */\nexport function isValidInstallName(value: string): boolean {\n return /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value);\n}\n","export type SkillTemplate = {\n name: string;\n description: string;\n version: string;\n render: () => string;\n /**\n * Renderers for past versions of this skill, keyed by semver.\n * When bumping `version` + `render`, move the previous render fn in here\n * under its old version string so `canary skill diff` can reproduce it.\n */\n previousVersions?: Record<string, () => string>;\n};\n\nexport const issueLogXrefTemplate: SkillTemplate = {\n name: \"issue-log-xref\",\n description:\n \"Cross-reference Canary issues with server logs to find root causes\",\n version: \"1.0.0\",\n render: () => `---\nname: issue-log-xref\nversion: 1.0.0\ndescription: Cross-reference Canary QA issues with server logs to identify root causes. Use when investigating why a test failed, correlating browser errors with backend logs, or debugging issues found by Canary.\nallowed-tools: Bash(canary issues:*), Bash(canary login:*), Grep, Read\n---\n\n# Issue Log Cross-Reference\n\nCross-reference Canary-detected issues with server logs to identify root causes, correlate errors, and provide actionable debugging context.\n\n## Prerequisites\n\n- \\`canary\\` CLI installed and authenticated (\\`canary login\\`)\n- Access to server logs (see Log Source Configuration below)\n\n## Workflow\n\n### 1. Fetch issues from Canary\n\nList recent issues to find ones worth investigating:\n\n\\`\\`\\`bash\ncanary issues list --format markdown\n\\`\\`\\`\n\nUse filters to narrow down:\n\n\\`\\`\\`bash\ncanary issues list --severity high --status open --format markdown\n\\`\\`\\`\n\n### 2. Get issue details\n\nOnce you identify an issue, fetch its full diagnostics:\n\n\\`\\`\\`bash\ncanary issues get <issue-id> --format markdown\n\\`\\`\\`\n\nNote the following from the issue details:\n- **Timestamps** — when the issue was detected\n- **URLs / endpoints** — which pages or API routes were involved\n- **Error messages** — any visible error text captured in screenshots or DOM\n- **HTTP status codes** — failed network requests\n\n### 3. Access server logs\n\n<!-- ============================================================\n LOG SOURCE CONFIGURATION\n\n Replace {{LOG_SOURCE_INSTRUCTIONS}} below with instructions\n specific to your infrastructure. The AI agent reading this\n skill will use these instructions to fetch logs.\n\n Examples:\n\n **AWS CloudWatch:**\n Query CloudWatch Logs Insights for the relevant log group:\n \\`\\`\\`bash\n aws logs filter-log-events \\\\\n --log-group-name /ecs/my-api \\\\\n --start-time <epoch-ms> \\\\\n --end-time <epoch-ms> \\\\\n --filter-pattern \"<error-text>\"\n \\`\\`\\`\n\n **Local log files:**\n Search local log files for matching entries:\n \\`\\`\\`bash\n grep -i \"<error-text>\" /var/log/my-app/*.log\n \\`\\`\\`\n\n **Datadog:**\n Use the Datadog CLI or API to query logs:\n \\`\\`\\`bash\n dog logs list --query \"service:my-api status:error\" \\\\\n --from <ISO-timestamp> --to <ISO-timestamp>\n \\`\\`\\`\n\n **kubectl (Kubernetes):**\n Fetch pod logs for the relevant service:\n \\`\\`\\`bash\n kubectl logs -l app=my-api --since=1h | grep \"<error-text>\"\n \\`\\`\\`\n============================================================ -->\n\n{{LOG_SOURCE_INSTRUCTIONS}}\n\n### 4. Cross-reference and correlate\n\nMatch the Canary issue with log entries using these correlation points:\n\n- **Timestamps** — find log entries within a few seconds of the issue detection time\n- **Error messages** — search logs for the same error text shown in the issue\n- **HTTP status codes** — look for 4xx/5xx responses matching the failed requests\n- **URLs / routes** — filter logs by the endpoint or page path from the issue\n- **Stack traces** — identify the code path that produced the error\n- **Request IDs** — if your app uses correlation/request IDs, trace the full request lifecycle\n\n## Analysis Guidelines\n\nWhen presenting findings:\n\n1. **State the match confidence** — clear match, likely match, or circumstantial\n2. **Show the timeline** — lay out events in chronological order across both sources\n3. **Identify the root cause** — distinguish between the symptom (what Canary caught) and the cause (what the logs reveal)\n4. **Suggest next steps** — point to the specific code, service, or configuration that needs attention\n5. **Note gaps** — if logs are missing or incomplete, say so explicitly rather than speculating\n`,\n};\n","import { WORKFLOW_GUIDE_CONCEPT_SECTIONS } from '@chatsdet/content/workflow-guide';\n\n/** Pull a shared workflow-guide section's body by slug (single source of truth). */\nconst guideSection = (slug: string): string =>\n WORKFLOW_GUIDE_CONCEPT_SECTIONS.find((s) => s.slug === slug)?.content.trimEnd() ?? '';\n\nexport const renderBrowserTestingCurrentWorkflowAuthoring =\n (): string => `## Creating Tests from Browser Exploration\n\nAfter exploring an app via \\`canary session\\`, you can persist what you discovered as a reusable test workflow.\n\n### Explore → Author → Create flow\n\n1. **Explore**: Use \\`canary session\\` to navigate, snapshot, and interact with the app\n2. **Author**: Construct workflow JSON with nodes and playbook steps based on what was observed\n3. **Create**: Pipe JSON to \\`canary workflow create\\`\n4. **Verify**: Check with \\`canary workflow get <id>\\`\n\n### What a strong action node looks like\n\nThe altitude guidance below is the shared source of truth (identical to \\`canary workflow guide action-nodes\\` and the Flow Designer):\n\n${guideSection('action-nodes')}\n\n### Authoring nodes in Cofactor JSON\n\n- Node types: \\`login\\` (authentication), \\`navigate\\` (go to URL), \\`action\\` (interact with elements), \\`assertion\\` (verify standalone page state), \\`end\\` (terminal node)\n- Every action node **must** have a \\`customActionTitle\\` — a short (3-8 word) title naming the step's goal\n- **Prefer inline assertions** on action nodes over separate assertion nodes. Add \\`inlineAssertions\\` to verify the outcome right after the action completes. Use separate \\`assertion\\` nodes only for standalone page-level checks that don't belong to an action\n- Inline assertion format: \\`{ \"condition\": \"...\", \"severity\": \"fatal\" | \"fail\" | \"warn\" }\\` (fatal = halt the test now, fail = mark run failed but continue, warn = record only). **Do not author an \\`id\\` field** — the server stamps a UUID on persist. Hand-rolled UUIDs (especially placeholders like \\`a1b2c3d4-...\\`) are rejected and replaced.\n\n`;\n","export const renderBrowserTestingSections = (sections: readonly string[]): string =>\n sections.join('');\n","export const renderBrowserTestingFrontmatter = (version: string): string => `---\nname: browser-testing\nversion: ${version}\ndescription: Control a local browser via the Canary CLI to test web applications interactively. Use when the user asks to test, browse, interact with, or verify a web application using canary browser sessions.\nallowed-tools: Bash(canary session:*), Bash(canary login:*), Bash(canary workflow:*), Bash(canary credential:*), Read\n---\n\n`;\n\nexport const renderBrowserTestingSessionGuide = (): string => `# Browser Testing with Canary\n\nUse the \\`canary session\\` CLI to launch and control a local browser for testing web applications. You interact with pages through **snapshots** (accessibility tree + screenshot), then issue commands to click, type, navigate, and assert.\n\n## Prerequisites\n\n- \\`canary\\` CLI installed and authenticated (\\`canary login\\`)\n- Run \\`canary session --help\\` for the full command reference\n\n## Environments & Authentication\n\nCanary credentials are stored remotely and belong to a **property** (an app with a base URL). When the user asks you to test, determine the environment:\n\n### Remote / Deployed environments (default)\n\nCredentials are pre-configured with storage state. Just use \\`--credential\\` to load one:\n\n\\`\\`\\`bash\n# Interactive picker — shows credential name, property name, and base URL\ncanary session start --credential\n\n# By name\ncanary session start --credential \"Admin User\" --url https://staging.example.com\n\\`\\`\\`\n\n### Local development\n\nCredentials stored in Canary won't work against localhost because session cookies are bound to the remote domain. When testing a local dev server:\n\n1. **Ask the user to log in manually.** Start a session without credentials and tell them to authenticate in the browser:\n\n\\`\\`\\`bash\ncanary session start --url http://localhost:5173\n\\`\\`\\`\n\nThen tell the user: \"I've opened a browser to your local app. Please log in, and let me know when you're ready for me to continue.\"\n\n2. **Wait for confirmation** before proceeding with testing.\n\n3. Alternatively, if the user has a **local storage state file**, use it:\n\n\\`\\`\\`bash\ncanary session start --storage-state ./local-auth.json --url http://localhost:5173\n\\`\\`\\`\n\n**Rule:** If the URL is localhost or 127.0.0.1, do NOT use \\`--credential\\` — it will download remote session state that won't work locally. Instead, prompt the user to log in.\n\n## Core Workflow\n\nThe fundamental loop is: **snapshot → read → act → snapshot → verify**.\n\n### 1. Start a session\n\n\\`\\`\\`bash\n# Start a headed browser (you can watch it)\ncanary session start --url https://your-app.com\n\n# Start with a saved credential (interactive picker shows property + base URL)\ncanary session start --credential\n\n# Start with a specific credential by name\ncanary session start --credential \"Admin User\" --url https://your-app.com\n\n# Load a credential into an already-running session\ncanary session load-credential\n\\`\\`\\`\n\n### 2. Take a snapshot to see the page\n\nSnapshots are your primary way to understand what's on the page. They return an **accessibility tree** with element references (refs) and a **screenshot**.\n\n\\`\\`\\`bash\n# Full snapshot: accessibility tree + screenshot\ncanary session snapshot\n\n# Search for specific elements (fastest way to find what you need)\ncanary session snapshot --search \"Submit\"\ncanary session snapshot --search \"Email|Password\"\n\n# Expand a collapsed section (use the ref shown in the tree, e.g. [e50])\ncanary session snapshot --expand e50\n\n# Screenshot only (useful for visual verification)\ncanary session snapshot --mode screenshot\n\n# Tree only (useful when you need ref details, no image)\ncanary session snapshot --mode tree\n\\`\\`\\`\n\n**Reading snapshot output:**\n\nThe accessibility tree shows elements with refs like \\`[ref=e15]\\`. Use these refs in subsequent commands. The tree is structured to show the page hierarchy — forms, buttons, links, headings, etc.\n\nWhen you use \\`--search\\`, matching elements are highlighted in the output and on the screenshot. Search is OR-matched and case-insensitive. Use search to **locate** elements, not to validate visual states — search overlays can obscure subtle UI changes.\n\nLarge sections of the tree may be collapsed (shown as e.g. \\`(127 elements - use expand=\"e50\" to see content)\\`). Use \\`--expand <ref>\\` to reveal the full contents of a collapsed section.\n\n### 3. Interact with the page\n\nAlways reference elements by their **ref** from the snapshot.\n\n\\`\\`\\`bash\n# Click an element\ncanary session click --ref e15 --element \"Submit button\"\n\n# Type into an input field\ncanary session type --ref e7 --text \"user@example.com\" --element \"Email input\"\n\n# Type and submit (presses Enter after typing)\ncanary session type --ref e7 --text \"search query\" --element \"Search box\" --submit\n\n# Fill multiple form fields at once\ncanary session fill --fields '[{\"ref\":\"e3\",\"value\":\"John\"},{\"ref\":\"e4\",\"value\":\"john@example.com\"}]'\n\n# Select a dropdown option\ncanary session select --ref e12 --value \"admin\" --element \"Role dropdown\"\n\n# Press a keyboard key\ncanary session press --key Enter\ncanary session press --key Escape\ncanary session press --key ArrowDown\n\n# Hover to reveal hidden content (tooltips, dropdowns)\ncanary session hover --ref e8 --element \"User menu\"\n\\`\\`\\`\n\n### 4. Navigate\n\n\\`\\`\\`bash\ncanary session navigate --url https://your-app.com/settings\ncanary session back\n\\`\\`\\`\n\n### 5. Scroll\n\n\\`\\`\\`bash\n# Scroll down the page\ncanary session scroll --direction down\n\n# Scroll with more intensity (1-10, default 3)\ncanary session scroll --direction down --amount 8\n\n# Scroll up\ncanary session scroll --direction up\n\\`\\`\\`\n\n### 6. Verify results\n\nAfter every action, take a snapshot to verify the result:\n\n\\`\\`\\`bash\n# Check what happened after clicking submit\ncanary session snapshot\n\n# Search for a success message\ncanary session snapshot --search \"Success|saved\"\n\n# Check for error messages\ncanary session snapshot --search \"Error|failed|invalid\"\n\n# Check console for JavaScript errors\ncanary session console --only-errors\n\n# Check network requests for failed API calls\ncanary session network\n\\`\\`\\`\n\n## Session Management\n\n\\`\\`\\`bash\n# List all active sessions\ncanary session list\n\n# Check session details\ncanary session status\n\n# Stop a session\ncanary session stop\n\n# Stop all sessions\ncanary session stop --all\n\n# When multiple sessions are active, specify which one\ncanary session snapshot --session s1\ncanary session click --ref e5 --element \"Button\" --session s2\n\\`\\`\\`\n\n## Advanced Techniques\n\n### Waiting for page changes\n\n\\`\\`\\`bash\n# Wait for text to appear (after navigation or async action)\ncanary session wait --text \"Dashboard loaded\"\n\n# Wait for text to disappear (loading spinner)\ncanary session wait --text \"Loading...\"\n\n# Wait a fixed time (use sparingly)\ncanary session wait --time 2\n\\`\\`\\`\n\n### Coordinate-based clicking\n\nWhen ref-based clicking doesn't work (overlays, canvas elements), use coordinates. First take a snapshot, look at the screenshot, estimate coordinates, then click:\n\n\\`\\`\\`bash\n# Click at specific coordinates\ncanary session click --x 450 --y 300 --element \"Canvas element\"\n\\`\\`\\`\n\n### Tab management\n\n\\`\\`\\`bash\ncanary session tabs --action list\ncanary session tabs --action new\ncanary session tabs --action select --index 0\ncanary session tabs --action close --index 1\n\\`\\`\\`\n\n### Evaluating JavaScript\n\n\\`\\`\\`bash\ncanary session evaluate --js \"() => document.title\"\ncanary session evaluate --js \"() => window.location.href\"\ncanary session evaluate --js \"() => document.querySelectorAll('.error').length\"\n\\`\\`\\`\n\n### Taking labeled screenshots\n\n\\`\\`\\`bash\n# Take a labeled screenshot for later reference\ncanary session screenshot --label \"before-submit\"\n\n# Full page screenshot\ncanary session screenshot --full-page --label \"full-page-state\"\n\\`\\`\\`\n\n### File downloads\n\n\\`\\`\\`bash\n# List downloaded files\ncanary session evaluate --js \"() => 'trigger download'\"\n# ... after download completes:\ncanary session list-downloads\ncanary session read-download\n\\`\\`\\`\n\n## Testing Guidelines\n\n1. **Always snapshot after actions** — never assume an action succeeded. Take a snapshot to verify.\n2. **Use search to locate elements** — \\`--search \"Submit\"\\` is faster than scanning the full tree.\n3. **Use refs, not coordinates** — ref-based interaction is more reliable. Only fall back to coordinates when refs fail.\n4. **Check for errors** — after form submissions or navigation, check both the page content and console/network for errors.\n5. **Wait for async operations** — if an action triggers an API call, use \\`wait --text\\` for the expected result rather than fixed delays.\n6. **Load credentials for authenticated testing** — use \\`canary session start --credential\\` or \\`canary session load-credential\\` to test as specific users.\n7. **Report what you find** — describe what you see in snapshots, what worked, what failed, and include relevant refs or error messages.\n\n## Improving Testability (Local Development)\n\nWhen testing locally, you have access to the source code — use this advantage. If the accessibility tree is confusing or elements are hard to target, **diagnose why** and suggest concrete improvements to the user.\n\n### When to investigate\n\nIf you encounter any of these signals, dig deeper before moving on:\n- Multiple elements with identical or vague labels (e.g., several \"Button\" or \"div\" entries)\n- Interactive elements missing from the accessibility tree entirely\n- Custom components that render as opaque containers with no semantic children\n- Difficulty distinguishing between similar repeated elements (e.g., rows in a table)\n- Elements you can see in the screenshot but can't find in the tree\n\n### How to investigate\n\n1. **Use JavaScript evaluation** to inspect the actual DOM structure:\n \\`\\`\\`bash\n canary session evaluate --js \"() => document.querySelector('[data-testid]')?.outerHTML\"\n canary session evaluate --js \"() => document.querySelectorAll('button').length\"\n canary session evaluate --js \"() => [...document.querySelectorAll('button')].map(b => ({ text: b.textContent?.trim(), role: b.getAttribute('role'), ariaLabel: b.getAttribute('aria-label') }))\"\n \\`\\`\\`\n\n2. **Read the component source code** — find and read the relevant component or template file to understand why the accessibility tree looks the way it does.\n\n3. **Compare screenshot vs tree** — take a screenshot-only snapshot and a tree-only snapshot. If you can see something visually but it's missing or ambiguous in the tree, that's a testability gap.\n\n### What to suggest\n\nWhen you find testability gaps, suggest specific fixes to the user. Frame suggestions as improvements that help both automated testing and human accessibility:\n\n- **Missing labels**: \"The 'Save' buttons in each card are indistinguishable in the accessibility tree. Adding \\`aria-label=\"Save {itemName}\"\\` or \\`data-testid=\"save-{itemId}\"\\` would make them individually targetable.\"\n- **Non-semantic elements**: \"This clickable \\`<div>\\` doesn't appear as a button in the tree. Changing it to \\`<button>\\` or adding \\`role=\"button\"\\` would fix this.\"\n- **Missing headings/landmarks**: \"This page section has no heading — screen readers and test agents can't tell what it contains. Adding an \\`<h2>\\` or \\`aria-label\\` to the \\`<section>\\` would help.\"\n- **Unlabeled form fields**: \"These inputs have placeholder text but no associated \\`<label>\\`. Adding \\`<label htmlFor=\"...\">\\` or \\`aria-label\\` would make them reliably targetable.\"\n- **Repeated generic elements**: \"The table rows are hard to distinguish. Adding \\`data-testid=\"row-{id}\"\\` or meaningful \\`aria-label\\` values to each row would make them individually addressable.\"\n\n**Tone**: These are suggestions, not demands. Present them as quick wins that improve both test reliability and accessibility. Group them at the end of your testing report rather than interrupting the testing flow.\n\n`;\n","export const renderBrowserTestingWorkflowDetails =\n (): string => `### Playbook step authoring guidance\n\n- Use **semantic targets** from the accessibility tree (button text, field labels, placeholder text) — NOT refs or CSS selectors\n- Target format: describe as a human would (\"Submit button\", \"Email input field\", \"Status dropdown\")\n- For \\`fill\\` actions: include \\`params: { \"value\": \"...\" }\\`\n- **Always prefer macros over hardcoded test data.** Macros generate fresh values each run, preventing flaky tests from stale or colliding data. Never hardcode emails, names, phone numbers, or dates when a macro can generate them.\n- Prefix test data with \"QA Test\" for identifiability (e.g., \\`\"QA Test $FIRST_NAME()\"\\`)\n- Valid actions: \\`click\\`, \\`fill\\`, \\`fill_form\\`, \\`select\\`, \\`navigate\\`, \\`wait\\`, \\`scroll\\`, \\`hover\\`, \\`upload\\`, \\`verify\\`, \\`press_key\\`, \\`drag\\`, \\`resize\\`, \\`capture\\`, \\`extract_table\\`, \\`python_execute\\`, \\`verify_download\\`, \\`verify_download_content\\`, \\`screenshot\\`, \\`agent_loop\\`\n\n### Using macros and variables\n\nMacros are resolved at run time — each execution gets fresh values, making tests repeatable and collision-free.\n\n**Available macros:**\n\n| Macro | Args | Output | Example |\n|-------|------|--------|---------|\n| \\`$EMAIL()\\` | — | Unique test email | \\`test-xk9mq2@example-test.com\\` |\n| \\`$FIRST_NAME()\\` | — | Random first name | \\`Jordan\\` |\n| \\`$LAST_NAME()\\` | — | Random last name | \\`Chen\\` |\n| \\`$PHONE()\\` | — | US phone (555 prefix) | \\`+1-555-382-7491\\` |\n| \\`$UUID()\\` | — | Random UUID v4 | \\`a1b2c3d4-...\\` |\n| \\`$RANDOM_INT(min, max)\\` | 2 ints | Random integer (inclusive) | \\`$RANDOM_INT(100,999)\\` → \\`427\\` |\n| \\`$RANDOM_STRING(length)\\` | 1 int (1–1000) | Alphanumeric string | \\`$RANDOM_STRING(8)\\` → \\`xK9mQ3bR\\` |\n| \\`$TODAY()\\` | — | Current date (YYYY-MM-DD) | \\`2026-04-06\\` |\n| \\`$DATE(days)\\` | 1 int | Date offset from today | \\`$DATE(-7)\\` → last week |\n| \\`$NOW()\\` | — | ISO 8601 timestamp | \\`2026-04-06T14:30:00.000Z\\` |\n| \\`$TIMESTAMP()\\` | — | Unix milliseconds | \\`1771520400000\\` |\n| \\`$SEQUENCE(\"name\")\\` | counter name | Auto-incrementing per run | \\`1\\`, \\`2\\`, \\`3\\`... |\n\n**When to use macros:**\n- Email fields → \\`$EMAIL()\\`\n- Name fields → \\`$FIRST_NAME()\\` / \\`$LAST_NAME()\\`\n- Amounts, quantities, identifiers → \\`$RANDOM_INT()\\` or \\`$RANDOM_STRING()\\`\n- Date fields → \\`$TODAY()\\` / \\`$DATE()\\`\n- Sequential numbering → \\`$SEQUENCE(\"name\")\\`\n- Macros combine inline: \\`\"QA Test $FIRST_NAME() $LAST_NAME()\"\\`, \\`\"order-$RANDOM_STRING(6)\"\\`\n\n**Variables (\\`$var.name\\`):**\n- Steps can reference data captured from earlier steps using \\`$var.name\\`\n- Variable values are extracted during execution and available to subsequent steps\n- Use step-qualified refs when multiple steps set the same variable: \\`$var.Step2_Create_Client.name\\`\n\n### Credential selection\n\n**Always use \\`credentialId\\` (UUID) in the login node — never just \\`credentialName\\`.**\n\n1. **List available credentials** before authoring:\n \\`\\`\\`bash\n canary credential list --json\n \\`\\`\\`\n This returns each credential's \\`id\\`, \\`name\\`, \\`isDefault\\`, \\`propertyName\\`, and environment info.\n\n2. **Pick the right credential**:\n - Prefer the **default credential** (\\`isDefault: true\\`)\n - **Never** use a credential with \"local\" in the name — it won't work in deployed environments\n - If multiple non-local credentials exist and you're unsure which to use, **ask the user**\n\n3. **Set both \\`credentialId\\` and \\`credentialName\\`** in the login node's \\`configJson\\`:\n \\`\\`\\`json\n { \"credentialId\": \"4f6db838-...\", \"credentialName\": \"QA User\" }\n \\`\\`\\`\n\n4. **If no matching credential exists**, warn the user that one needs to be created first in the web app.\n\nThe CLI will auto-resolve credentials if \\`credentialId\\` is missing, but it may fail if the choice is ambiguous. Always specify the ID explicitly for reliable uploads.\n\n### Approving and promoting workflows\n\nNew workflows start as \\`draft\\`. Making a test run in suite regressions is a two-step,\nexplicit flow on two orthogonal axes:\n\n- **Approve** (\\`canary workflow approve <id> --yes\\`) — the approval axis: a human verified the test checks the right thing (\\`draft\\` → \\`approved\\`).\n- **Promote** (\\`canary workflow promote <id>\\`) — the promotion axis: an approved test is included in suite runs. \\`canary workflow pause <id>\\` excludes it again.\n- Reliability is tracked automatically by the workflow's \\`health\\` (starts \\`unverified\\`); a promoted flow that keeps failing becomes \\`degraded\\` and is skipped in suites until edited or re-enabled.\n\n### Usage\n\n\\`\\`\\`bash\n# Create (starts as draft)\necho '<workflow JSON>' | canary workflow create --from-stdin --property \"My App\"\n\n# Then run, approve, and promote so it's included in suite runs\ncanary workflow run <workflowId> --stream\ncanary workflow approve <workflowId> --yes\ncanary workflow promote <workflowId>\n\n# From file\ncanary workflow create --from-file workflow.json\n\\`\\`\\`\n\n### Example workflow JSON\n\n\\`\\`\\`json\n{\n \"name\": \"Verify user can create an invoice\",\n \"description\": \"Tests the invoice creation flow end-to-end\",\n \"nodes\": [\n {\n \"nodeType\": \"login\",\n \"configJson\": {\n \"credentialId\": \"4f6db838-16be-49e8-8887-8d0be1c83a87\",\n \"credentialName\": \"QA User\"\n }\n },\n {\n \"nodeType\": \"navigate\",\n \"configJson\": { \"pageUrl\": \"/invoices\", \"pageTitle\": \"Invoices\" }\n },\n {\n \"nodeType\": \"action\",\n \"configJson\": {\n \"customActionTitle\": \"Create a new invoice\",\n \"actionDescription\": \"Fill out the new invoice form and save\",\n \"playbookSteps\": [\n { \"order\": 1, \"action\": \"click\", \"target\": \"New Invoice button\" },\n { \"order\": 2, \"action\": \"fill\", \"target\": \"Client name field\", \"params\": { \"value\": \"QA Test $FIRST_NAME()\" } },\n { \"order\": 3, \"action\": \"fill\", \"target\": \"Amount field\", \"params\": { \"value\": \"$RANDOM_INT(100,999)\" } },\n { \"order\": 4, \"action\": \"click\", \"target\": \"Save button\" }\n ],\n \"inlineAssertions\": [\n {\n \"condition\": \"Success message 'Invoice created' is visible and the new invoice appears in the list\",\n \"severity\": \"fail\"\n }\n ]\n }\n }\n ]\n}\n\\`\\`\\`\n\n### Updating existing workflows\n\nUse \\`canary workflow sync\\` to replace a workflow's nodes. It accepts the same\nsimple format as create — no edges, positions, or IDs needed:\n\n\\`\\`\\`bash\n# From stdin\necho '{\"nodes\": [...]}' | canary workflow sync <workflowId> --from-stdin\n\n# From file\ncanary workflow sync <workflowId> --from-file updated.json\n\n# Create a proposal for review instead of applying directly\ncanary workflow sync <workflowId> --from-file updated.json --propose\n\\`\\`\\`\n\nWhen using \\`--propose\\` on an existing workflow, fetch the current state first\nand reuse each node's \\`id\\` for steps you keep — only omit \\`id\\` for genuinely\nnew steps. This is the best way to ensure the diff stays accurate so reviewers\nsee only the fields that actually changed:\n\n\\`\\`\\`bash\n# Round-trip pattern for proposals\ncanary workflow get <workflowId> --format json > current.json\n# edit current.json: change configJsons, keep ids you're not replacing\ncanary workflow sync <workflowId> --from-file current.json --propose\n\\`\\`\\`\n\n### Generating API sequences\n\nConvert a browser-based workflow to a fast API sequence using its latest successful run:\n\n\\`\\`\\`bash\n# Generate from the workflow's latest run\ncanary workflow generate-api-sequence <workflowId>\n\n# With additional guidance\ncanary workflow generate-api-sequence <workflowId> --guidance \"Focus on the create endpoint\"\n\n# JSON output\ncanary workflow generate-api-sequence <workflowId> --json\n\\`\\`\\`\n\n### Reference\n\nRun \\`canary workflow guide\\` for the full authoring reference:\n\n\\`\\`\\`bash\ncanary workflow guide # All sections\ncanary workflow guide node-types # Available node types\ncanary workflow guide macros # Dynamic test data ($EMAIL, $RANDOM_STRING, etc.)\ncanary workflow guide playbook # Playbook steps and caching\ncanary workflow guide seed-workflows # Seed workflow patterns\ncanary workflow guide assertions # Inline and standalone assertions\n\\`\\`\\`\n`;\n","import { renderBrowserTestingCurrentWorkflowAuthoring } from './browser-testing/current-workflow-authoring.js';\nimport { renderBrowserTestingSections } from './browser-testing/render-sections.js';\nimport {\n renderBrowserTestingFrontmatter,\n renderBrowserTestingSessionGuide,\n} from './browser-testing/shared-session-sections.js';\nimport { renderBrowserTestingWorkflowDetails } from './browser-testing/shared-workflow-sections.js';\n\nexport const browserTestingRenderCurrent = () =>\n renderBrowserTestingSections([\n renderBrowserTestingFrontmatter('1.1.0'),\n renderBrowserTestingSessionGuide(),\n renderBrowserTestingCurrentWorkflowAuthoring(),\n renderBrowserTestingWorkflowDetails(),\n ]);\n","export const renderBrowserTestingV1WorkflowAuthoring =\n (): string => `## Creating Tests from Browser Exploration\n\nAfter exploring an app via \\`canary session\\`, you can persist what you discovered as a reusable test workflow.\n\n### Explore → Author → Create flow\n\n1. **Explore**: Use \\`canary session\\` to navigate, snapshot, and interact with the app\n2. **Author**: Construct workflow JSON with nodes and playbook steps based on what was observed\n3. **Create**: Pipe JSON to \\`canary workflow create\\`\n4. **Verify**: Check with \\`canary workflow get <id>\\`\n\n### Node authoring guidance\n\n- Group related actions into single action nodes (one node per logical step, not per click)\n- Node types: \\`login\\` (authentication), \\`navigate\\` (go to URL), \\`action\\` (interact with elements), \\`assertion\\` (verify standalone page state), \\`end\\` (terminal node)\n- Every action node **must** have a \\`customActionTitle\\` — a short (3-8 word) human-readable title describing the step\n- **Prefer inline assertions** on action nodes over separate assertion nodes. Add \\`inlineAssertions\\` to verify outcomes right after the action completes. Use separate \\`assertion\\` nodes only for standalone page-level verifications (e.g., initial page state before any action)\n- Inline assertion format: \\`{ \"condition\": \"...\", \"severity\": \"fatal\" | \"fail\" | \"warn\" }\\` (fatal = halt the test now, fail = mark run failed but continue, warn = record only). **Do not author an \\`id\\` field** — the server stamps a UUID on persist. Hand-rolled UUIDs (especially placeholders like \\`a1b2c3d4-...\\`) are rejected and replaced.\n\n`;\n","import { renderBrowserTestingSections } from './browser-testing/render-sections.js';\nimport {\n renderBrowserTestingFrontmatter,\n renderBrowserTestingSessionGuide,\n} from './browser-testing/shared-session-sections.js';\nimport { renderBrowserTestingV1WorkflowAuthoring } from './browser-testing/v1-workflow-authoring.js';\nimport { renderBrowserTestingWorkflowDetails } from './browser-testing/shared-workflow-sections.js';\n\n// Frozen v1.0.0 render retained as section renderers so `cofactor skill diff` / install can reproduce it.\nexport const browserTestingRenderV1_0_0 = () =>\n renderBrowserTestingSections([\n renderBrowserTestingFrontmatter('1.0.0'),\n renderBrowserTestingSessionGuide(),\n renderBrowserTestingV1WorkflowAuthoring(),\n renderBrowserTestingWorkflowDetails(),\n ]);\n","import type { SkillTemplate } from './issue-log-xref.js';\nimport { browserTestingRenderCurrent } from './browser-testing-current.js';\nimport { browserTestingRenderV1_0_0 } from './browser-testing-v1-0-0.js';\n\nexport const browserTestingTemplate: SkillTemplate = {\n name: 'browser-testing',\n description: 'Use the Canary CLI to control a browser for testing web applications',\n version: '1.1.0',\n render: browserTestingRenderCurrent,\n previousVersions: {\n '1.0.0': browserTestingRenderV1_0_0,\n },\n};\n","import type { SkillTemplate } from './issue-log-xref.js';\n\nexport const agentTasksTemplate: SkillTemplate = {\n name: 'agent-tasks',\n description: 'Manage trigger-based agent tasks for deferred work items',\n version: '1.0.0',\n render: () => `---\nname: agent-tasks\nversion: 1.0.0\ndescription: Manage trigger-based agent tasks via the Canary CLI. Use when the user asks to create a task, schedule post-deploy work, set up reminders for flag cleanup, track knob deprecation, or manage deferred work items triggered by system events.\nallowed-tools: Bash(canary task:*), Read, Grep, Glob\n---\n\n# Agent Tasks with Canary\n\nUse \\`canary task\\` to create and manage **trigger-based work items** — deferred tasks that become actionable when a system event fires (deploy, flag change, schedule, etc.).\n\n## Prerequisites\n\n- \\`canary\\` CLI installed and authenticated (\\`canary login\\`)\n- Your account must be a **superadmin** — agent tasks are a superadmin-only capability\n- Run \\`canary task --help\\` for the full command reference\n\n## Quick Reference\n\n\\`\\`\\`bash\n# Create a task\ncanary task create --title \"Remove feature flag\" \\\\\n --description \"Delete COOL_FEATURE flag and all gating code\" \\\\\n --trigger flag-deleted --flag COOL_FEATURE\n\n# List tasks\ncanary task list # all tasks\ncanary task list --status waiting # waiting for trigger\ncanary task list --status actionable # ready to work on\ncanary task list --trigger production-deploy # by trigger type\n\n# Manage tasks\ncanary task get <id> # view details + event history\ncanary task update <id> --title \"New title\" # update task fields\ncanary task claim <id> # mark in progress\ncanary task complete <id> # mark done\ncanary task complete <id> --commit abc123 # done, link to resolution commit\ncanary task cancel <id> # cancel\ncanary task trigger <id> # manually fire trigger\n\\`\\`\\`\n\n## Trigger Types\n\n| Type | Fires when... | Auto-fired? | Required flag |\n|------|---------------|-------------|---------------|\n| \\`production-deploy\\` | Code deployed to production | **Yes** | — |\n| \\`flag-deprecated\\` | Feature flag set to deprecated | Yes | \\`--flag <name>\\` |\n| \\`flag-cleanup\\` | Feature flag set to ready_for_cleanup | Yes | \\`--flag <name>\\` |\n| \\`flag-deleted\\` | Feature flag deleted | Yes | \\`--flag <name>\\` |\n| \\`knob-deprecated\\` | Knob set to deprecated | Yes | \\`--knob <key>\\` |\n| \\`knob-cleanup\\` | Knob set to ready_for_cleanup | Yes | \\`--knob <key>\\` |\n| \\`knob-deleted\\` | Knob deleted | Yes | \\`--knob <key>\\` |\n| \\`scheduled\\` | A date/time is reached | Yes | \\`--scheduled-date <ISO>\\` |\n| \\`pr-merged\\` | A specific PR is merged | Yes | \\`--pr <number>\\` |\n| \\`immediate\\` | Immediately (no waiting) | N/A | — |\n| \\`manual\\` | Manually triggered via CLI | N/A | — |\n\n**Note:** \\`pr-merged\\` tasks are scoped to the linked repository selected by \\`--repo\\`, \\`--role\\`, or \\`--repo-id\\`.\n\n## Task Lifecycle\n\n\\`\\`\\`\n ┌─── immediate ───► actionable\n │ │\n create ──────────┤ claim\n │ │\n └─── other types ──► waiting ──trigger──► actionable ──► in_progress ──► completed\n ├──► canceled\n └──► expired\n\\`\\`\\`\n\n- **waiting**: Created, waiting for its trigger event\n- **actionable**: Trigger fired (or immediate type), ready to be worked on\n- **in_progress**: Claimed by someone, actively being worked\n- **completed**: Done (optionally linked to a resolution commit)\n- **canceled** / **expired**: Terminated without completion\n\n## Common Workflows\n\n### Post-deploy cleanup (remove temporary code after next production deploy)\n\n\\`\\`\\`bash\ncanary task create \\\\\n --title \"Remove backwards-compat shim for widget API\" \\\\\n --description \"Old endpoint can be removed now that new endpoint is deployed.\" \\\\\n --trigger production-deploy \\\\\n --priority 1 \\\\\n --tag cleanup --tag api\n\\`\\`\\`\n\nThis task automatically becomes actionable after the next successful production deployment.\n\n### Flag removal after GA\n\nWhen a feature graduates from behind a flag:\n\n\\`\\`\\`bash\ncanary task create \\\\\n --title \"Clean up COOL_FEATURE flag gating code\" \\\\\n --description \"Feature is GA. Remove all gating checks and delete the constant.\" \\\\\n --trigger flag-deprecated --flag COOL_FEATURE \\\\\n --tag cleanup --tag feature-flags\n\\`\\`\\`\n\nAuto-fires when someone runs \\`canary feature-flag lifecycle COOL_FEATURE --stage deprecated\\`.\n\n### Knob deprecation follow-up\n\n\\`\\`\\`bash\ncanary task create \\\\\n --title \"Remove agent.truncation.enabled knob reads\" \\\\\n --description \"Replace all knob reads with the hardcoded final value.\" \\\\\n --trigger knob-deprecated --knob agent.truncation.enabled \\\\\n --tag cleanup\n\\`\\`\\`\n\n### Scheduled future work\n\n\\`\\`\\`bash\ncanary task create \\\\\n --title \"Rotate API signing keys\" \\\\\n --description \"Quarterly key rotation per security policy.\" \\\\\n --trigger scheduled --scheduled-date 2026-06-30T00:00:00Z \\\\\n --priority 2 --tag security\n\\`\\`\\`\n\n### Immediate task (starts actionable, no trigger wait)\n\n\\`\\`\\`bash\ncanary task create \\\\\n --title \"Fix type error in auth middleware\" \\\\\n --description \"Strict mode caught a missing null check. Needs immediate fix.\" \\\\\n --trigger immediate \\\\\n --priority 2 --assign dev@example.com\n\\`\\`\\`\n\n## Integration Points\n\n### Feature Flags → Tasks\n\nFlag lifecycle changes automatically fire matching task triggers:\n- \\`canary feature-flag lifecycle <name> --stage deprecated\\` → fires \\`flag-deprecated\\` tasks\n- \\`canary feature-flag lifecycle <name> --stage ready_for_cleanup\\` → fires \\`flag-cleanup\\` tasks\n- \\`canary feature-flag delete <name>\\` → fires \\`flag-deleted\\` tasks\n\n### Knobs → Tasks\n\nSame pattern as flags:\n- \\`canary knobs lifecycle <key> --stage deprecated\\` → fires \\`knob-deprecated\\` tasks\n- \\`canary knobs lifecycle <key> --stage ready_for_cleanup\\` → fires \\`knob-cleanup\\` tasks\n- \\`canary knobs delete <key>\\` → fires \\`knob-deleted\\` tasks\n\n### Production Deploys → Tasks\n\nThe deployment notifier Lambda fires \\`production-deploy\\` task triggers automatically on successful production deployments. Any waiting tasks with this trigger type transition to \\`actionable\\`.\n\n## Tips\n\n- \\`--commit\\` defaults to \\`git HEAD\\` — auto-detects the current commit\n- \\`--repo\\` is auto-selected if the org has a single linked repository\n- \\`--tag\\` is repeatable: \\`--tag cleanup --tag api --tag urgent\\`\n- \\`--description-file <path>\\` reads description from a file (useful for long markdown descriptions)\n- \\`--json\\` on any command returns structured JSON output for scripting\n- \\`--priority\\`: 0 = normal (default), 1 = high, 2 = critical\n- \\`--expires <ISO date>\\` sets an expiry after which the task auto-expires if not completed\n- Use \\`canary task trigger <id>\\` to manually fire any waiting task's trigger\n`,\n};\n","import type { SkillTemplate } from './issue-log-xref.js';\n\nexport const canaryBasicTemplate: SkillTemplate = {\n name: 'canary-basic',\n description: 'Learn the Canary CLI — commands, help, and common patterns',\n version: '1.0.0',\n render: () => `---\nname: canary-basic\nversion: 1.0.0\ndescription: Reference guide for the Canary CLI. Invoke when anyone mentions canary, canary CLI, or asks about CLI commands for testing, browser sessions, workflows, issues, or releases.\nallowed-tools: Read, Grep, Glob\n---\n\n# Canary CLI Guide\n\nThe \\`canary\\` CLI is a command-line tool for running tests, controlling browser sessions, managing workflows, and inspecting issues.\n\n## Install & Login\n\n\\`\\`\\`bash\n# Install globally\nnpm install -g @canaryai/cli\n# or\nbun add -g @canaryai/cli\n\n# Authenticate (opens browser)\ncanary login\n\n# Login to a specific org (for multi-org users)\ncanary login --org \"My Org\"\n\\`\\`\\`\n\n### Environment switching\n\n\\`\\`\\`bash\n# Production (default)\ncanary login\n\n# Dev\ncanary login --app-url https://app.dev.trycanary.ai --api-url https://api.dev.trycanary.ai\n\n# Local\ncanary login --app-url http://localhost:5173 --api-url http://localhost:3000\n\n# Or set the env var\nexport CANARY_API_URL=http://localhost:3000\n\\`\\`\\`\n\n---\n\n## Command Reference\n\n### Test Suites\n\n\\`\\`\\`bash\n# Trigger a test suite and stream results\ncanary test-suite run\ncanary test-suite run --tag smoke\ncanary test-suite run --property \"My App\" --environment staging --verbose\n\n# Query test suite results\ncanary test-suite list\ncanary test-suite get <id> --failures-only\ncanary test-suite diagnostics <workflowId> <runId>\ncanary test-suite steps <workflowId> <runId>\n\\`\\`\\`\n\nRun options: \\`--token\\`, \\`--property\\`, \\`--environment\\`, \\`--tag\\`, \\`--name-pattern\\`, \\`--verbose\\`\n\n---\n\n### Browser Sessions\n\nStart and control browser sessions for interactive testing.\n\n#### Session lifecycle\n\n\\`\\`\\`bash\ncanary session start # Start a new session\ncanary session start --credential \"admin\" # Start with a credential\ncanary session start --url https://example.com --headless\ncanary session list # List active sessions\ncanary session status # Show session details\ncanary session stop # Stop the current session\ncanary session stop --all # Stop all sessions\ncanary session load-credential # Load a credential into a running session\ncanary session allow-screenshots # Grant Claude auto-read for screenshots\n\\`\\`\\`\n\n#### Browser actions\n\n\\`\\`\\`bash\n# Navigation\ncanary session navigate --url https://example.com\ncanary session back\n\n# Observe the page\ncanary session snapshot # Get accessibility tree\ncanary session snapshot --mode screenshot # Get a screenshot\ncanary session snapshot --mode both # Tree + screenshot\ncanary session snapshot --search \"Login\" # Search for text\ncanary session snapshot --expand e5 # Expand a collapsed ref\ncanary session screenshot --full-page # Full-page screenshot\n\n# Interact with elements (use ref from snapshot)\ncanary session click --ref e12\ncanary session type --ref e8 --text \"hello\" --submit\ncanary session fill --fields '[{\"ref\":\"e1\",\"value\":\"user@example.com\"},{\"ref\":\"e2\",\"value\":\"pass123\"}]'\ncanary session select --ref e15 --value \"option-1\"\ncanary session hover --ref e3\ncanary session press --key Enter\ncanary session scroll --direction down --amount 3\n\n# Tabs\ncanary session tabs # List tabs\ncanary session tabs --action new # Open new tab\ncanary session tabs --action select --index 0 # Switch to tab\ncanary session tabs --action close # Close current tab\n\n# Debugging\ncanary session wait --text \"Success\" --timeout 5000\ncanary session console --only-errors # Show console messages\ncanary session network # Show network requests\ncanary session evaluate --js \"document.title\" # Run JavaScript\n\\`\\`\\`\n\nCommon options: \\`--session <id|name>\\` (target a specific session), \\`--json\\`, \\`--env\\`\n\n#### Control (for cloud-connected sessions)\n\n\\`\\`\\`bash\ncanary session take-control # Force CLI control (pauses cloud)\ncanary session resume-cloud # Resume cloud execution\n\\`\\`\\`\n\n---\n\n### Recording\n\nRecord browser interactions for creating test workflows.\n\n\\`\\`\\`bash\ncanary record\ncanary record --credential admin --url https://example.com\ncanary record --output ./recordings --no-upload # Save locally only\n\\`\\`\\`\n\nOptions: \\`--credential\\`, \\`--url\\`, \\`--output\\`, \\`--env\\`, \\`--no-upload\\`\n\n---\n\n### Workflows\n\nInspect and manage workflow definitions.\n\n\\`\\`\\`bash\n# List and search\ncanary workflow list\ncanary workflow list --search \"checkout\" --status approved --json\n\n# Get workflow definition\ncanary workflow get <workflowId> --format markdown\ncanary workflow get <workflowId> --json\n\n# Create from file or stdin (new workflows start as draft)\ncanary workflow create --from-file workflow.json\necho '<workflow JSON>' | canary workflow create --from-stdin --property \"My App\"\n\n# Approve (human-verified), then promote so suites run it\ncanary workflow approve <workflowId> --yes\ncanary workflow promote <workflowId>\n\n# Update workflow\ncanary workflow patch <workflowId> --name \"New Name\" --status approved\n\n# Run a workflow\ncanary workflow run <workflowId> --stream\n\n# Replace all nodes/edges\ncanary workflow sync <workflowId> --from-file updated.json\n\n# Authoring guide\ncanary workflow guide\ncanary workflow guide selectors\n\\`\\`\\`\n\nList filters: \\`--search\\`, \\`--flow-type\\` (standard|setup|seed|teardown), \\`--status\\` (draft|approved), \\`--page\\`, \\`--page-size\\`\n\nWorkflow statuses: \\`draft\\` = editable, not yet human-verified. \\`approved\\` = a human verified the test checks the right thing. Inclusion in regression runs is a separate axis: \\`canary workflow promote <id>\\` makes an approved test run in suites, and \\`canary workflow pause <id>\\` excludes it again. Reliability is tracked automatically by the \\`health\\` dimension — a flow that keeps failing in suites becomes \\`degraded\\` and is skipped (shown \"degraded — not run\") until it's edited or manually re-enabled.\n\n---\n\n### Issues\n\nSearch and inspect QA issues detected by Canary.\n\n\\`\\`\\`bash\n# List issues\ncanary issues list\ncanary issues list --severity high --status open --format markdown\ncanary issues list --search \"timeout\" --property-id <uuid>\n\n# Get issue details\ncanary issues get <issue-id>\ncanary issues get <issue-id> --format markdown\n\\`\\`\\`\n\nList options: \\`--search\\`, \\`--severity\\` (low|medium|high|unknown), \\`--status\\` (open|closed|not_a_bug), \\`--property-id\\`, \\`--page\\`, \\`--page-size\\`, \\`--json\\`, \\`--format markdown\\`\n\n---\n\n### Release QA (CI/CD)\n\nTrigger and monitor Release QA runs from CI pipelines.\n\n\\`\\`\\`bash\ncanary release trigger --property-id <uuid>\ncanary release status <run-id> --json\ncanary release run --property-id <uuid> --timeout 600 # Trigger and poll\n\\`\\`\\`\n\n---\n\n### Properties & Credentials\n\n\\`\\`\\`bash\ncanary property list # List properties and linked repos\ncanary credential list # List credentials with environment info\n\\`\\`\\`\n\n---\n\n### Superadmin Commands\n\nThese commands require superadmin access.\n\n\\`\\`\\`bash\n# Knobs (global runtime config)\ncanary knobs list\ncanary knobs get <key>\ncanary knobs set <key> <value> --type boolean|number|string\ncanary knobs toggle <key>\ncanary knobs delete <key>\ncanary knobs lifecycle <key> --stage <stage>\n\n# Feature flags (per-org gating)\ncanary feature-flag list\ncanary feature-flag create <name> --description \"...\"\ncanary feature-flag enable <name> --target-org <orgId>\ncanary feature-flag disable <name> --target-org <orgId>\ncanary feature-flag delete <name>\ncanary feature-flag lifecycle <name> --stage <stage>\n\n# Database (read-only)\ncanary psql \"SELECT * FROM knobs LIMIT 5\" --json\n\n# Redis (read-only)\ncanary redis \"GET some:key\" --json\n\n# Documentation pages\ncanary docs <sub-command>\n\n# Debug sessions\ncanary debug-session --env dev --json\n\\`\\`\\`\n\n---\n\n## Common Patterns\n\n| Pattern | Description |\n|---------|-------------|\n| \\`--json\\` | Raw JSON output (most commands) |\n| \\`--format markdown\\` | Markdown-formatted output (issues, workflows) |\n| \\`--env <env>\\` | Target environment: \\`local\\`, \\`dev\\`, \\`prod\\` |\n| \\`--verbose, -v\\` | Show all events / detailed output |\n| \\`-h, --help\\` | Show help for any command |\n\n### Environment variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| \\`CANARY_API_URL\\` | \\`https://api.runcofactor.com\\` | API endpoint |\n| \\`CANARY_APP_URL\\` | \\`https://app.runcofactor.com\\` | App URL for login |\n| \\`CANARY_API_TOKEN\\` | — | API key (alternative to \\`canary login\\`) |\n\n## Getting Help\n\n\\`\\`\\`bash\ncanary help # Show all commands\ncanary <command> --help # Show help for a specific command\ncanary version # Show CLI version\ncanary upgrade # Upgrade to latest version\n\\`\\`\\`\n`,\n};\n","export const testCasesRenderCurrent = () => `---\nname: test-cases\nversion: 2.4.0\ndescription: Author high-quality test cases as \\`.cofactor.md\\` specs that compile straight into Cofactor workflows. Invoke when the user asks to write test cases, draft a test plan, plan QA scenarios, decide what to test, or convert a PRD/ticket/design into tests.\nallowed-tools: Read, Grep, Glob, Bash, Write\n---\n\n# Test Case Authoring (Cofactor)\n\nUse this skill when the user asks for test cases, a test plan, QA scenarios, \"what should we test for X\", or wants to turn a PRD / ticket / design into tests. The output is one or more **\\`.cofactor.md\\` spec files** — each file is one workflow, one journey, one test case. \\`cofactor spec compile <file>\\` turns them into runnable Cofactor workflows; \\`cofactor spec validate <file>\\` enforces the structural rules below. (Legacy \\`.canary.md\\` files still validate and compile; new specs default to \\`.cofactor.md\\`.)\n\nThe skill has three layers:\n1. **Industry rubric** — what makes a test case good (ISTQB-aligned).\n2. **Spec mapping** — how each rubric piece becomes a section of \\`.cofactor.md\\`.\n3. **Domain Context** — customer-specific sources of truth, filled in once.\n\nRead the Domain Context block at the bottom **first**. If it is unfilled, follow the discovery instructions there before authoring any cases.\n\n---\n\n## 1. The 7-rule rubric\n\nEach case must satisfy all seven. If a rule cannot be satisfied, say so explicitly and explain why — don't silently skip.\n\n### 1. One coherent journey per case (atomic, but not micro)\nA case covers a single coherent journey — one user objective, possibly with several verifications along the way. \"Atomic\" means *coherent*, not *minimal*: if multiple checks share the same setup and naturally flow from one another, they belong in the same case.\n\n- Good (coherent journey, multiple checks): \"Onboard an org: create org → invite a user → claim invite → land on dashboard.\" Each step verifies its own outcome inline.\n- Good (single short journey): \"Submit a ticket and confirm it appears in the queue.\"\n- Bad (unrelated jobs): \"Submit a ticket, edit a user, generate a report.\" — three journeys, three separate \\`.cofactor.md\\` files.\n\n**Rule of thumb:** if isolating a check (e.g. \"tagging works\") would force you to duplicate most of another case's setup, fold it in as an inline assertion on the larger journey instead. Splitting only pays off when the setup is genuinely different or the failure modes are independent.\n\n### 2. Specific, observable expected results\nEvery assertion must be something a stranger could verify without judgement.\n- Good: \"URL ends with \\`/dashboard\\`.\" / \"A row with name \\`X\\` appears in the table.\"\n- Bad: \"The page looks correct.\" / \"It works.\"\n\nLint enforces this as **R1**: a spec with zero run-failing (\\`fail\\`/\\`fatal\\`) assertions warns.\n\n### 3. Independent and self-sufficient\nA case must not depend on another case running first or on long-lived shared state. Provision data inline (\\`## Inputs\\` + \\`## Scenarios\\`, or a \\`**Seed**\\` node) and clean up in \\`## Cleanup\\`. Use macros (\\\\$EMAIL, \\\\$UUID) so reruns don't collide.\n\n### 4. Traceable\nEvery case carries \\`requirementRef:\\` in frontmatter pointing at the ticket / PRD / design. If you can't find one, flag the gap to the user — untraceable specs rot. Lint **R2** warns when missing.\n\n### 5. Risk-prioritized\nTag each case with a priority via the \\`tags:\\` array. Use one of: \\`p0\\`, \\`p1\\`, \\`p2\\`.\n- **p0** — happy path of the core promise; if this breaks, the feature is broken.\n- **p1** — primary edge cases, validation, role variants, common error states.\n- **p2** — rare conditions, visual/agentic checks, low-frequency edges.\n\n### 6. Includes preconditions, data, and cleanup\n- **Auth/role preconditions** → \\`actor:\\` in frontmatter.\n- **Other preconditions** (feature flags, seeded data, sister flows) → bulleted prose in \\`## Preflight\\`.\n- **Test data** → \\`## Inputs\\` (with macros) and per-variant \\`## Scenarios\\`.\n- **Teardown** → bulleted prose in \\`## Cleanup\\`.\n\n### 7. Written as human intent, not UI mechanics\nAction titles describe *what the user is trying to do*; the optional \\`> blockquote\\` underneath gives just enough context for the recorder/agent. Don't write click-by-click sequences.\n- Good: \\`**Action — Assign the ticket to Support**\\`\n- Bad: \\`**Action — Click 'Assign' dropdown, scroll, click 'Support', click Save**\\`\n\nLint **R9** warns when an action reads as click-by-click.\n\n---\n\n## 2. Coverage checklist\n\nBefore handing back a set of specs, sanity-check coverage. For each, either include a case or note why it doesn't apply:\n- Happy path (p0)\n- Primary edges / boundary inputs\n- Negative paths / validation errors\n- Permissions and role variants (admin / member / unauthenticated)\n- Empty, loading, and error states\n- Cross-entity side effects (does this change something visible elsewhere?)\n- Cleanup / undo where applicable\n\nAim for the smallest set that proves the feature works. Five sharp cases beat twenty fuzzy ones.\n\n---\n\n## 3. Authoring \\`.cofactor.md\\`\n\n\\`.cofactor.md\\` is one workflow per file. Frontmatter sets identity; H2 sections carry prose and structured config; \\`## Journey\\` is the linear test itself. The compiler validates structure; lint enforces the rubric semantics above.\n\nRun these for the definitive grammar — do **not** restate them here:\n\n\\`\\`\\`bash\ncofactor spec --help # validate / compile / diff commands\ncofactor spec validate <file> # parse + lint offline; enforce the rules in §1\ncofactor spec compile <file> # create or update the workflow (prints the live URL)\ncofactor workflow guide # node-shape and macro reference\n\\`\\`\\`\n\nAfter \\`cofactor spec compile\\`, echo the printed \\`URL:\\` line back to the user verbatim — it points at the workflow you just created (\\`https://app.runcofactor.com/flows/<id>\\` for prod, \\`https://app.dev.trycanary.ai/flows/<id>\\` for dev). Don't construct it yourself.\n\nMapping at a glance:\n\n| Rubric piece | Where it lives in \\`.cofactor.md\\` |\n|-----------------------------------------|---------------------------------------------------------------------------|\n| Case title | \\`frontmatter.name\\` |\n| Requirement / ticket ref | \\`frontmatter.requirementRef\\` |\n| Priority (rule 5) | \\`tags: [p0]\\` (or p1/p2) in frontmatter |\n| Auth role precondition | \\`actor: <X>\\` + \\`authenticated: true\\` in frontmatter. \\`<X>\\` is a **persona** name by default (e.g. \\`actor: Admin\\` or the explicit \\`actor: persona Admin\\`), or a specific raw credential via \\`actor: credential <name>\\` when the case genuinely needs one named account. Personas resolve at run/suite level; raw credentials bind a single fixed account. Legacy \\`actor: template Admin\\` remains accepted. List personas with \\`cofactor persona list --application \"<application>\"\\`; list credentials with \\`cofactor credential list\\`. |\n| Feature flag / seeded data preconditions| Bulleted prose in \\`## Preflight\\` (\"Feature flag X enabled.\", \"Seed workflow Y published.\") |\n| One-paragraph user-visible promise | \\`## Spirit\\` (blockquote) |\n| Workflow-level declared inputs | \\`## Inputs\\` (e.g. \\`- foo: \\\\$EMAIL\\`) — parses to \\`workflows.inputs_json\\`, surfaces in Workflow Settings → Inputs |\n| Per-step bound values | \\`- field X: Y\\` under an Action — populates *that* step's Inputs panel with \\`Y\\` as the default (compiler mirrors fields → \\`dataRequirements\\` + \\`inputValues\\` on the node). Prefer \\`## Inputs\\` for values shared across actions. |\n| Variants (free / enterprise, etc.) | \\`## Scenarios\\` with per-scenario \\`values:\\` / \\`credentials:\\` overrides |\n| Steps (human intent) | \\`## Journey\\` — \\`**Navigate to** …\\`, \\`**Action — …**\\`, \\`**Seed** …\\` |\n| Inline expected results | \\`- assert (fatal \\\\| fail \\\\| warn): <condition>\\` under the action that produced it. \\`fatal\\` ends the test now (gating preconditions), \\`fail\\` marks the run failed but keeps going (feature claims), \\`warn\\` records without failing (cosmetics) |\n| Standalone assertion | \\`**Assert** <condition>\\` node (prefer inline when possible) |\n| Role change mid-journey | \\`**Switch role to** <X>\\` — mirrors \\`actor:\\`. \\`<X>\\` is a persona name by default (\\`**Switch role to** Admin\\`), \\`persona <name>\\` is the explicit persona form (\\`**Switch role to** persona Admin\\`), \\`credential <name>\\` binds a specific raw credential (\\`**Switch role to** credential admin-bob\\`). Legacy \\`template <name>\\` remains accepted. Compiles to a login node with \\`performLogin: true\\`. Repeat as many times as needed in one journey. |\n| Cross-action data flow | \\`- capture: <name>\\` on the upstream action, \\`\\\\$var.<name>\\` downstream |\n| Cleanup | Bulleted prose in \\`## Cleanup\\` |\n\nWhen a journey shares setup and naturally flows end-to-end, emit **one** \\`.cofactor.md\\` with multiple action nodes and inline assertions. When journeys are unrelated, emit **one file per journey**; if one journey depends on data created by another, link them with \\`**Seed** <spec-name>\\` or \\`**Setup** <spec-name>\\` at the top of the dependent file.\n\n### Action altitude — what each \\`**Action —**\\` step should cover\n\nEach \\`**Action —**\\` is one coherent, intent-level step. The same altitude the Flow Designer and recorder use applies here (see \\`cofactor workflow guide action-nodes\\`):\n\n- **One coherent step, usually broader than a single click** — \"Submit the ticket\", \"Fill out the subscription form\". A lone action that stands on its own (\"Click Start to open the config modal\") is fine; a purely mechanical title (\"Click the button\") or a stuffed multi-outcome step is not. When the recorder compiles your step it should land around 3–8 playbook actions — if one \\`**Action —**\\` implies ~20 clicks across several screens, it's two actions.\n- **End each step at an assertable boundary** (modal gone, URL changed, row appeared) and assert it inline. Relative or temporal checks must reference an upstream \\`- capture:\\` — \\`assert (fail): current count = \\\\$var.start_count - 2\\`, never \"the count dropped by 2\" (a cache-replayed action's assertion can be judged with no memory of the \"before\" state).\n- **No conditionals inside a step** — \"if patient X isn't there, create X\" usually means the data wasn't seeded; stage it in \\`## Preflight\\` / a \\`**Seed**\\` instead. If the same steps reach the goal from any starting state (idempotent), just write them unconditionally.\n\n### Inputs defaults — the decision rule\n\nWhen you need a value (workflow-level \\`## Inputs\\` or step-level \\`- field\\`), pick where it comes from in this order:\n\n1. **Names existing data in the target environment** — a property name, a credential, a seeded record, an existing org/user/team. **Stop and ask the user for the value before writing the spec.** Don't hand-pick. The right sources of truth:\n - \\`cofactor property list\\` — properties (target apps)\n - \\`cofactor persona list --application \"<application>\"\\` — personas (these are what \\`actor:\\` and \\`- credential …\\` reference)\n - \\`cofactor workflow list --search <term>\\` — existing workflows to seed/link to\n - \\`cofactor feature-flag list --env <env>\\` — flag names for Preflight prose\n2. **Synthesizable** — a new email, a UUID, a throwaway string, an ISO date. Pick a macro (\\`\\\\$EMAIL\\`, \\`\\\\$UUID\\`, \\`\\\\$ISO_DATE\\`) and move on without asking. These render as pills in the Inputs panel and resolve at run time.\n3. **Prefer personas** for any auth/role-scoped input. \\`actor: Admin\\` (frontmatter) and \\`- credential admin: Admin\\` (inputs) are cleaner than passing \\`username:\\` + \\`password:\\` and work across environments. Reach for the raw-credential form (\\`actor: credential <name>\\`, \\`**Switch role to** credential <name>\\`, \\`- credential admin: <name>\\`) only when the case genuinely requires a specific fixed account.\n\n---\n\n## 4. Output format\n\nFor each case, write a \\`.cofactor.md\\` file alongside a one-row summary line. Default location: \\`cofactor/specs/<slug>.cofactor.md\\` (confirm with the user if their repo uses a different layout — check Domain Context below).\n\n### Summary table\n\n| file | name | priority | requirementRef |\n|-----------------------------------|--------------------------------------------|----------|------------------|\n| cofactor/specs/submit-ticket.cofactor.md | Submit a ticket and confirm it appears in the queue | p0 | <ticket/PRD ref> |\n\n### Per-case file\n\n\\`\\`\\`markdown\n---\nname: <one user goal, action-oriented>\nactor: <persona name from Domain Context — verbatim, e.g. \"Admin\"; or \\`credential <name>\\` for a specific raw credential>\nauthenticated: true\ntags: [p0] # or p1 / p2; add other tags from Domain Context's tagging conventions\nrequirementRef: <ticket id, PRD path, design link>\n---\n\n# <same as name>\n\n## Spirit\n> <one short paragraph: the user-visible promise this case proves>\n\n## Preflight\n- <feature flag / seed / sister flow / role precondition, one per bullet>\n\n## Cleanup\n- <records to delete, flags to reset>\n\n## Inputs\n- <name>: <value or macro>\n\n## Journey\n\n**Navigate to** \\\\\\`/some/path\\\\\\`.\n\n**Action — <human intent>**\n> <one-sentence context for the recorder/agent>\n- field <name> [(type)]: <value or \\\\$input>\n- capture: <name> # optional, only if a later step needs it via \\\\$var.<name>\n- assert (fatal): <gating precondition — test must stop if wrong>\n- assert (fail): <observable condition — feature is broken if wrong>\n- assert (warn): <softer signal — cosmetic, run still passes>\n\n**End**.\n\\`\\`\\`\n\nA case is one coherent journey — long or short, with no target node count. If a case grows very long, ask whether it's really several independent journeys: splitting them into separate \\`.cofactor.md\\` files lets them run in parallel and fail independently. Keep a single coherent journey together — don't split mid-flow.\n\n---\n\n## 5. Worked example (generic)\n\nRequest: \"Test the support ticket flow.\"\n\n| file | name | priority | requirementRef |\n|-------------------------------------------|-----------------------------------------------------|----------|----------------|\n| cofactor/specs/submit-ticket.cofactor.md | Submit a ticket and confirm it appears in the queue | p0 | <fill in> |\n| cofactor/specs/ticket-required-fields.cofactor.md | Required-field validation blocks submit | p1 | <fill in> |\n| cofactor/specs/ticket-non-admin-reassign.cofactor.md | Non-admin cannot reassign a ticket | p1 | <fill in> |\n\n\\`cofactor/specs/submit-ticket.cofactor.md\\`:\n\n\\`\\`\\`markdown\n---\nname: Submit a ticket and confirm it appears in the queue\nactor: Admin\nauthenticated: true\ntags: [p0, smoke, support]\nrequirementRef: <fill in>\n---\n\n# Submit a ticket and confirm it appears in the queue\n\n## Spirit\n> A member can file a support ticket from the in-app form and immediately\n> see it land in their team's queue without a refresh.\n\n## Preflight\n- At least one Support team exists in the test org (seed workflow \\\\\\`support-team-seed\\\\\\`).\n- Feature flag \\\\\\`support_inbox_v3\\\\\\` is enabled.\n\n## Cleanup\n- Delete the created ticket.\n\n## Inputs\n- subject: \"QA \\\\$UUID\"\n- priority: high\n\n## Journey\n\n**Navigate to** \\\\\\`/support/new\\\\\\`.\n\n**Action — Submit the ticket**\n> Fill subject and priority, then submit.\n- field subject: \\\\$subject\n- field priority (select): \\\\$priority\n- assert (warn): Toast contains \"Ticket created\"\n- assert (fail): URL ends with \\\\\\`/support\\\\\\`\n\n**Navigate to** \\\\\\`/support/queue\\\\\\`.\n\n**Action — Confirm it appears in the queue**\n> Locate the new ticket in the team queue.\n- assert (fail): A row matching \\\\\\`\\\\$subject\\\\\\` is visible\n\n**End**.\n\\`\\`\\`\n\nAfter writing, run \\`cofactor spec validate cofactor/specs/submit-ticket.cofactor.md\\` and resolve any errors / warnings before handing back.\n\n---\n\n## 6. Anti-patterns\n\n- Mega-files that try to cover five unrelated journeys.\n- The opposite: splitting one coherent journey into N tiny files that each re-create the same setup. Bundle them into one \\`## Journey\\` instead.\n- Click-by-click action titles (\"Click X, scroll, click Y\").\n- Conditional steps (\"if X isn't set, set it\"; \"if patient X is missing, create X\") — seed the precondition or write idempotent steps instead.\n- Relative or temporal assertions (\"the count dropped by 2\") with no upstream \\`- capture:\\` to anchor the baseline.\n- \"Looks correct\" / \"everything works\" assertions.\n- Hardcoded emails, IDs, or names that collide on rerun. Use macros (\\\\$EMAIL, \\\\$UUID).\n- Specs that depend on another spec having run first without an explicit \\`**Seed**\\` / \\`**Setup**\\` node.\n- Skipping \\`requirementRef\\` because \"it's obvious\".\n- Asserting state via toasts only — confirm the underlying record changed.\n- Dropping the priority tag — risk-rank every case (\\`p0\\` / \\`p1\\` / \\`p2\\`).\n\n---\n\n## 7. Domain Context\n\n<!-- AGENT/CUSTOMER: fill in this block on first use of the skill, then commit it. -->\n<!-- If any field below is \"<unfilled>\", do a discovery pass before authoring cases: -->\n<!-- - Read README.md, CLAUDE.md, AGENTS.md, docs/, specs/ for requirement and design pointers. -->\n<!-- - Scan recent git log for ticket-tracker references (JIRA-123, LIN-456, #issue). -->\n<!-- - Run \\`cofactor property list\\` and \\`cofactor persona list --application \"<application>\"\\` to learn applications + the personas that map to \\`actor:\\` values. -->\n<!-- - (\\`cofactor credential list\\` shows live credentials — useful, but the \\`actor:\\` field references personas, not credentials.) -->\n<!-- - Run \\`cofactor workflow list --search <feature>\\` to avoid duplicating existing workflows. -->\n<!-- - Run \\`cofactor feature-flag list\\` to confirm flag names referenced in Preflight prose. -->\n<!-- - Propose values to the user, get confirmation, then edit this block in place. -->\n\n- **Requirements / PRDs**: <unfilled — paths or URLs, e.g. \\`docs/specs/\\`, Notion space, Linear project>\n- **Designs**: <unfilled — Figma links, design system doc>\n- **Ticket tracker**: <unfilled — Jira/Linear project key + how to format \\`requirementRef\\` (e.g. \\`PROJ-123\\` or a URL)>\n- **Default property**: <unfilled — the property name to target; find via \\`cofactor property list\\`>\n- **Default environment**: <unfilled — \\`prod\\` | \\`staging\\` | \\`dev\\`>\n- **Credentials / role matrix** (\\`actor:\\` is a persona name by default — list via \\`cofactor persona list --application \"<application>\"\\`. Prefix with \\`credential \\` to bind a specific raw credential — list via \\`cofactor credential list\\`. Use the persona form unless the case genuinely needs a fixed named account.): <unfilled — list the persona names available on the default application, with a one-line note on which to use when. Common shape: \\`actor: Admin\\` (standard user), \\`actor: Superadmin\\` (full access).>\n- **Tagging conventions**: <unfilled — e.g. \\`smoke\\`, \\`regression\\`, plus the priority tags \\`p0\\` / \\`p1\\` / \\`p2\\`>\n- **Spec directory**: <unfilled — where \\`.cofactor.md\\` files live in this repo, e.g. \\`cofactor/specs/\\`>\n- **Existing workflows to extend or avoid duplicating**: <unfilled — search via \\`cofactor workflow list --search <term>\\`>\n- **Glossary / domain terms**: <unfilled — terms that show up in tickets and should appear verbatim in spec names>\n- **Other sources of truth**: <unfilled — runbooks, support tickets, analytics dashboards>\n\nWhen this block is fully populated, every case you author should reference at least the **Requirements**, **Default property**, **Spec directory**, and **Credentials** entries.\n`;\n","// Frozen v2.3.0 render — retained verbatim so `cofactor skill diff` / install can reproduce it.\nexport const testCasesRenderV2_3_0 = () => `---\nname: test-cases\nversion: 2.3.0\ndescription: Author high-quality test cases as \\`.cofactor.md\\` specs that compile straight into Cofactor workflows. Invoke when the user asks to write test cases, draft a test plan, plan QA scenarios, decide what to test, or convert a PRD/ticket/design into tests.\nallowed-tools: Read, Grep, Glob, Bash, Write\n---\n\n# Test Case Authoring (Cofactor)\n\nUse this skill when the user asks for test cases, a test plan, QA scenarios, \"what should we test for X\", or wants to turn a PRD / ticket / design into tests. The output is one or more **\\`.cofactor.md\\` spec files** — each file is one workflow, one journey, one test case. \\`cofactor spec compile <file>\\` turns them into runnable Cofactor workflows; \\`cofactor spec validate <file>\\` enforces the structural rules below. (Legacy \\`.canary.md\\` files still validate and compile; new specs default to \\`.cofactor.md\\`.)\n\nThe skill has three layers:\n1. **Industry rubric** — what makes a test case good (ISTQB-aligned).\n2. **Spec mapping** — how each rubric piece becomes a section of \\`.cofactor.md\\`.\n3. **Domain Context** — customer-specific sources of truth, filled in once.\n\nRead the Domain Context block at the bottom **first**. If it is unfilled, follow the discovery instructions there before authoring any cases.\n\n---\n\n## 1. The 7-rule rubric\n\nEach case must satisfy all seven. If a rule cannot be satisfied, say so explicitly and explain why — don't silently skip.\n\n### 1. One coherent journey per case (atomic, but not micro)\nA case covers a single coherent journey — one user objective, possibly with several verifications along the way. \"Atomic\" means *coherent*, not *minimal*: if multiple checks share the same setup and naturally flow from one another, they belong in the same case.\n\n- Good (coherent journey, multiple checks): \"Onboard an org: create org → invite a user → claim invite → land on dashboard.\" Each step verifies its own outcome inline.\n- Good (single short journey): \"Submit a ticket and confirm it appears in the queue.\"\n- Bad (unrelated jobs): \"Submit a ticket, edit a user, generate a report.\" — three journeys, three separate \\`.cofactor.md\\` files.\n\n**Rule of thumb:** if isolating a check (e.g. \"tagging works\") would force you to duplicate most of another case's setup, fold it in as an inline assertion on the larger journey instead. Splitting only pays off when the setup is genuinely different or the failure modes are independent.\n\n### 2. Specific, observable expected results\nEvery assertion must be something a stranger could verify without judgement.\n- Good: \"URL ends with \\`/dashboard\\`.\" / \"A row with name \\`X\\` appears in the table.\"\n- Bad: \"The page looks correct.\" / \"It works.\"\n\nLint enforces this as **R1**: a spec with zero run-failing (\\`fail\\`/\\`fatal\\`) assertions warns.\n\n### 3. Independent and self-sufficient\nA case must not depend on another case running first or on long-lived shared state. Provision data inline (\\`## Inputs\\` + \\`## Scenarios\\`, or a \\`**Seed**\\` node) and clean up in \\`## Cleanup\\`. Use macros (\\\\$EMAIL, \\\\$UUID) so reruns don't collide.\n\n### 4. Traceable\nEvery case carries \\`requirementRef:\\` in frontmatter pointing at the ticket / PRD / design. If you can't find one, flag the gap to the user — untraceable specs rot. Lint **R2** warns when missing.\n\n### 5. Risk-prioritized\nTag each case with a priority via the \\`tags:\\` array. Use one of: \\`p0\\`, \\`p1\\`, \\`p2\\`.\n- **p0** — happy path of the core promise; if this breaks, the feature is broken.\n- **p1** — primary edge cases, validation, role variants, common error states.\n- **p2** — rare conditions, visual/agentic checks, low-frequency edges.\n\n### 6. Includes preconditions, data, and cleanup\n- **Auth/role preconditions** → \\`actor:\\` in frontmatter.\n- **Other preconditions** (feature flags, seeded data, sister flows) → bulleted prose in \\`## Preflight\\`.\n- **Test data** → \\`## Inputs\\` (with macros) and per-variant \\`## Scenarios\\`.\n- **Teardown** → bulleted prose in \\`## Cleanup\\`.\n\n### 7. Written as human intent, not UI mechanics\nAction titles describe *what the user is trying to do*; the optional \\`> blockquote\\` underneath gives just enough context for the recorder/agent. Don't write click-by-click sequences.\n- Good: \\`**Action — Assign the ticket to Support**\\`\n- Bad: \\`**Action — Click 'Assign' dropdown, scroll, click 'Support', click Save**\\`\n\nLint **R9** warns when an action reads as click-by-click.\n\n---\n\n## 2. Coverage checklist\n\nBefore handing back a set of specs, sanity-check coverage. For each, either include a case or note why it doesn't apply:\n- Happy path (p0)\n- Primary edges / boundary inputs\n- Negative paths / validation errors\n- Permissions and role variants (admin / member / unauthenticated)\n- Empty, loading, and error states\n- Cross-entity side effects (does this change something visible elsewhere?)\n- Cleanup / undo where applicable\n\nAim for the smallest set that proves the feature works. Five sharp cases beat twenty fuzzy ones.\n\n---\n\n## 3. Authoring \\`.cofactor.md\\`\n\n\\`.cofactor.md\\` is one workflow per file. Frontmatter sets identity; H2 sections carry prose and structured config; \\`## Journey\\` is the linear test itself. The compiler validates structure; lint enforces the rubric semantics above.\n\nRun these for the definitive grammar — do **not** restate them here:\n\n\\`\\`\\`bash\ncofactor spec --help # validate / compile / diff commands\ncofactor spec validate <file> # parse + lint offline; enforce the rules in §1\ncofactor spec compile <file> # create or update the workflow (prints the live URL)\ncofactor workflow guide # node-shape and macro reference\n\\`\\`\\`\n\nAfter \\`cofactor spec compile\\`, echo the printed \\`URL:\\` line back to the user verbatim — it points at the workflow you just created (\\`https://app.runcofactor.com/flows/<id>\\` for prod, \\`https://app.dev.trycanary.ai/flows/<id>\\` for dev). Don't construct it yourself.\n\nMapping at a glance:\n\n| Rubric piece | Where it lives in \\`.cofactor.md\\` |\n|-----------------------------------------|---------------------------------------------------------------------------|\n| Case title | \\`frontmatter.name\\` |\n| Requirement / ticket ref | \\`frontmatter.requirementRef\\` |\n| Priority (rule 5) | \\`tags: [p0]\\` (or p1/p2) in frontmatter |\n| Auth role precondition | \\`actor: <X>\\` + \\`authenticated: true\\` in frontmatter. \\`<X>\\` is a **persona** name by default (e.g. \\`actor: Admin\\` or the explicit \\`actor: persona Admin\\`), or a specific raw credential via \\`actor: credential <name>\\` when the case genuinely needs one named account. Personas resolve at run/suite level; raw credentials bind a single fixed account. Legacy \\`actor: template Admin\\` remains accepted. List personas with \\`cofactor persona list --application \"<application>\"\\`; list credentials with \\`cofactor credential list\\`. |\n| Feature flag / seeded data preconditions| Bulleted prose in \\`## Preflight\\` (\"Feature flag X enabled.\", \"Seed workflow Y published.\") |\n| One-paragraph user-visible promise | \\`## Spirit\\` (blockquote) |\n| Workflow-level declared inputs | \\`## Inputs\\` (e.g. \\`- foo: \\\\$EMAIL\\`) — parses to \\`workflows.inputs_json\\`, surfaces in Workflow Settings → Inputs |\n| Per-step bound values | \\`- field X: Y\\` under an Action — populates *that* step's Inputs panel with \\`Y\\` as the default (compiler mirrors fields → \\`dataRequirements\\` + \\`inputValues\\` on the node). Prefer \\`## Inputs\\` for values shared across actions. |\n| Variants (free / enterprise, etc.) | \\`## Scenarios\\` with per-scenario \\`values:\\` / \\`credentials:\\` overrides |\n| Steps (human intent) | \\`## Journey\\` — \\`**Navigate to** …\\`, \\`**Action — …**\\`, \\`**Seed** …\\` |\n| Inline expected results | \\`- assert (fatal \\\\| fail \\\\| warn): <condition>\\` under the action that produced it. \\`fatal\\` ends the test now (gating preconditions), \\`fail\\` marks the run failed but keeps going (feature claims), \\`warn\\` records without failing (cosmetics) |\n| Standalone assertion | \\`**Assert** <condition>\\` node (prefer inline when possible) |\n| Role change mid-journey | \\`**Switch role to** <X>\\` — mirrors \\`actor:\\`. \\`<X>\\` is a persona name by default (\\`**Switch role to** Admin\\`), \\`persona <name>\\` is the explicit persona form (\\`**Switch role to** persona Admin\\`), \\`credential <name>\\` binds a specific raw credential (\\`**Switch role to** credential admin-bob\\`). Legacy \\`template <name>\\` remains accepted. Compiles to a login node with \\`performLogin: true\\`. Repeat as many times as needed in one journey. |\n| Cross-action data flow | \\`- capture: <name>\\` on the upstream action, \\`\\\\$var.<name>\\` downstream |\n| Cleanup | Bulleted prose in \\`## Cleanup\\` |\n\nWhen a journey shares setup and naturally flows end-to-end, emit **one** \\`.cofactor.md\\` with multiple action nodes and inline assertions. When journeys are unrelated, emit **one file per journey**; if one journey depends on data created by another, link them with \\`**Seed** <spec-name>\\` or \\`**Setup** <spec-name>\\` at the top of the dependent file.\n\n### Inputs defaults — the decision rule\n\nWhen you need a value (workflow-level \\`## Inputs\\` or step-level \\`- field\\`), pick where it comes from in this order:\n\n1. **Names existing data in the target environment** — a property name, a credential, a seeded record, an existing org/user/team. **Stop and ask the user for the value before writing the spec.** Don't hand-pick. The right sources of truth:\n - \\`cofactor property list\\` — properties (target apps)\n - \\`cofactor persona list --application \"<application>\"\\` — personas (these are what \\`actor:\\` and \\`- credential …\\` reference)\n - \\`cofactor workflow list --search <term>\\` — existing workflows to seed/link to\n - \\`cofactor feature-flag list --env <env>\\` — flag names for Preflight prose\n2. **Synthesizable** — a new email, a UUID, a throwaway string, an ISO date. Pick a macro (\\`\\\\$EMAIL\\`, \\`\\\\$UUID\\`, \\`\\\\$ISO_DATE\\`) and move on without asking. These render as pills in the Inputs panel and resolve at run time.\n3. **Prefer personas** for any auth/role-scoped input. \\`actor: Admin\\` (frontmatter) and \\`- credential admin: Admin\\` (inputs) are cleaner than passing \\`username:\\` + \\`password:\\` and work across environments. Reach for the raw-credential form (\\`actor: credential <name>\\`, \\`**Switch role to** credential <name>\\`, \\`- credential admin: <name>\\`) only when the case genuinely requires a specific fixed account.\n\n---\n\n## 4. Output format\n\nFor each case, write a \\`.cofactor.md\\` file alongside a one-row summary line. Default location: \\`cofactor/specs/<slug>.cofactor.md\\` (confirm with the user if their repo uses a different layout — check Domain Context below).\n\n### Summary table\n\n| file | name | priority | requirementRef |\n|-----------------------------------|--------------------------------------------|----------|------------------|\n| cofactor/specs/submit-ticket.cofactor.md | Submit a ticket and confirm it appears in the queue | p0 | <ticket/PRD ref> |\n\n### Per-case file\n\n\\`\\`\\`markdown\n---\nname: <one user goal, action-oriented>\nactor: <persona name from Domain Context — verbatim, e.g. \"Admin\"; or \\`credential <name>\\` for a specific raw credential>\nauthenticated: true\ntags: [p0] # or p1 / p2; add other tags from Domain Context's tagging conventions\nrequirementRef: <ticket id, PRD path, design link>\n---\n\n# <same as name>\n\n## Spirit\n> <one short paragraph: the user-visible promise this case proves>\n\n## Preflight\n- <feature flag / seed / sister flow / role precondition, one per bullet>\n\n## Cleanup\n- <records to delete, flags to reset>\n\n## Inputs\n- <name>: <value or macro>\n\n## Journey\n\n**Navigate to** \\\\\\`/some/path\\\\\\`.\n\n**Action — <human intent>**\n> <one-sentence context for the recorder/agent>\n- field <name> [(type)]: <value or \\\\$input>\n- capture: <name> # optional, only if a later step needs it via \\\\$var.<name>\n- assert (fatal): <gating precondition — test must stop if wrong>\n- assert (fail): <observable condition — feature is broken if wrong>\n- assert (warn): <softer signal — cosmetic, run still passes>\n\n**End**.\n\\`\\`\\`\n\nKeep journeys short (3–8 nodes). If a case grows past that, it's probably two cases.\n\n---\n\n## 5. Worked example (generic)\n\nRequest: \"Test the support ticket flow.\"\n\n| file | name | priority | requirementRef |\n|-------------------------------------------|-----------------------------------------------------|----------|----------------|\n| cofactor/specs/submit-ticket.cofactor.md | Submit a ticket and confirm it appears in the queue | p0 | <fill in> |\n| cofactor/specs/ticket-required-fields.cofactor.md | Required-field validation blocks submit | p1 | <fill in> |\n| cofactor/specs/ticket-non-admin-reassign.cofactor.md | Non-admin cannot reassign a ticket | p1 | <fill in> |\n\n\\`cofactor/specs/submit-ticket.cofactor.md\\`:\n\n\\`\\`\\`markdown\n---\nname: Submit a ticket and confirm it appears in the queue\nactor: Admin\nauthenticated: true\ntags: [p0, smoke, support]\nrequirementRef: <fill in>\n---\n\n# Submit a ticket and confirm it appears in the queue\n\n## Spirit\n> A member can file a support ticket from the in-app form and immediately\n> see it land in their team's queue without a refresh.\n\n## Preflight\n- At least one Support team exists in the test org (seed workflow \\\\\\`support-team-seed\\\\\\`).\n- Feature flag \\\\\\`support_inbox_v3\\\\\\` is enabled.\n\n## Cleanup\n- Delete the created ticket.\n\n## Inputs\n- subject: \"QA \\\\$UUID\"\n- priority: high\n\n## Journey\n\n**Navigate to** \\\\\\`/support/new\\\\\\`.\n\n**Action — Submit the ticket**\n> Fill subject and priority, then submit.\n- field subject: \\\\$subject\n- field priority (select): \\\\$priority\n- assert (warn): Toast contains \"Ticket created\"\n- assert (fail): URL ends with \\\\\\`/support\\\\\\`\n\n**Navigate to** \\\\\\`/support/queue\\\\\\`.\n\n**Action — Confirm it appears in the queue**\n> Locate the new ticket in the team queue.\n- assert (fail): A row matching \\\\\\`\\\\$subject\\\\\\` is visible\n\n**End**.\n\\`\\`\\`\n\nAfter writing, run \\`cofactor spec validate cofactor/specs/submit-ticket.cofactor.md\\` and resolve any errors / warnings before handing back.\n\n---\n\n## 6. Anti-patterns\n\n- Mega-files that try to cover five unrelated journeys.\n- The opposite: splitting one coherent journey into N tiny files that each re-create the same setup. Bundle them into one \\`## Journey\\` instead.\n- Click-by-click action titles (\"Click X, scroll, click Y\").\n- \"Looks correct\" / \"everything works\" assertions.\n- Hardcoded emails, IDs, or names that collide on rerun. Use macros (\\\\$EMAIL, \\\\$UUID).\n- Specs that depend on another spec having run first without an explicit \\`**Seed**\\` / \\`**Setup**\\` node.\n- Skipping \\`requirementRef\\` because \"it's obvious\".\n- Asserting state via toasts only — confirm the underlying record changed.\n- Dropping the priority tag — risk-rank every case (\\`p0\\` / \\`p1\\` / \\`p2\\`).\n\n---\n\n## 7. Domain Context\n\n<!-- AGENT/CUSTOMER: fill in this block on first use of the skill, then commit it. -->\n<!-- If any field below is \"<unfilled>\", do a discovery pass before authoring cases: -->\n<!-- - Read README.md, CLAUDE.md, AGENTS.md, docs/, specs/ for requirement and design pointers. -->\n<!-- - Scan recent git log for ticket-tracker references (JIRA-123, LIN-456, #issue). -->\n<!-- - Run \\`cofactor property list\\` and \\`cofactor persona list --application \"<application>\"\\` to learn applications + the personas that map to \\`actor:\\` values. -->\n<!-- - (\\`cofactor credential list\\` shows live credentials — useful, but the \\`actor:\\` field references personas, not credentials.) -->\n<!-- - Run \\`cofactor workflow list --search <feature>\\` to avoid duplicating existing workflows. -->\n<!-- - Run \\`cofactor feature-flag list\\` to confirm flag names referenced in Preflight prose. -->\n<!-- - Propose values to the user, get confirmation, then edit this block in place. -->\n\n- **Requirements / PRDs**: <unfilled — paths or URLs, e.g. \\`docs/specs/\\`, Notion space, Linear project>\n- **Designs**: <unfilled — Figma links, design system doc>\n- **Ticket tracker**: <unfilled — Jira/Linear project key + how to format \\`requirementRef\\` (e.g. \\`PROJ-123\\` or a URL)>\n- **Default property**: <unfilled — the property name to target; find via \\`cofactor property list\\`>\n- **Default environment**: <unfilled — \\`prod\\` | \\`staging\\` | \\`dev\\`>\n- **Credentials / role matrix** (\\`actor:\\` is a persona name by default — list via \\`cofactor persona list --application \"<application>\"\\`. Prefix with \\`credential \\` to bind a specific raw credential — list via \\`cofactor credential list\\`. Use the persona form unless the case genuinely needs a fixed named account.): <unfilled — list the persona names available on the default application, with a one-line note on which to use when. Common shape: \\`actor: Admin\\` (standard user), \\`actor: Superadmin\\` (full access).>\n- **Tagging conventions**: <unfilled — e.g. \\`smoke\\`, \\`regression\\`, plus the priority tags \\`p0\\` / \\`p1\\` / \\`p2\\`>\n- **Spec directory**: <unfilled — where \\`.cofactor.md\\` files live in this repo, e.g. \\`cofactor/specs/\\`>\n- **Existing workflows to extend or avoid duplicating**: <unfilled — search via \\`cofactor workflow list --search <term>\\`>\n- **Glossary / domain terms**: <unfilled — terms that show up in tickets and should appear verbatim in spec names>\n- **Other sources of truth**: <unfilled — runbooks, support tickets, analytics dashboards>\n\nWhen this block is fully populated, every case you author should reference at least the **Requirements**, **Default property**, **Spec directory**, and **Credentials** entries.\n`;\n","import type { SkillTemplate } from './issue-log-xref.js';\nimport { testCasesRenderCurrent } from './test-cases-current.js';\nimport { testCasesRenderV2_3_0 } from './test-cases-v2-3-0.js';\n\nexport const testCasesTemplate: SkillTemplate = {\n name: 'test-cases',\n description:\n 'Author high-quality test cases as `.cofactor.md` specs that compile straight into Cofactor workflows. Invoke when the user asks to write test cases, draft a test plan, plan QA scenarios, decide what to test, or convert a PRD/ticket/design into tests.',\n version: '2.4.0',\n render: testCasesRenderCurrent,\n previousVersions: {\n '2.3.0': testCasesRenderV2_3_0,\n },\n};\n","/**\n * `debug-run` skill template.\n *\n * Unlike the other entries in SKILL_TEMPLATES (which inline their content as\n * JS strings), the debug-run skill is rendered from the Handlebars partials in\n * `@chatsdet/diagnostic-playbook`. Source of truth = the playbook partials.\n *\n * Versioning: each released version is a frozen snapshot file under\n * `packages/canary-cli/skills/debug-run/history/<version>.md`. The current\n * version is stamped in `version.json` next to the history dir. To mint a new\n * version after editing partials, run:\n *\n * bun run --filter=@canaryai/cli bump-skill debug-run [patch|minor|major]\n *\n * The drift test in `apps/api/tests/unit/diagnostics/skill-rendered.test.ts`\n * fails if the live `renderSkill()` output diverges from\n * `history/<currentVersion>.md`, forcing a bump rather than silent edits to a\n * previously-released version. `previousVersions` is auto-populated from the\n * history dir so `canary skill diff debug-run` can replay any released version.\n */\n\nimport { readFileSync, readdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { SkillTemplate } from './issue-log-xref.js';\n\nconst HERE = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Resolve the on-disk location of the debug-run skill assets.\n *\n * At runtime the assets live in one of two places depending on whether we\n * are running from the source tree (tests, dev), the bundled dist (npm\n * install), or from a published @canaryai/cli inside node_modules:\n *\n * - source: packages/canary-cli/src/skill-templates/debug-run.ts\n * → ../../skills/debug-run/\n * - dist: packages/canary-cli/dist/<chunk>.js\n * → ./skills/debug-run/ (copied by `cp -r skills dist/`)\n *\n * The first candidate that has a readable `version.json` wins.\n */\nfunction resolveSkillDir(): string {\n const candidates = [\n join(HERE, '..', '..', 'skills', 'debug-run'), // source tree\n join(HERE, 'skills', 'debug-run'), // dist\n join(HERE, '..', 'skills', 'debug-run'), // dist split-chunk variant\n ];\n for (const c of candidates) {\n try {\n readFileSync(join(c, 'version.json'), 'utf-8');\n return c;\n } catch {\n // try next\n }\n }\n throw new Error(\n `Could not locate debug-run skill assets relative to ${HERE}. Tried: ${candidates.join(', ')}`,\n );\n}\n\nconst SKILL_DIR = resolveSkillDir();\nconst HISTORY_DIR = join(SKILL_DIR, 'history');\n\nconst versionMeta = JSON.parse(\n readFileSync(join(SKILL_DIR, 'version.json'), 'utf-8'),\n) as { current: string };\n\nfunction readVersion(version: string): string {\n return readFileSync(join(HISTORY_DIR, `${version}.md`), 'utf-8');\n}\n\nfunction listVersionsOnDisk(): string[] {\n return readdirSync(HISTORY_DIR)\n .filter((f) => f.endsWith('.md'))\n .map((f) => f.slice(0, -3));\n}\n\nconst previousVersions: Record<string, () => string> = {};\nfor (const v of listVersionsOnDisk()) {\n if (v !== versionMeta.current) {\n previousVersions[v] = () => readVersion(v);\n }\n}\n\nexport const debugRunTemplate: SkillTemplate = {\n name: 'debug-run',\n description:\n 'Diagnose why a workflow test failed — root-cause an end-to-end run from its materialised artifacts',\n version: versionMeta.current,\n render: () => readVersion(versionMeta.current),\n previousVersions,\n};\n","import type { SkillTemplate } from './issue-log-xref.js';\n\nexport const sandboxTemplate: SkillTemplate = {\n name: 'sandbox',\n description: 'Orientation for Canary sandboxes — ephemeral app environments built from a verified template',\n version: '1.0.0',\n render: () => `---\nname: sandbox\nversion: 1.0.0\ndescription: Orientation for Canary sandboxes — ephemeral, containerized app environments built from a verified template. Use whenever the user mentions a sandbox or sandboxes (especially Canary sandboxes), sandbox templates or instances, provisioning / building / verifying / terminating a sandbox, sandbox artifacts / checklist / actions, or running PR / release tests against an ephemeral environment. Anchors to \\`canary sandbox guide\\`.\nallowed-tools: Bash(canary sandbox:*), Bash(canary login:*), Read\n---\n\n# Canary Sandboxes\n\nA **sandbox** is an ephemeral, containerized deployment of an app, provisioned on\ndemand from a verified **template**. Use it to stand up a real, browsable\nenvironment for PR / release testing and to run server-side **actions** inside\nworkflow runs.\n\n> **Start with the guide.** The authoritative, always-current reference is the\n> built-in guide — read the relevant section before doing sandbox work:\n>\n> \\`\\`\\`bash\n> canary sandbox guide [goal|research|artifacts|actions|verify|checklist]\n> canary sandbox --help\n> \\`\\`\\`\n>\n> This skill is a thin map; the guide is the source of truth. Don't re-derive it\n> — hand off to it.\n\n## Prerequisites\n\n- \\`canary\\` CLI installed and authenticated (\\`canary login\\`).\n- Run \\`canary sandbox --help\\` for the full command surface.\n\n## Core concepts\n\n- **Template** — the reusable, verified blueprint: a git repo + branch, its\n artifacts (Dockerfile, compose, scripts), a config schema, a setup checklist,\n and optional sandbox actions. Lifecycle: \\`draft → authoring → verified\\`.\n- **Instance** — a running environment provisioned from a template, with a TTL\n (default 8h) and a public URL. Lifecycle:\n \\`provisioning → running/healthy → terminated\\` (or \\`failed\\`).\n\nTemplates are durable; instances are disposable. You author against a template,\nthen provision throwaway instances from it.\n\n## Lifecycle & key verbs\n\n\\`\\`\\`\ncreate Create a template + its first authoring instance (from a property/repo)\n ↓ research the app, set config, upload artifacts (guide: research, artifacts)\nbuild Build images, start containers, generate routing\n ↓ inspect with diagnostics / logs / run-command (guide: verify)\nverify Provision a fresh instance, probe it, flip template → verified\n ↓\nprovision Spin up fresh instances from the verified template (--ttl, --name)\nterminate Destroy one instance delete Remove the template + all instances\n\\`\\`\\`\n\nSee \\`canary sandbox guide goal\\` for the full authoring loop and \\`guide verify\\`\nfor the debugging playbook.\n\n## Features (each defers to the guide for detail)\n\n- **Checklist profiles** — \\`minimal\\` (code cloned), \\`ci-ready\\` (unit tests\n runnable), \\`full-stack\\` (app fully running). Items form a dependency-ordered\n list. → \\`canary sandbox guide checklist\\`\n- **Artifacts** — the typed files that define the sandbox: \\`dockerfile\\`,\n \\`docker-compose\\`, \\`setup-script\\`, \\`startup-script\\`, \\`seed-script\\`, \\`file\\`.\n Uploads are template-level — rebuild an instance to apply.\n → \\`canary sandbox guide artifacts\\`\n- **Config** — required / optional / sensitive env vars + per-template defaults,\n pushed to the instance as its \\`.env\\`. → \\`canary sandbox config list|set\\`\n- **Multi-repo** — link several repos to one template as distinct services.\n → \\`canary sandbox repo list|add\\`\n- **Actions** — template-scoped, parameterized scripts run against an instance,\n with typed input/output and optional credential output.\n → \\`canary sandbox guide actions\\`\n- **AMIs** — per-template golden images for fast provisioning.\n → \\`canary sandbox ami list|rebake|use\\`\n- **Sizing** — instance presets \\`small … 2xlarge\\`. → \\`canary sandbox set-size\\`\n\n## Getting started — create a sandbox\n\n\\`\\`\\`bash\ncanary sandbox create <property> # template + first authoring instance\n# read \\`canary sandbox guide research\\`, then:\ncanary sandbox config set <template-id> <KEY> <VALUE>\ncanary sandbox artifact create <template-id> <type> <local-file>\ncanary sandbox build <instance-id> # apply artifacts/config\ncanary sandbox diagnostics <instance-id> # + logs to confirm it's up\ncanary sandbox checklist complete <template-id> <item-id> --status success --summary \"...\"\ncanary sandbox verify <template-id> # flip to verified\n\\`\\`\\`\n\nBatch your artifact + config changes, then \\`build\\` **once**. Walk the guide\nsections in order (\\`goal → research → artifacts → verify → checklist\\`) — they\ncontain the env-var classification, migration, and monorepo build-order details\nthat make the build succeed.\n\n## Updating an existing sandbox\n\n- Edit an artifact: \\`canary sandbox artifact get <template-id> <type>\\` → change\n it → \\`canary sandbox artifact create <template-id> <type> <file>\\` →\n \\`canary sandbox build <instance-id>\\` to apply (artifact uploads are\n template-level; running instances need a rebuild).\n- Change config defaults: \\`canary sandbox config set <template-id> <KEY> <VALUE>\\`.\n- Re-run / update the checklist; \\`canary sandbox ami rebake <template-id>\\` for a\n fresh golden image after artifact changes.\n\n## How sandboxes are used in Canary\n\n1. **PR / release testing.** A verified template provisions an *ephemeral\n environment* that a test suite runs against. A spec/workflow binds to a\n template (the spec's \\`sandboxTemplate:\\` frontmatter); the suite\n auto-provisions one instance, shares it across the suite's runs, and tears it\n down afterward. → \\`canary sandbox guide goal\\`\n\n2. **Actions inside workflows.** A sandbox action is a template-scoped script\n that runs *server-side* inside the run's backing instance (referenced by\n slug, so it's portable across environments). Its JSON output registers as\n workflow variables (\\`$var.<key>\\`), and it can emit an ephemeral login\n credential for downstream login steps. On a non-sandbox environment the step\n skips with a warning. → \\`canary sandbox guide actions\\`\n\n## Cheat-sheet\n\n\\`\\`\\`bash\ncanary sandbox list # templates + instances\ncanary sandbox template <template-id> # template detail + config\ncanary sandbox create <property> # new template + authoring instance\ncanary sandbox provision <template-id> --ttl 4 # fresh instance from a verified template\ncanary sandbox build <instance-id> # build/start services\ncanary sandbox diagnostics <instance-id> # container health, URL, phase\ncanary sandbox logs <instance-id> --service <name>\ncanary sandbox run-command <instance-id> \"<cmd>\" # host VM (add --service <name> for a container)\ncanary sandbox verify <template-id> # provision + probe + mark verified\ncanary sandbox action list|get|create|execute <template-id> ...\ncanary sandbox checklist <template-id> # setup progress\ncanary sandbox terminate <instance-id> # destroy one instance\n\\`\\`\\`\n\n## More info\n\n- \\`canary sandbox guide <section>\\` and \\`canary sandbox --help\\` — the source of truth.\n- Authoring deeper actions / credentials: \\`canary sandbox guide actions\\`.\n`,\n};\n","import type { SkillTemplate } from './issue-log-xref.js';\nimport { issueLogXrefTemplate } from './issue-log-xref.js';\nimport { browserTestingTemplate } from './browser-testing.js';\nimport { agentTasksTemplate } from './agent-tasks.js';\nimport { canaryBasicTemplate } from './canary-basic.js';\nimport { testCasesTemplate } from './test-cases.js';\nimport { debugRunTemplate } from './debug-run.js';\nimport { sandboxTemplate } from './sandbox.js';\n\n// SkillTemplate kept file-local (defined in issue-log-xref.ts)\n\nexport const SKILL_TEMPLATES: Record<string, SkillTemplate> = {\n 'canary-basic': canaryBasicTemplate,\n 'agent-tasks': agentTasksTemplate,\n 'issue-log-xref': issueLogXrefTemplate,\n 'browser-testing': browserTestingTemplate,\n 'test-cases': testCasesTemplate,\n 'debug-run': debugRunTemplate,\n 'sandbox': sandboxTemplate,\n};\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACTvD,IAAM,sCACX,MAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC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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;AAiShB;;;ACvSO,IAAM,yBAAyB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCrC,IAAM,wBAAwB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":["existsSync","readFileSync","homedir","join","join","i","j","join","homedir","existsSync","readFileSync"]}
@@ -12,7 +12,7 @@ import {
12
12
  workflowToSpec,
13
13
  writeNodeIds,
14
14
  writeWorkflowId
15
- } from "./chunk-5N4OZPFQ.js";
15
+ } from "./chunk-DECTGV4O.js";
16
16
  import "./chunk-HI2UUGRK.js";
17
17
  import {
18
18
  fetchOrExit
@@ -22,7 +22,7 @@ import {
22
22
  hasFlag,
23
23
  resolveAppUrl
24
24
  } from "./chunk-YBYOOXMK.js";
25
- import "./chunk-4ZNTGBJR.js";
25
+ import "./chunk-EHKHZ5UR.js";
26
26
  import {
27
27
  isSpecFile,
28
28
  readableSpecDirs,
@@ -980,4 +980,4 @@ export {
980
980
  stampedSpecPath,
981
981
  uniqueName
982
982
  };
983
- //# sourceMappingURL=spec-QPWXRPAG.js.map
983
+ //# sourceMappingURL=spec-TOUOP4TC.js.map
@@ -12,14 +12,14 @@ import {
12
12
  captureSubstrateV2,
13
13
  consoleLogger,
14
14
  parseSnapshot
15
- } from "./chunk-IFZ72FZV.js";
15
+ } from "./chunk-3X3TSH2B.js";
16
16
  import "./chunk-S3Q7MDCS.js";
17
17
  import {
18
18
  MACRO_PATTERN,
19
19
  isVolatileIdentifier,
20
20
  stableAttrSelector,
21
21
  stableIdentifierPrefix
22
- } from "./chunk-4ZNTGBJR.js";
22
+ } from "./chunk-EHKHZ5UR.js";
23
23
  import "./chunk-2EHYDUHX.js";
24
24
  import "./chunk-ICKB3EOT.js";
25
25
 
@@ -7387,4 +7387,4 @@ export {
7387
7387
  verifySelectorAgainstRef,
7388
7388
  waitForTraceDomHydration
7389
7389
  };
7390
- //# sourceMappingURL=src-BH5O6Z3E.js.map
7390
+ //# sourceMappingURL=src-YZGG5ZSL.js.map
@@ -8,14 +8,14 @@ import {
8
8
  fetchList,
9
9
  promptChoice,
10
10
  selectProperty
11
- } from "./chunk-LSL2M7O6.js";
11
+ } from "./chunk-WTMSRIDK.js";
12
12
  import "./chunk-H3LWYSKY.js";
13
13
  import {
14
14
  getArgValue,
15
15
  resolveConfig
16
16
  } from "./chunk-YBYOOXMK.js";
17
17
  import "./chunk-S3Q7MDCS.js";
18
- import "./chunk-4ZNTGBJR.js";
18
+ import "./chunk-EHKHZ5UR.js";
19
19
  import "./chunk-ZSOAFMES.js";
20
20
  import "./chunk-ICKB3EOT.js";
21
21
 
@@ -150,4 +150,4 @@ Use \`canary session\` commands to interact with the browser.`);
150
150
  export {
151
151
  runLocalStart
152
152
  };
153
- //# sourceMappingURL=start-5BADZ65B.js.map
153
+ //# sourceMappingURL=start-JDLIIBPC.js.map
@@ -5,12 +5,12 @@ import {
5
5
  formatUnknownTagsError,
6
6
  resolveTagNames,
7
7
  runTag
8
- } from "./chunk-YBX5BIKL.js";
9
- import "./chunk-LSL2M7O6.js";
8
+ } from "./chunk-PK5UICGR.js";
9
+ import "./chunk-WTMSRIDK.js";
10
10
  import "./chunk-H3LWYSKY.js";
11
11
  import "./chunk-YBYOOXMK.js";
12
12
  import "./chunk-S3Q7MDCS.js";
13
- import "./chunk-4ZNTGBJR.js";
13
+ import "./chunk-EHKHZ5UR.js";
14
14
  import "./chunk-ZSOAFMES.js";
15
15
  import "./chunk-ICKB3EOT.js";
16
16
  export {
@@ -20,4 +20,4 @@ export {
20
20
  resolveTagNames,
21
21
  runTag
22
22
  };
23
- //# sourceMappingURL=tag-CIR6U5LL.js.map
23
+ //# sourceMappingURL=tag-LSS3IOUA.js.map
@@ -2,7 +2,7 @@ import { createRequire as __cr } from "module"; import { fileURLToPath as __fup
2
2
  import {
3
3
  apiRequest,
4
4
  getTargetOrg
5
- } from "./chunk-LSL2M7O6.js";
5
+ } from "./chunk-WTMSRIDK.js";
6
6
  import "./chunk-H3LWYSKY.js";
7
7
  import {
8
8
  getArgValue,
@@ -10,7 +10,7 @@ import {
10
10
  resolveConfig
11
11
  } from "./chunk-YBYOOXMK.js";
12
12
  import "./chunk-S3Q7MDCS.js";
13
- import "./chunk-4ZNTGBJR.js";
13
+ import "./chunk-EHKHZ5UR.js";
14
14
  import "./chunk-ZSOAFMES.js";
15
15
  import "./chunk-ICKB3EOT.js";
16
16
 
@@ -921,4 +921,4 @@ async function runTask(argv) {
921
921
  export {
922
922
  runTask
923
923
  };
924
- //# sourceMappingURL=task-4YKONXJI.js.map
924
+ //# sourceMappingURL=task-KCNDIT4A.js.map
@@ -1,13 +1,13 @@
1
1
  import { createRequire as __cr } from "module"; import { fileURLToPath as __fup } from "url"; import { dirname as __dn } from "path"; const require = __cr(import.meta.url); const __filename = __fup(import.meta.url); const __dirname = __dn(__filename);
2
2
  import {
3
3
  runRemoteTest
4
- } from "./chunk-3VHY375S.js";
4
+ } from "./chunk-3VIBXXNX.js";
5
5
  import {
6
6
  isTriageEnabledForExecution
7
- } from "./chunk-ZP3RP4IK.js";
7
+ } from "./chunk-6AJLNMHB.js";
8
8
  import {
9
9
  apiRequest
10
- } from "./chunk-LSL2M7O6.js";
10
+ } from "./chunk-WTMSRIDK.js";
11
11
  import "./chunk-H3LWYSKY.js";
12
12
  import {
13
13
  getArgValue,
@@ -15,7 +15,7 @@ import {
15
15
  resolveConfig
16
16
  } from "./chunk-YBYOOXMK.js";
17
17
  import "./chunk-S3Q7MDCS.js";
18
- import "./chunk-4ZNTGBJR.js";
18
+ import "./chunk-EHKHZ5UR.js";
19
19
  import "./chunk-ZSOAFMES.js";
20
20
  import "./chunk-ICKB3EOT.js";
21
21
 
@@ -395,4 +395,4 @@ async function runTestSuite(argv) {
395
395
  export {
396
396
  runTestSuite
397
397
  };
398
- //# sourceMappingURL=test-suite-PRJ2PGMN.js.map
398
+ //# sourceMappingURL=test-suite-MOVN2XL5.js.map
@@ -1,15 +1,15 @@
1
1
  import { createRequire as __cr } from "module"; import { fileURLToPath as __fup } from "url"; import { dirname as __dn } from "path"; const require = __cr(import.meta.url); const __filename = __fup(import.meta.url); const __dirname = __dn(__filename);
2
2
  import {
3
3
  runTrace
4
- } from "./chunk-4SV3CGNM.js";
4
+ } from "./chunk-SFRUUIIC.js";
5
5
  import "./chunk-YBYOOXMK.js";
6
- import "./chunk-IFZ72FZV.js";
6
+ import "./chunk-3X3TSH2B.js";
7
7
  import "./chunk-S3Q7MDCS.js";
8
- import "./chunk-4ZNTGBJR.js";
8
+ import "./chunk-EHKHZ5UR.js";
9
9
  import "./chunk-2EHYDUHX.js";
10
10
  import "./chunk-ZSOAFMES.js";
11
11
  import "./chunk-ICKB3EOT.js";
12
12
  export {
13
13
  runTrace
14
14
  };
15
- //# sourceMappingURL=trace-XVB47RLY.js.map
15
+ //# sourceMappingURL=trace-7OZNMAKV.js.map
@@ -2,16 +2,16 @@ import { createRequire as __cr } from "module"; import { fileURLToPath as __fup
2
2
  import {
3
3
  isTriageEnabledForExecution,
4
4
  runTriage
5
- } from "./chunk-ZP3RP4IK.js";
6
- import "./chunk-LSL2M7O6.js";
5
+ } from "./chunk-6AJLNMHB.js";
6
+ import "./chunk-WTMSRIDK.js";
7
7
  import "./chunk-H3LWYSKY.js";
8
8
  import "./chunk-YBYOOXMK.js";
9
9
  import "./chunk-S3Q7MDCS.js";
10
- import "./chunk-4ZNTGBJR.js";
10
+ import "./chunk-EHKHZ5UR.js";
11
11
  import "./chunk-ZSOAFMES.js";
12
12
  import "./chunk-ICKB3EOT.js";
13
13
  export {
14
14
  isTriageEnabledForExecution,
15
15
  runTriage
16
16
  };
17
- //# sourceMappingURL=triage-L5WR65KW.js.map
17
+ //# sourceMappingURL=triage-BRSUW4Z7.js.map
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __cr } from "module"; import { fileURLToPath as __fup } from "url"; import { dirname as __dn } from "path"; const require = __cr(import.meta.url); const __filename = __fup(import.meta.url); const __dirname = __dn(__filename);
2
2
  import {
3
3
  apiRequest
4
- } from "./chunk-LSL2M7O6.js";
4
+ } from "./chunk-WTMSRIDK.js";
5
5
  import "./chunk-H3LWYSKY.js";
6
6
  import {
7
7
  getArgValue,
@@ -9,7 +9,7 @@ import {
9
9
  resolveConfig
10
10
  } from "./chunk-YBYOOXMK.js";
11
11
  import "./chunk-S3Q7MDCS.js";
12
- import "./chunk-4ZNTGBJR.js";
12
+ import "./chunk-EHKHZ5UR.js";
13
13
  import "./chunk-ZSOAFMES.js";
14
14
  import "./chunk-ICKB3EOT.js";
15
15
 
@@ -438,4 +438,4 @@ async function runUtilities(argv) {
438
438
  export {
439
439
  runUtilities
440
440
  };
441
- //# sourceMappingURL=utilities-LBKWREPU.js.map
441
+ //# sourceMappingURL=utilities-TXQGGH37.js.map