{"_id":"canary-lab","_rev":"79-e1c08c4fe87277ff9ef3e20814e59fa9","name":"canary-lab","dist-tags":{"latest":"2.3.1"},"versions":{"2.2.1":{"name":"canary-lab","version":"2.2.1","keywords":["playwright","playwright-testing","e2e","e2e-testing","testing","test-automation","local-development","developer-tools","ai-agents","ai-testing","coding-agents","agent-harness","ai-verification","concurrent-testing","mcp","mcp-server","claude","claude-code","codex"],"author":{"url":"https://github.com/ferterahadi/canary-lab","name":"Fer Terahadi","email":"fernanditerahadi@gmail.com"},"license":"MIT","_id":"canary-lab@2.2.1","maintainers":[{"name":"ferterahadi","email":"fernanditerahadi@gmail.com"}],"homepage":"https://github.com/ferterahadi/canary-lab#readme","bugs":{"url":"https://github.com/ferterahadi/canary-lab/issues"},"bin":{"canary-lab":"dist/apps/cli/cli.js"},"dist":{"shasum":"a5eeb7219974edb8eed9bb50b362ec1b619f0074","tarball":"https://registry.npmjs.org/canary-lab/-/canary-lab-2.2.1.tgz","fileCount":537,"integrity":"sha512-S4QiwaK2OuZpaG+cR/Jse6KiuMWtrvdE8UABV6YmSqqkfsq8BolGyBP2XQNgqN5vCxXbULYFa0Dt2tDl1CfhCA==","signatures":[{"sig":"MEQCIFbmq4N9+rSmchEknhJ0sCQ6+QI8moRSChb0+76BY/V/AiA8BbHDnvDOSmd64rDSklAQq6eVJwxptLcgdh/C8iQqHA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":7407220},"engines":{"npm":">=9.0.0","node":">=22.12.0"},"exports":{"./feature-support/types":"./dist/shared/launcher/types.js","./feature-support/load-env":"./dist/shared/configs/loadEnv.js","./feature-support/playwright-base":"./dist/shared/configs/playwright.base.js","./feature-support/log-marker-fixture":"./dist/shared/e2e-runner/log-marker-fixture.js"},"gitHead":"8aff9ca6d73f165b179944ec177c0d7457d38ff3","scripts":{"tag":"node tools/tag-release.mjs","demo":"node tools/smoke-demo.mjs --interactive","lint":"eslint .","test":"vitest run","build":"node tools/gen-agents-md.mjs && node tools/gen-codex-skills.mjs && node tools/clean-dist.mjs && tsc -p tsconfig.build.json && node tools/prepare-assets.mjs && vite build --config apps/web/vite.config.ts","dev:web":"vite --config apps/web/vite.config.ts","prepack":"npm run build","build:web":"vite build --config apps/web/vite.config.ts","changelog":"node tools/generate-changelog.mjs","tag:force":"node tools/tag-release.mjs --force","typecheck":"tsc -p tsconfig.build.json --noEmit","check:docs":"node tools/check-docs.mjs","check:wire":"node tools/check-wire-contracts.mjs","demo:clean":"node tools/clean-demo-workspaces.mjs","e2e:flight":"tsx apps/cli/e2e-flight-drive.ts","gen:agents":"node tools/gen-agents-md.mjs","gen:skills":"node tools/gen-codex-skills.mjs","smoke:demo":"node tools/smoke-demo.mjs","smoke:pack":"node tools/smoke-pack.mjs","test:watch":"vitest","postinstall":"node tools/fix-node-pty-permissions.mjs","check:cycles":"node tools/check-import-cycles.mjs","gen:demo-prd":"tsx tools/gen-storefront-prd-summary.ts && tsx tools/gen-workflow-workbench-prd-summary.ts","test:coverage":"vitest run --coverage","typecheck:all":"npm run typecheck && npm run typecheck:web && npm run typecheck:server","typecheck:web":"tsc -p apps/web/tsconfig.json --noEmit","publish:package":"node tools/publish-package.mjs","check:boundaries":"node tools/check-feature-boundaries.mjs","typecheck:server":"tsc -p tsconfig.web-server.json --noEmit","changelog:preview":"node tools/generate-changelog.mjs --dry-run","check:conventions":"node tools/check-conventions.mjs","record:getting-started":"node tools/record-getting-started.mjs"},"_npmUser":{"name":"ferterahadi","email":"fernanditerahadi@gmail.com"},"//exports":"Semver surface. Every scaffolded workspace on disk imports these four specifiers; renaming a source file or changing a signature is a breaking release, not a refactor. Read shared/README.md first.","overrides":{"@hono/node-server":"^2.0.5"},"repository":{"url":"git+https://github.com/ferterahadi/canary-lab.git","type":"git"},"//overrides":["Transitive pin for GHSA-frvp-7c67-39w9 — path traversal in @hono/node-server's","serveStatic on Windows, patched in 2.0.5. There is no patched 1.x.","","Why a pin is needed: @modelcontextprotocol/node@2.0.0 hard-declares ^1.19.9,","so ordinary resolution cannot reach the fix.","","Why the major bump is safe: the adapter imports one symbol, getRequestListener.","The vulnerable serveStatic is a separate subpath export that nothing in this","tree imports. Typecheck and the MCP integration suite verify the resolved 2.x.","","Note: npm overrides are honored only in the root project, so this does NOT","protect anyone installing canary-lab as a dependency — only an upstream bump does.","","REMOVE this override once the adapter widens its range to ^1.19.9 || ^2 — tracked at","https://github.com/modelcontextprotocol/typescript-sdk/issues/2531"],"_npmVersion":"12.0.2","description":"The independent local harness for AI-repaired Playwright tests — it runs the tests itself, so a green run can't be faked.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"ws":"^8.21.1","zod":"^4.4.3","hono":"^4.12.34","shiki":"^4.3.1","dotenv":"^16.6.1","recast":"^0.23.12","fastify":"^5.10.0","mammoth":"^1.12.0","node-pty":"^1.1.0","ast-types":"^0.16.1","pdf-parse":"^2.4.5","typescript":"5.9.3","@babel/parser":"^7.29.7","@fastify/static":"^10.1.2","@playwright/test":"^1.62.0","@toon-format/toon":"^4.1.0","@fastify/multipart":"^10.1.0","@fastify/websocket":"^11.3.0","@modelcontextprotocol/node":"^2.0.0","@modelcontextprotocol/client":"^2.0.0","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.23.1","vite":"^8.1.5","react":"^19.2.8","eslint":"^10.8.0","vitest":"^4.1.10","postcss":"^8.5.23","@types/ws":"^8.18.1","happy-dom":"^20.11.1","react-dom":"^19.2.8","remark-gfm":"^4.0.1","@types/node":"^26.1.1","tailwindcss":"^4.3.3","@types/react":"^19.2.14","@xterm/xterm":"^6.0.0","autoprefixer":"^10.5.4","@dnd-kit/core":"^6.3.1","react-markdown":"^10.1.0","@types/react-dom":"^19.2.3","@xterm/addon-fit":"^0.11.0","@dnd-kit/sortable":"^10.0.0","typescript-eslint":"^8.65.0","@dnd-kit/utilities":"^3.2.2","@xterm/addon-webgl":"^0.19.0","@vitest/coverage-v8":"^4.1.10","@tailwindcss/postcss":"^4.3.3","@vitejs/plugin-react":"^6.0.4","eslint-plugin-react-hooks":"^7.1.1"},"_npmOperationalInternal":{"tmp":"tmp/canary-lab_2.2.1_1788174035184_0.8459831415359871","host":"s3://npm-registry-packages-npm-production"}},"2.3.0":{"name":"canary-lab","version":"2.3.0","keywords":["playwright","playwright-testing","e2e","e2e-testing","testing","test-automation","local-development","developer-tools","ai-agents","ai-testing","coding-agents","agent-harness","ai-verification","concurrent-testing","mcp","mcp-server","claude","claude-code","codex"],"author":{"url":"https://github.com/ferterahadi/canary-lab","name":"Fer Terahadi","email":"fernanditerahadi@gmail.com"},"license":"MIT","_id":"canary-lab@2.3.0","maintainers":[{"name":"ferterahadi","email":"fernanditerahadi@gmail.com"}],"homepage":"https://github.com/ferterahadi/canary-lab#readme","bugs":{"url":"https://github.com/ferterahadi/canary-lab/issues"},"bin":{"canary-lab":"dist/apps/cli/cli.js"},"dist":{"shasum":"996c905b984c3db92680905bb267b235427b6907","tarball":"https://registry.npmjs.org/canary-lab/-/canary-lab-2.3.0.tgz","fileCount":638,"integrity":"sha512-k9WoTeYHt4HHtk747xa1z9OYy/lqZAsu/5Yk7HYCT4TZ96VK0j0rKJHSWTU1+AVX9gFYXy0gcuiH+VbtbYFO7Q==","signatures":[{"sig":"MEUCIQDAB/ueJUSWLfAAT0sXQMVwQwzIo7CD9lfzOe4hTAXrjgIgOSP2cg+FCAsu4aIDhwREY9Fk6ePqxRp/y/GBle7LULA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQC8rTD1xJEMTbrYti5Z71KadxtK6TXy5s2yvGVOOezJPwIhALr4Czl8ivuagi2rpLEqlnFfyVunJYvRZPYTq8cRFiT8","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":8380530},"engines":{"npm":">=9.0.0","node":">=22.12.0"},"exports":{"./feature-support/types":"./dist/shared/launcher/types.js","./feature-support/load-env":"./dist/shared/configs/loadEnv.js","./feature-support/playwright-base":"./dist/shared/configs/playwright.base.js","./feature-support/log-marker-fixture":"./dist/shared/e2e-runner/log-marker-fixture.js"},"gitHead":"d82fb38bf67776fee720f7fb8a473c950ec0d038","scripts":{"tag":"node tools/tag-release.mjs","demo":"node tools/smoke-demo.mjs --interactive","lint":"eslint . && npm run check:test-readability","test":"vitest run","build":"node tools/gen-agents-md.mjs && node tools/gen-codex-skills.mjs && node tools/clean-dist.mjs && tsc -p tsconfig.build.json && node tools/prepare-assets.mjs && vite build --config apps/web/vite.config.ts","dev:web":"vite --config apps/web/vite.config.ts","prepack":"npm run build","build:web":"vite build --config apps/web/vite.config.ts","changelog":"node tools/generate-changelog.mjs","tag:force":"node tools/tag-release.mjs --force","typecheck":"tsc -p tsconfig.build.json --noEmit","check:docs":"node tools/check-docs.mjs","check:wire":"node tools/check-wire-contracts.mjs","demo:clean":"node tools/clean-demo-workspaces.mjs","e2e:flight":"tsx apps/cli/e2e-flight-drive.ts","gen:agents":"node tools/gen-agents-md.mjs","gen:skills":"node tools/gen-codex-skills.mjs","smoke:demo":"node tools/smoke-demo.mjs","smoke:pack":"node tools/smoke-pack.mjs","test:watch":"vitest","postinstall":"node tools/fix-node-pty-permissions.mjs","check:cycles":"node tools/check-import-cycles.mjs","gen:demo-prd":"tsx tools/gen-storefront-prd-summary.ts && tsx tools/gen-workflow-workbench-prd-summary.ts","check:english":"node --import tsx tools/check-english.ts","test:coverage":"vitest run --coverage","typecheck:all":"npm run typecheck && npm run typecheck:web && npm run typecheck:server","typecheck:web":"tsc -p apps/web/tsconfig.json --noEmit","publish:package":"node tools/publish-package.mjs","check:boundaries":"node tools/check-feature-boundaries.mjs","typecheck:server":"tsc -p tsconfig.web-server.json --noEmit","changelog:preview":"node tools/generate-changelog.mjs --dry-run","check:conventions":"node tools/check-conventions.mjs","fix:test-readability":"node --import tsx apps/cli/test-readability.ts --rules-only --fix apps shared","check:test-readability":"node --import tsx apps/cli/test-readability.ts --rules-only apps shared","record:getting-started":"node tools/record-getting-started.mjs"},"_npmUser":{"name":"ferterahadi","email":"fernanditerahadi@gmail.com"},"//exports":"Semver surface. Every scaffolded workspace on disk imports these four specifiers; renaming a source file or changing a signature is a breaking release, not a refactor. Read shared/README.md first.","overrides":{"@hono/node-server":"^2.0.5"},"repository":{"url":"git+https://github.com/ferterahadi/canary-lab.git","type":"git"},"//overrides":["Transitive pin for GHSA-frvp-7c67-39w9 — path traversal in @hono/node-server's","serveStatic on Windows, patched in 2.0.5. There is no patched 1.x.","","Why a pin is needed: @modelcontextprotocol/node@2.0.0 hard-declares ^1.19.9,","so ordinary resolution cannot reach the fix.","","Why the major bump is safe: the adapter imports one symbol, getRequestListener.","The vulnerable serveStatic is a separate subpath export that nothing in this","tree imports. Typecheck and the MCP integration suite verify the resolved 2.x.","","Note: npm overrides are honored only in the root project, so this does NOT","protect anyone installing canary-lab as a dependency — only an upstream bump does.","","REMOVE this override once the adapter widens its range to ^1.19.9 || ^2 — tracked at","https://github.com/modelcontextprotocol/typescript-sdk/issues/2531"],"_npmVersion":"12.0.2","description":"The independent local harness for AI-repaired Playwright tests — it runs the tests itself, so a green run can't be faked.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"ws":"^8.21.1","zod":"^4.4.3","hono":"^4.12.34","shiki":"^4.3.1","dotenv":"^16.6.1","recast":"^0.23.12","fastify":"^5.10.0","mammoth":"^1.12.0","node-pty":"^1.1.0","prettier":"3.9.7","ast-types":"^0.16.1","pdf-parse":"^2.4.5","typescript":"5.9.3","@babel/parser":"^7.29.7","@fastify/static":"^10.1.2","@playwright/test":"^1.62.0","@toon-format/toon":"^4.1.0","@fastify/multipart":"^10.1.0","@fastify/websocket":"^11.3.0","@modelcontextprotocol/node":"^2.0.0","@modelcontextprotocol/client":"^2.0.0","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.23.1","vite":"^8.1.5","react":"^19.2.8","eslint":"^10.8.0","vitest":"^4.1.10","postcss":"^8.5.23","@types/ws":"^8.18.1","happy-dom":"^20.11.1","react-dom":"^19.2.8","remark-gfm":"^4.0.1","@types/node":"^26.1.1","tailwindcss":"^4.3.3","@types/react":"^19.2.14","@xterm/xterm":"^6.0.0","autoprefixer":"^10.5.4","@dnd-kit/core":"^6.3.1","react-markdown":"^10.1.0","@types/react-dom":"^19.2.3","@xterm/addon-fit":"^0.11.0","@dnd-kit/sortable":"^10.0.0","typescript-eslint":"^8.65.0","@dnd-kit/utilities":"^3.2.2","@xterm/addon-webgl":"^0.19.0","@vitest/coverage-v8":"^4.1.10","@tailwindcss/postcss":"^4.3.3","@vitejs/plugin-react":"^6.0.4","eslint-plugin-react-hooks":"^7.1.1"},"_npmOperationalInternal":{"tmp":"tmp/canary-lab_2.3.0_1790270282178_0.5382972216577473","host":"s3://npm-registry-packages-npm-production"}},"2.3.1":{"_id":"canary-lab@2.3.1","bin":{"canary-lab":"dist/apps/cli/cli.js"},"bugs":{"url":"https://github.com/ferterahadi/canary-lab/issues"},"dist":{"shasum":"525c95f49388ef39d06ae40d6e867907ab3807d0","tarball":"https://registry.npmjs.org/canary-lab/-/canary-lab-2.3.1.tgz","fileCount":646,"integrity":"sha512-0DwYbMHXpNzZ/C48Hy8QRM1yDra9n+abQ0jTJWBbl8Jw8vTPbdJnLsy35rwa3U9eGxAeE3tmNjqRNLtLY+NGdQ==","signatures":[{"sig":"MEQCIFhbItQk3Xs3RyZulIOZf58dlQvLP5C7ifsMUVP8zuZcAiBlKtUm1gGNmFK6UhvxuqNGzRyZiHzvfEj4ZG3M36zMVw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDUb+B9IVlRECD8sr5mqxra4cwcHDOySA7hZ1ArnimTnQIhAK7G345Ss0Owvw/PAHkYX6YiPGpZyGh1md8e5UVU1usO"}],"unpackedSize":8450282},"name":"canary-lab","author":{"url":"https://github.com/ferterahadi/canary-lab","name":"Fer Terahadi","email":"fernanditerahadi@gmail.com"},"engines":{"npm":">=9.0.0","node":">=22.12.0"},"exports":{"./feature-support/types":"./dist/shared/launcher/types.js","./feature-support/load-env":"./dist/shared/configs/loadEnv.js","./feature-support/playwright-base":"./dist/shared/configs/playwright.base.js","./feature-support/log-marker-fixture":"./dist/shared/e2e-runner/log-marker-fixture.js"},"gitHead":"d8ee0d450d1f2d05aa787a63252084bb41eda1fd","license":"MIT","scripts":{"tag":"node tools/tag-release.mjs","demo":"node tools/smoke-demo.mjs --interactive","lint":"eslint . && npm run check:test-readability","test":"vitest run","build":"node tools/gen-agents-md.mjs && node tools/gen-codex-skills.mjs && node tools/clean-dist.mjs && tsc -p tsconfig.build.json && node tools/prepare-assets.mjs && vite build --config apps/web/vite.config.ts","dev:web":"vite --config apps/web/vite.config.ts","prepack":"npm run build","build:web":"vite build --config apps/web/vite.config.ts","changelog":"node tools/generate-changelog.mjs","tag:force":"node tools/tag-release.mjs --force","typecheck":"tsc -p tsconfig.build.json --noEmit","check:docs":"node tools/check-docs.mjs","check:wire":"node tools/check-wire-contracts.mjs","demo:clean":"node tools/clean-demo-workspaces.mjs","e2e:flight":"tsx apps/cli/e2e-flight-drive.ts","gen:agents":"node tools/gen-agents-md.mjs","gen:skills":"node tools/gen-codex-skills.mjs","smoke:demo":"node tools/smoke-demo.mjs","smoke:pack":"node tools/smoke-pack.mjs","test:watch":"vitest","postinstall":"node tools/fix-node-pty-permissions.mjs","check:cycles":"node tools/check-import-cycles.mjs","gen:demo-prd":"tsx tools/gen-storefront-prd-summary.ts && tsx tools/gen-workflow-workbench-prd-summary.ts","check:english":"node --import tsx tools/check-english.ts","test:coverage":"vitest run --coverage","typecheck:all":"npm run typecheck && npm run typecheck:web && npm run typecheck:server","typecheck:web":"tsc -p apps/web/tsconfig.json --noEmit","publish:package":"node tools/publish-package.mjs","check:boundaries":"node tools/check-feature-boundaries.mjs","typecheck:server":"tsc -p tsconfig.web-server.json --noEmit","changelog:preview":"node tools/generate-changelog.mjs --dry-run","check:conventions":"node tools/check-conventions.mjs","fix:test-readability":"node --import tsx apps/cli/test-readability.ts --rules-only --fix apps shared","check:test-readability":"node --import tsx apps/cli/test-readability.ts --rules-only apps shared","record:getting-started":"node tools/record-getting-started.mjs"},"version":"2.3.1","_npmUser":{"name":"ferterahadi","email":"fernanditerahadi@gmail.com"},"homepage":"https://github.com/ferterahadi/canary-lab#readme","keywords":["playwright","playwright-testing","e2e","e2e-testing","testing","test-automation","local-development","developer-tools","ai-agents","ai-testing","coding-agents","agent-harness","ai-verification","concurrent-testing","mcp","mcp-server","claude","claude-code","codex"],"//exports":"Semver surface. Every scaffolded workspace on disk imports these four specifiers; renaming a source file or changing a signature is a breaking release, not a refactor. Read shared/README.md first.","overrides":{"@hono/node-server":"^2.0.5"},"repository":{"url":"git+https://github.com/ferterahadi/canary-lab.git","type":"git"},"//overrides":["Transitive pin for GHSA-frvp-7c67-39w9 — path traversal in @hono/node-server's","serveStatic on Windows, patched in 2.0.5. There is no patched 1.x.","","Why a pin is needed: @modelcontextprotocol/node@2.0.0 hard-declares ^1.19.9,","so ordinary resolution cannot reach the fix.","","Why the major bump is safe: the adapter imports one symbol, getRequestListener.","The vulnerable serveStatic is a separate subpath export that nothing in this","tree imports. Typecheck and the MCP integration suite verify the resolved 2.x.","","Note: npm overrides are honored only in the root project, so this does NOT","protect anyone installing canary-lab as a dependency — only an upstream bump does.","","REMOVE this override once the adapter widens its range to ^1.19.9 || ^2 — tracked at","https://github.com/modelcontextprotocol/typescript-sdk/issues/2531"],"_npmVersion":"12.0.2","description":"The independent local harness for AI-repaired Playwright tests — it runs the tests itself, so a green run can't be faked.","directories":{},"maintainers":[{"name":"ferterahadi","email":"fernanditerahadi@gmail.com"}],"_nodeVersion":"22.22.2","dependencies":{"ws":"^8.21.1","zod":"^4.4.3","hono":"^4.12.34","shiki":"^4.3.1","dotenv":"^16.6.1","recast":"^0.23.12","fastify":"^5.10.0","mammoth":"^1.12.0","node-pty":"^1.1.0","prettier":"3.9.7","ast-types":"^0.16.1","pdf-parse":"^2.4.5","typescript":"5.9.3","@babel/parser":"^7.29.7","@fastify/static":"^10.1.2","@playwright/test":"^1.62.0","@toon-format/toon":"^4.1.0","@fastify/multipart":"^10.1.0","@fastify/websocket":"^11.3.0","@modelcontextprotocol/node":"^2.0.0","@modelcontextprotocol/client":"^2.0.0","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.23.1","vite":"^8.1.5","react":"^19.2.8","eslint":"^10.8.0","vitest":"^4.1.10","postcss":"^8.5.23","@types/ws":"^8.18.1","happy-dom":"^20.11.1","react-dom":"^19.2.8","remark-gfm":"^4.0.1","@types/node":"^26.1.1","tailwindcss":"^4.3.3","@types/react":"^19.2.14","@xterm/xterm":"^6.0.0","autoprefixer":"^10.5.4","@dnd-kit/core":"^6.3.1","react-markdown":"^10.1.0","@types/react-dom":"^19.2.3","@xterm/addon-fit":"^0.11.0","@dnd-kit/sortable":"^10.0.0","typescript-eslint":"^8.65.0","@dnd-kit/utilities":"^3.2.2","@xterm/addon-webgl":"^0.19.0","@vitest/coverage-v8":"^4.1.10","@tailwindcss/postcss":"^4.3.3","@vitejs/plugin-react":"^6.0.4","eslint-plugin-react-hooks":"^7.1.1"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/canary-lab_2.3.1_1790357238500_0.31306517192981675"}}},"time":{"created":"2026-04-15T18:38:55.590Z","modified":"2026-09-25T17:27:18.875Z","0.1.0":"2026-04-15T18:38:55.877Z","0.2.0":"2026-04-16T04:02:19.114Z","0.2.1":"2026-04-16T08:07:24.378Z","0.2.2":"2026-04-16T08:25:30.254Z","0.3.0":"2026-04-16T08:30:48.635Z","0.4.0":"2026-04-16T16:51:28.828Z","0.5.0":"2026-04-17T03:22:49.320Z","0.5.1":"2026-04-17T07:30:21.549Z","0.6.0":"2026-04-17T11:07:37.716Z","0.7.0":"2026-04-19T09:51:20.577Z","0.8.0":"2026-04-21T17:46:39.565Z","0.9.0":"2026-04-24T04:33:01.345Z","0.9.1":"2026-04-24T19:20:13.958Z","0.9.2":"2026-04-24T19:38:57.275Z","0.9.3":"2026-04-26T18:11:30.254Z","1.0.0":"2026-05-10T17:18:20.387Z","1.0.1":"2026-05-11T05:56:56.170Z","1.0.2":"2026-05-11T11:05:42.039Z","1.0.3":"2026-05-11T18:33:14.286Z","1.0.4":"2026-05-12T06:46:49.716Z","1.0.5":"2026-05-13T19:17:07.691Z","1.0.6":"2026-05-15T17:42:22.978Z","1.0.7":"2026-05-16T20:44:13.538Z","1.0.8":"2026-05-17T14:51:15.537Z","1.1.0":"2026-05-28T15:37:16.782Z","1.2.0":"2026-06-01T17:46:43.183Z","1.3.0":"2026-06-14T07:47:00.297Z","1.3.1":"2026-06-15T03:08:50.649Z","1.3.2":"2026-06-16T05:36:14.871Z","1.4.0":"2026-06-25T18:06:31.660Z","1.4.1":"2026-06-27T18:08:34.318Z","1.4.2":"2026-06-30T09:25:09.826Z","1.5.0":"2026-07-01T07:40:59.727Z","1.5.1":"2026-07-02T17:36:07.100Z","2.0.0":"2026-08-25T08:30:01.343Z","2.0.1":"2026-08-25T11:13:59.578Z","2.1.0":"2026-08-28T07:29:06.688Z","2.2.0":"2026-08-30T14:36:39.911Z","2.2.1":"2026-08-31T11:00:35.416Z","2.3.0":"2026-09-24T17:18:02.357Z","2.3.1":"2026-09-25T17:27:18.731Z"},"bugs":{"url":"https://github.com/ferterahadi/canary-lab/issues"},"author":{"url":"https://github.com/ferterahadi/canary-lab","name":"Fer Terahadi","email":"fernanditerahadi@gmail.com"},"license":"MIT","homepage":"https://github.com/ferterahadi/canary-lab#readme","keywords":["playwright","playwright-testing","e2e","e2e-testing","testing","test-automation","local-development","developer-tools","ai-agents","ai-testing","coding-agents","agent-harness","ai-verification","concurrent-testing","mcp","mcp-server","claude","claude-code","codex"],"repository":{"url":"git+https://github.com/ferterahadi/canary-lab.git","type":"git"},"description":"The independent local harness for AI-repaired Playwright tests — it runs the tests itself, so a green run can't be faked.","maintainers":[{"name":"ferterahadi","email":"fernanditerahadi@gmail.com"}],"readme":"# Canary Lab\n\n[![npm](https://img.shields.io/npm/v/canary-lab.svg)](https://www.npmjs.com/package/canary-lab)\n[![license](https://img.shields.io/npm/l/canary-lab.svg)](LICENSE)\n\n**Give Claude or Codex an app repo. Get a Playwright evaluation backed by a run the agent cannot mark green itself.**\n\nYour agent investigates the app, writes tests, and fixes application failures. Canary Lab starts the services, runs Playwright, and records the results. You get a report that links requirements, tests, captured evidence, and the actual pass or fail result.\n\n![Canary Lab end-to-end: an AI agent scaffolds a Checkout test suite, checks requirement coverage (47%), authors more tests to reach 100%, runs the suite green (12/12), and exports a verified evaluation report](docs/assets/canary-lab-flight.gif)\n\n## Quick Start\n\nYou need Node.js 22.12 or newer and npm 9 or newer.\n\n1. Create a Canary Lab workspace. This is separate from the app repo you want to test:\n\n   ```bash\n   npx canary-lab init my-lab\n   ```\n\n   `init` installs the workspace dependencies and Chromium, then registers the Canary Lab skills and one Model Context Protocol (MCP) connection, exposed as `exec`, for supported Claude and Codex clients. The workspace holds test suites and run evidence; your app stays in its own repo.\n\n2. Restart Claude or Codex so it discovers the skill and connection. In its chat, ask it to test a specific flow using your app's absolute path:\n\n   ```text\n   /canary-lab /absolute/path/to/your-app \"checkout flow\"\n   ```\n\n3. Follow the Flight (the end-to-end evaluation) in your agent or open the Canary Lab interface. When the report is ready, open its evaluation archive to review the test results and captured evidence. A failed run keeps its failed verdict in the report.\n\nThe connection starts the local Canary Lab service when needed. To open the interface yourself:\n\n```bash\ncd my-lab\nnpx canary-lab ui\n```\n\nIf `/canary-lab` or the Canary Lab `exec` tool is missing, run `npx canary-lab setup --force` from the workspace and restart your agent. Setup reports each saved connection separately; see [configuration repair](docs/COMMANDS.md#repair-agent-configuration) for skill migration, backups, and verification outcomes.\n\n## What Happens During a Flight\n\n`/canary-lab` starts one resumable Flight:\n\nscan repo → create suite → collect requirements → author and map tests → run and repair → export evaluation → check readiness for parallel runs\n\nThe skill keeps the reasoning work in your current Claude or Codex session. Canary Lab performs the mechanical checks and calculates every stage result from saved evidence.\n\n- **Requirements stay reviewable.** Add a product requirements document, link a local file, gather relevant repo documents, or infer requirements from the branch diff.\n- **Coverage is explicit.** Tests map to requirements and paths instead of producing a guessed percentage.\n- **Repairs are usually isolated.** Runs use separate Git checkouts when available. Before a suite is prepared for parallel runs, worktree creation failure can make a run use the app's working copy; Canary Lab warns you.\n- **Progress survives interruption.** Run `/canary-lab` again with the same repo to continue the existing Flight.\n- **The evaluation is the deliverable.** The archive preserves the real verdict, test evidence, any captured browser media, and per-test reasoning. It is available before the separate Parallel setup stage finishes.\n\n## Why the Verdict Is Independent\n\nAn agent can propose a fix and say it works. Canary Lab checks that claim with its own Playwright run. The agent can read the evidence and request a rerun, but its statement alone cannot turn a failed run into a pass.\n\nCanary Lab adds:\n\n- **Results the agent does not own.** The harness runs the tests and holds the pass/fail result.\n- **Controlled concurrency.** After Canary Lab verifies that the app accepts assigned ports, runs can use separate ports and Git worktrees. Conflicting work waits in a queue.\n- **Safe environment switching.** Environment files are backed up before changes and restored when the run ends.\n\n## Choose the Right Skill\n\nUse `/canary-lab` for the complete journey. Use a focused skill when you need only one part:\n\n| Goal | Skill |\n| --- | --- |\n| Take a bare repo through a complete evaluation | `/canary-lab` |\n| Run an existing suite and repair application failures | `/canary-lab-run` |\n| Verify a running or deployed environment | `/canary-lab-verify` |\n| Create a suite and its Playwright tests | `/canary-lab-author` |\n| Build the requirement-to-test coverage ledger | `/canary-lab-coverage` |\n| Prepare a suite for concurrent runs | `/canary-lab-portify` |\n| Export a completed run as an evaluation | `/canary-lab-export` |\n\nThe skills share the same workspace, runs, evidence, and UI. Work started in one surface appears in the others.\n\n## Use the UI or CLI Directly\n\nThe agent skill is the normal interactive path. The same Flight can also start from the **Flights** view or from a terminal:\n\n```bash\nnpx canary-lab flight /absolute/path/to/your-app \"checkout flow\"\n```\n\nUse the CLI for shell automation or when you want Canary Lab to conduct the Flight outside an existing agent conversation. Calling it again follows an active Flight or resumes a paused one. A completed Flight needs `--redo` or `--from-stage` to run again.\n\nThe UI and MCP server share one configurable port, `7421` by default. Choose another during setup with `npx canary-lab init my-lab --port 8200`, or change it later in Project Settings. The `ui --port` option is not supported.\n\nCustom MCP clients should connect to `http://localhost:<port>/mcp?profile=compact`.\n\n## Playwright Without a New Test Language\n\nCanary Lab suites use normal Playwright tests plus a service configuration that names your existing development commands. Canary Lab starts each service, waits for health checks, and tags the output so failures map back to the correct test. Once the app is prepared for parallel runs, Canary Lab can assign free ports to concurrent runs.\n\nSee [Suite Folders](docs/FEATURES.md) for the file structure and examples, or [Guide](docs/GUIDE.md) for the complete run and repair workflow.\n\nNew workspaces include demonstrations for a prepared repair loop, a bare repo Flight, and focused coverage and authoring workflows. Delete the demo files after exploring them.\n\n### Works With Docker Compose\n\nUse Docker Compose for infrastructure such as Postgres or Redis, and let Canary Lab start application services with their normal development commands. This keeps hot reload available during repair.\n\n## How It Compares\n\n| | Plain Playwright | Docker Compose with watch | Hosted dashboard | Canary Lab |\n| --- | :---: | :---: | :---: | :---: |\n| Runs existing development commands with hot reload | One service | Needs a development image and watch rules | Varies | Yes |\n| Boots several services together | You script it | Yes | Varies | Yes |\n| Runs concurrently on one machine | Manual | Not built in | Hosted | After port readiness is verified |\n| Keeps the run verdict separate from the repair agent's report | Manual | Manual | Varies | Yes |\n| Switches environment files with backup and restore | Manual | Manual | No | Yes |\n| Keeps harness data on your machine | Yes | Yes | No | Yes |\n\nUse Canary Lab when failures depend on service startup, environment files, backend logs, requirement coverage, or evidence the agent should not control. Plain `npx playwright test` is enough when you do not need orchestration or independent repair evidence. Harness data stays local; repair agents may still need network access.\n\n## Updating a Workspace\n\nWith Node.js 22.12 or newer:\n\n```bash\nnpm install --save-dev canary-lab@latest\nnpx canary-lab upgrade\n```\n\nRestart Canary Lab and connected agent apps afterwards so they load the refreshed skills and connection path. Existing suite folders under `features/` and personal agent files are preserved.\n\n## Requirements\n\n- Node.js 22.12 or newer and npm 9 or newer.\n- Chromium for Playwright, installed automatically by `canary-lab init` unless installation is skipped.\n- A local UI server, started automatically through the agent connection or manually with `npx canary-lab ui`.\n- Optional repair agents: supported Claude or Codex command-line clients on `PATH`.\n\n`node-pty` gives each service a real terminal. Its prebuilt binaries require no normal installation-time compilation. A postinstall step restores the execute bit on its helper binary when needed; it does nothing on Windows or when `node-pty` is absent.\n\n## Limitations\n\n- Repairs are only as useful as your service logs.\n- Environment runs overwrite target files while active. If a process is killed during backup or restore, reopen the UI and use the environment controls to recover.\n- Environment values are not validated, so stale configuration can surface as unclear failures.\n- Linux and Windows workflows are not polished yet.\n\n## Documentation\n\n| Document | What it covers |\n| --- | --- |\n| [Changelog](docs/CHANGELOG.md) | Release history. |\n| [Roadmap](docs/ROADMAP.md) | Planned product milestones and their evidence bars. |\n| [Guide](docs/GUIDE.md) | Environment switching, run output, repairs, and evaluation reports. |\n| [Commands](docs/COMMANDS.md) | Full CLI and trigger-surface reference. |\n| [Suite Folders](docs/FEATURES.md) | Suite structure, configuration, and Playwright tests. |\n| [Architecture](docs/ARCHITECTURE.md) | Module map, run lifecycle, concurrency, healing, and MCP. |\n| [Product Requirements](docs/PRD.md) | Product intent, non-goals, and quality bars. |\n| [Design System](docs/DESIGN-SYSTEM.md) | Web UI tokens, primitives, and layout patterns. |\n| [Contributing](docs/CONTRIBUTING.md) | Code orientation and development workflow. |\n\n## License\n\n[MIT](LICENSE)\n","readmeFilename":"README.md"}