@gfdelarue/testkit 0.5.0 → 0.6.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 (95) hide show
  1. package/README.md +136 -110
  2. package/dist/app/bugs/draft.js +2 -2
  3. package/dist/app/bugs/guide.js +1 -1
  4. package/dist/app/bugs/record.js +2 -2
  5. package/dist/app/campaigns/index.js +2 -2
  6. package/dist/app/destroy/index.js +1 -1
  7. package/dist/app/discover/index.js +2 -2
  8. package/dist/app/environments/static-values.js +1 -1
  9. package/dist/app/environments/supplied.js +1 -1
  10. package/dist/app/inspect/index.js +1 -1
  11. package/dist/app/lint/native.js +1 -1
  12. package/dist/app/lint/options.js +1 -1
  13. package/dist/app/run/engine-orchestration.js +1 -1
  14. package/dist/app/run/environment.js +1 -1
  15. package/dist/app/run/orchestrator.js +1 -1
  16. package/dist/app/run/request.js +1 -1
  17. package/dist/app/run/run-finalization.js +1 -1
  18. package/dist/app/run/task-batches.js +1 -1
  19. package/dist/app/run/worker-loop.js +1 -1
  20. package/dist/app/status/model.js +1 -1
  21. package/dist/app/status/runs.js +1 -1
  22. package/dist/app/typecheck/index.js +4 -4
  23. package/dist/cli/command-catalog.js +1 -1
  24. package/dist/cli/command-flags.js +1 -1
  25. package/dist/cli/commands/artifacts.js +2 -2
  26. package/dist/cli/commands/discover.js +1 -1
  27. package/dist/cli/commands/guard/unsafe-entrypoint.js +1 -1
  28. package/dist/cli/commands/run.js +2 -2
  29. package/dist/cli/commands/typecheck.js +1 -1
  30. package/dist/cli/commands/workspace.js +1 -1
  31. package/dist/config/authoring/database-fixture-discovery.js +1 -0
  32. package/dist/config/authoring/index.js +1 -1
  33. package/dist/config/loader/config-loader.js +1 -1
  34. package/dist/config/loader/decode-discovery.js +1 -1
  35. package/dist/config/loader/discover-tests.js +1 -1
  36. package/dist/config/loader/discovery.js +2 -2
  37. package/dist/config/loader/file-metadata.js +1 -1
  38. package/dist/config/loader/groups.js +2 -1
  39. package/dist/config/loader/load.js +1 -1
  40. package/dist/config/loader/managed-configs.js +1 -1
  41. package/dist/config/loader/owned-discovery.js +1 -1
  42. package/dist/config/loader/runtime-isolation.js +1 -1
  43. package/dist/config/loader/skip-config.js +1 -1
  44. package/dist/database/admin.js +2 -2
  45. package/dist/database/configured-steps.js +1 -1
  46. package/dist/domain/identifiers.js +1 -1
  47. package/dist/domain/retired-test-types.js +1 -1
  48. package/dist/domain/suite-selection.js +1 -1
  49. package/dist/domain/test-types.js +1 -1
  50. package/dist/engines/catalog.js +1 -1
  51. package/dist/engines/definitions.js +1 -1
  52. package/dist/engines/environment/index.js +1 -1
  53. package/dist/engines/installations/node-vitest.js +1 -1
  54. package/dist/engines/installations/playwright.js +1 -1
  55. package/dist/engines/managed-module-resolution.js +6 -2
  56. package/dist/engines/node-vitest/adapter/adapter.js +1 -1
  57. package/dist/engines/node-vitest/adapter/driver.js +2 -2
  58. package/dist/engines/node-vitest/adapter/evidence.js +2 -2
  59. package/dist/engines/node-vitest/adapter/workspace.js +8 -24
  60. package/dist/engines/node-vitest/inventory/index.js +2 -2
  61. package/dist/engines/node-vitest/inventory/list-files.js +3 -3
  62. package/dist/engines/node-vitest/runtime/data/index.js +1 -1
  63. package/dist/engines/node-vitest/runtime/data/report.js +1 -1
  64. package/dist/engines/node-vitest/runtime/data/scenario.js +2 -2
  65. package/dist/engines/node-vitest/runtime/runtime-input.js +1 -1
  66. package/dist/engines/playwright/adapter/adapter.js +1 -1
  67. package/dist/engines/playwright/adapter/config.js +2 -2
  68. package/dist/engines/playwright/runtime/managed-test.js +1 -0
  69. package/dist/environment/lifecycle.js +1 -1
  70. package/dist/environment/run-environment.js +1 -1
  71. package/dist/evidence/artifact-config.js +1 -1
  72. package/dist/evidence/maintenance.js +1 -0
  73. package/dist/evidence/read-run.js +1 -1
  74. package/dist/kernel/known-keys.js +1 -0
  75. package/dist/process/execa-bundle.json +1 -1
  76. package/dist/repo/fingerprint-policy.js +1 -1
  77. package/dist/steps/configured-step-testkit-modules.js +1 -1
  78. package/dist/toolchains/index.js +2 -2
  79. package/dist/toolchains/vitest/index.js +1 -1
  80. package/dist/types/config.d.ts +7 -86
  81. package/dist/types/environment.d.ts +6 -0
  82. package/dist/types/node-vitest-data.d.ts +2 -218
  83. package/dist/types/workspace.d.ts +27 -11
  84. package/docs/bug-records.md +3 -8
  85. package/docs/engines.md +63 -17
  86. package/docs/release-notes.md +2116 -0
  87. package/docs/test-types.md +19 -69
  88. package/package.json +2 -5
  89. package/testkit-config-schema.md +65 -128
  90. package/dist/app/lint/rules/data.js +0 -1
  91. package/dist/config/authoring/runtime.js +0 -1
  92. package/dist/engines/node-vitest/runtime/contract/index.js +0 -1
  93. package/dist/engines/node-vitest/runtime/data/http.js +0 -1
  94. package/dist/engines/node-vitest/runtime/data/runner.js +0 -1
  95. package/dist/types/node-vitest-contract.d.ts +0 -75
@@ -1 +1 @@
1
- export{formatTestTypeLabel}from"../../domain/test-types.js";import{runModel as p}from"../../evidence/index.js";import{readRunDocument as k}from"../../evidence/read-run.js";import m from"fs";import o from"path";import{errorMessage as l}from"../../kernel/error-serialization.js";import{isEngineProfileIdentity as D}from"../../engines/catalog.js";import{loadDiscoveryContext as S,hasDiscoveryErrors as b,buildDiscoveryErrorFromDiagnostics as N,formatDisplayName as $}from"../../config/loader/index.js";import{collectServiceStatus as A,collectConfiguredServiceStatus as M}from"../status/index.js";export{discoverTests,fileDisplayName,formatDisplayName,testTypeContract}from"../../config/loader/index.js";export{listRunBundles,loadRunBundleArtifact,loadRunBundleManifest,verifyRunBundle}from"../../evidence/index.js";const C=3,j=24,x=String;export async function inspectWorkspace(e={}){const t=V(e.targetLimit,j),r=new Date().toISOString(),n=await F(e),a=n.data?.product.directory||o.resolve(process.cwd(),e.dir||"."),[s,i,u]=await Promise.all([e.status===!1?E():P(e,n.context),f(a,"latest"),f(a,"live")]),d=i.data===null?null:p(i.data),c=u.data===null?null:p(u.data),h=g(d,"latest"),I=g(c,"live"),T=L({discovery:n.data,group:e.group||null,latestRun:d,liveRun:c,limit:t}),w=[...n.warnings,...s.warnings,...i.warnings,...u.warnings];return{schemaVersion:C,source:"testkit-workspace",generatedAt:r,product:n.data?.product||{directory:a,name:o.basename(a)},discovery:n.data?{configFile:n.data.configFile||null,diagnostics:n.data.diagnostics,summary:n.data.summary}:null,status:s.data,runs:{latest:h,live:I},targets:T,activity:z(s.data),warnings:w}}async function F(e){try{const{discovery:t,context:r,notice:n}=await S({diagnostics:"report",dir:e.dir,runnableOnly:!1,group:e.group||null});n!==null&&e.notice?.(n);const a=t.diagnostics.filter(s=>s.severity==="error").map(s=>`Discovery diagnostic: ${s.message}`);return{data:t,warnings:a,context:r}}catch(t){return{data:null,context:null,warnings:[`Discovery unavailable: ${l(t)}`]}}}async function P(e,t){try{if(t&&b(t.discovery.diagnostics))throw N(t.discovery.diagnostics);const r=t?M(t.services):await A({dir:e.dir});return{data:B(r),warnings:[]}}catch(r){return{data:{ok:!1,results:[]},warnings:[`Status unavailable: ${l(r)}`]}}}function E(){return Promise.resolve({data:{ok:!0,results:[]},warnings:[]})}function f(e,t){const r=t==="live"?"live.json":"latest.json",n=o.join(e,".testkit","results",r);if(!m.existsSync(n))return Promise.resolve({data:null,warnings:[]});try{const a=k(JSON.parse(m.readFileSync(n,"utf8")),n);return Promise.resolve({data:a,warnings:[]})}catch(a){return Promise.resolve({data:null,warnings:[`${t} run artifact unavailable: ${l(a)}`]})}}function B(e){return{ok:!0,results:e.map(t=>({caches:t.caches,hasState:t.hasState,name:t.name,product:t.product,runtimeGraphs:t.runtimeGraphs.map(r=>({currentRuntimeDirCount:r.currentRuntimeDirs.length,desired:r.desired,exists:r.exists,name:r.name,orphan:r.orphan,runtimeDirCount:r.runtimeDirCount,staleRuntimeDirCount:r.staleRuntimeDirs.length})),runs:{active:t.runs.active,stale:t.runs.stale,total:t.runs.total},warnings:t.warnings}))}}function g(e,t){if(e===null)return null;const{run:r,summary:n}=e;return{durationMs:r.durationMs,generatedAt:e.generatedAt,id:r.id,startedAt:r.startedAt,status:r.status,types:[...r.types],source:t,files:{failed:n?.files.failed??0,notRun:n?.files.notRun??0,passed:n?.files.passed??0,skipped:n?.files.skipped??0,total:n?.files.total??0},groups:{failed:n?.groups.failed??0,passed:n?.groups.passed??0,skipped:n?.groups.skipped??0,total:n?.groups.total??0},suites:{completed:n?.suites.completed??0,failed:n?.suites.failed??0,passed:n?.suites.passed??0,skipped:n?.suites.skipped??0,total:n?.suites.total??0}}}function L({discovery:e,group:t,latestRun:r,liveRun:n,limit:a}){const s=[O(e),...y(n,"live",t),...y(r,"latest",t),...W(e).slice(0,Math.ceil(a/2)),..._(e).slice(0,a)].filter(i=>i!==null);return G(s).slice(0,a)}function O(e){return e?{detail:e.product.directory,id:"project:all",kind:"project",label:`All tests in ${e.product.name}`,runnable:!0,source:"discovery"}:null}function W(e){return(e?.suites||[]).map(t=>({detail:[t.group,t.testType,t.engineId,t.profileId].filter(Boolean).join(" - "),id:`suite:${t.group}:${t.testType??""}:${t.engineId}:${t.profileId}:${t.name}`,engineId:t.engineId,group:t.group,kind:"suite",label:t.displayName||t.name,profileId:t.profileId,runnable:t.activeFileCount>0,source:"discovery",suiteName:t.name,testType:t.testType??null}))}function _(e){return(e?.files||[]).filter(t=>!t.skipped).map(t=>v(t,"discovery"))}function y(e,t,r){const n=[];for(const a of e?.groups??[])if(!(r!==null&&a.name!==r))for(const s of a.suites)for(const i of s.files)i.status!=="failed"&&!i.error||n.push(v({displayName:R(i.path),engineId:s.engineId,path:i.path,profileId:s.profileId,group:a.name,suiteName:s.name,testType:s.testType},t,"failed"));return n}function v(e,t,r=null){return{detail:[e.group,e.testType,e.engineId,e.profileId,e.suiteName].filter(Boolean).join(" - "),filePath:e.path,engineId:e.engineId,group:e.group||null,id:`file:${e.group||""}:${e.testType??""}:${e.engineId}:${e.profileId}:${e.path}`,kind:"file",label:e.displayName||R(e.path),profileId:e.profileId,runnable:D(e),source:t,status:r||null,suiteName:e.suiteName||null,testType:e.testType??null}}function z(e){return{activeRuns:e.results.reduce((t,r)=>t+r.runs.active,0),staleRuns:e.results.reduce((t,r)=>t+r.runs.stale,0)}}function G(e){const t=new Set,r=[];for(const n of e)t.has(n.id)||(t.add(n.id),r.push(n));return r}function V(e,t){const r=Number(e);return Number.isFinite(r)?Math.max(1,Math.min(100,Math.round(r))):t}function R(e){return $(o.basename(x(e||"test")).replace(/\.testkit\.[cm]?[jt]sx?$/,""))}
1
+ export{formatTestTypeLabel}from"../../domain/test-types.js";import{runModel as p}from"../../evidence/index.js";import{readRunDocument as k}from"../../evidence/read-run.js";import m from"fs";import o from"path";import{errorMessage as l}from"../../kernel/error-serialization.js";import{isEngineProfileIdentity as D}from"../../engines/catalog.js";import{loadDiscoveryContext as S,hasDiscoveryErrors as b,buildDiscoveryErrorFromDiagnostics as N,formatDisplayName as $}from"../../config/loader/index.js";import{collectServiceStatus as A,collectConfiguredServiceStatus as M}from"../status/index.js";export{discoverTests,fileDisplayName,formatDisplayName,testTypeContract}from"../../config/loader/index.js";export{listRunBundles,loadRunBundleArtifact,loadRunBundleManifest,verifyRunBundle}from"../../evidence/index.js";const C=3,j=24,x=String;export async function inspectWorkspace(e={}){const t=V(e.targetLimit,j),r=new Date().toISOString(),n=await F(e),a=n.data?.product.directory||o.resolve(process.cwd(),e.dir||"."),[s,i,u]=await Promise.all([e.status===!1?E():P(e,n.context),f(a,"latest"),f(a,"live")]),d=i.data===null?null:p(i.data),c=u.data===null?null:p(u.data),h=g(d,"latest"),I=g(c,"live"),T=L({discovery:n.data,group:e.group||null,latestRun:d,liveRun:c,limit:t}),w=[...n.warnings,...s.warnings,...i.warnings,...u.warnings];return{schemaVersion:C,source:"testkit-workspace",generatedAt:r,product:n.data?.product||{directory:a,name:o.basename(a)},discovery:n.data?{configFile:n.data.configFile||null,diagnostics:n.data.diagnostics,summary:n.data.summary}:null,status:s.data,runs:{latest:h,live:I},targets:T,activity:z(s.data),warnings:w}}async function F(e){try{const{discovery:t,context:r}=await S({diagnostics:"report",dir:e.dir,runnableOnly:!1,group:e.group||null}),n=t.diagnostics.filter(a=>a.severity==="error").map(a=>`Discovery diagnostic: ${a.message}`);return{data:t,warnings:n,context:r}}catch(t){return{data:null,context:null,warnings:[`Discovery unavailable: ${l(t)}`]}}}async function P(e,t){try{if(t&&b(t.discovery.diagnostics))throw N(t.discovery.diagnostics);const r=t?M(t.services):await A({dir:e.dir});return{data:B(r),warnings:[]}}catch(r){return{data:{ok:!1,results:[]},warnings:[`Status unavailable: ${l(r)}`]}}}function E(){return Promise.resolve({data:{ok:!0,results:[]},warnings:[]})}function f(e,t){const r=t==="live"?"live.json":"latest.json",n=o.join(e,".testkit","results",r);if(!m.existsSync(n))return Promise.resolve({data:null,warnings:[]});try{const a=k(JSON.parse(m.readFileSync(n,"utf8")),n);return Promise.resolve({data:a,warnings:[]})}catch(a){return Promise.resolve({data:null,warnings:[`${t} run artifact unavailable: ${l(a)}`]})}}function B(e){return{ok:!0,results:e.map(t=>({caches:t.caches,hasState:t.hasState,name:t.name,product:t.product,runtimeGraphs:t.runtimeGraphs.map(r=>({currentRuntimeDirCount:r.currentRuntimeDirs.length,desired:r.desired,exists:r.exists,name:r.name,orphan:r.orphan,runtimeDirCount:r.runtimeDirCount,staleRuntimeDirCount:r.staleRuntimeDirs.length})),runs:{active:t.runs.active,stale:t.runs.stale,total:t.runs.total},warnings:t.warnings}))}}function g(e,t){if(e===null)return null;const{run:r,summary:n}=e;return{durationMs:r.durationMs,generatedAt:e.generatedAt,id:r.id,startedAt:r.startedAt,status:r.status,types:[...r.types],source:t,files:{failed:n?.files.failed??0,notRun:n?.files.notRun??0,passed:n?.files.passed??0,skipped:n?.files.skipped??0,total:n?.files.total??0},groups:{failed:n?.groups.failed??0,passed:n?.groups.passed??0,skipped:n?.groups.skipped??0,total:n?.groups.total??0},suites:{completed:n?.suites.completed??0,failed:n?.suites.failed??0,passed:n?.suites.passed??0,skipped:n?.suites.skipped??0,total:n?.suites.total??0}}}function L({discovery:e,group:t,latestRun:r,liveRun:n,limit:a}){const s=[O(e),...y(n,"live",t),...y(r,"latest",t),...W(e).slice(0,Math.ceil(a/2)),..._(e).slice(0,a)].filter(i=>i!==null);return G(s).slice(0,a)}function O(e){return e?{detail:e.product.directory,id:"project:all",kind:"project",label:`All tests in ${e.product.name}`,runnable:!0,source:"discovery"}:null}function W(e){return(e?.suites||[]).map(t=>({detail:[t.group,t.testType,t.engineId,t.profileId].filter(Boolean).join(" - "),id:`suite:${t.group}:${t.testType??""}:${t.engineId}:${t.profileId}:${t.name}`,engineId:t.engineId,group:t.group,kind:"suite",label:t.displayName||t.name,profileId:t.profileId,runnable:t.activeFileCount>0,source:"discovery",suiteName:t.name,testType:t.testType??null}))}function _(e){return(e?.files||[]).filter(t=>!t.skipped).map(t=>v(t,"discovery"))}function y(e,t,r){const n=[];for(const a of e?.groups??[])if(!(r!==null&&a.name!==r))for(const s of a.suites)for(const i of s.files)i.status!=="failed"&&!i.error||n.push(v({displayName:R(i.path),engineId:s.engineId,path:i.path,profileId:s.profileId,group:a.name,suiteName:s.name,testType:s.testType},t,"failed"));return n}function v(e,t,r=null){return{detail:[e.group,e.testType,e.engineId,e.profileId,e.suiteName].filter(Boolean).join(" - "),filePath:e.path,engineId:e.engineId,group:e.group||null,id:`file:${e.group||""}:${e.testType??""}:${e.engineId}:${e.profileId}:${e.path}`,kind:"file",label:e.displayName||R(e.path),profileId:e.profileId,runnable:D(e),source:t,status:r||null,suiteName:e.suiteName||null,testType:e.testType??null}}function z(e){return{activeRuns:e.results.reduce((t,r)=>t+r.runs.active,0),staleRuns:e.results.reduce((t,r)=>t+r.runs.stale,0)}}function G(e){const t=new Set,r=[];for(const n of e)t.has(n.id)||(t.add(n.id),r.push(n));return r}function V(e,t){const r=Number(e);return Number.isFinite(r)?Math.max(1,Math.min(100,Math.round(r))):t}function R(e){return $(o.basename(x(e||"test")).replace(/\.testkit\.[cm]?[jt]sx?$/,""))}
@@ -1 +1 @@
1
- import m from"node:path";import{posixPath as j}from"../../process/files/paths.js";import{LINT_RULE_NAMES as _}from"./options.js";import{compareFindings as b,findingKey as B,isTypeScriptLikePath as L,matchesAnyPathPattern as p,normalizeFinding as g,SOURCE_IGNORES as M}from"./shared.js";import{createSyntaxPolicy as F}from"./rules/syntax.js";import{createDataPolicy as R}from"./rules/data.js";import{createUnitPolicy as U}from"./rules/unit.js";import{createEngineImportPolicy as $}from"./rules/engine-imports.js";export async function lintProject({productDir:r,files:n,trackedFiles:a,options:s}){const T=await A(),[{ESLint:y},h]=T;if(y.version!=="10.7.0"||h.version!=="8.65.0")throw new Error("Testkit lint requires its managed eslint@10.7.0 and @typescript-eslint/parser@8.65.0 installation");const k=new Map,c=_.filter(t=>s.rules[t].enabled),x=Object.fromEntries(c.filter(t=>t!=="testkitBoundary").map(t=>{const e=s.rules[t],i={meta:{type:"problem",schema:[],messages:{violation:"{{message}}"}},defaultOptions:[],create(o){return(()=>{const P=j(m.relative(r,o.filename)),u={context:o,file:P,report:(l,C,N,d)=>{const O=g({file:P,ruleName:t,ruleId:e.ruleId,kind:C,target:N,message:d,line:l.loc.start.line,snippet:o.sourceCode.getText(l).split(/\r?\n/u)[0]});k.set(E(o.filename,l.loc.start.line,l.loc.start.column+1,d),O),o.report({node:l,messageId:"violation",data:{message:d}})},options:s};return t==="engineImports"?$(u):t==="dataSuiteContract"?R(u):t==="unitTestBoundaries"?U(u):F(t,u,n)})()}};return[e.ruleId,i]})),S=new y({cwd:r,overrideConfigFile:!0,allowInlineConfig:!1,errorOnUnmatchedPattern:!1,globInputPaths:!1,warnIgnored:!1,overrideConfig:[{ignores:M},{files:["**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}"],languageOptions:{parser:h,ecmaVersion:"latest",sourceType:"module"},plugins:{testkit:{rules:x}}},...c.filter(t=>t!=="testkitBoundary").map(t=>{const e=s.rules[t];return{files:e.include.length?e.include:["**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}"],ignores:e.exclude,rules:{[`testkit/${e.ruleId}`]:"error"}}})]}),I=[],v=n.filter(L);if(v.length){const t=v.map(i=>m.join(r,i)),e=await S.lintFiles(t);I.push(...e)}const w=I.flatMap(t=>t.messages.map(e=>{if(e.ruleId===null)return g({file:j(m.relative(r,t.filePath)),line:e.line,ruleName:"syntax",ruleId:"syntax",kind:"parse-error",target:e.message,message:e.message});const i=k.get(E(t.filePath,e.line,e.column,e.message));if(!i)throw new Error(`Missing Testkit finding for ${e.ruleId}: ${e.message}`);return i}));if(c.includes("testkitBoundary")){const t=s.rules.testkitBoundary,e=a&&new Set(a);for(const i of n)t.trackedOnly&&e&&!e.has(i)||!q(i,t)||!i.split("/").some(o=>o.toLowerCase().includes("testkit"))||p(i,t.allowed??[])||w.push(g({file:i,ruleName:"testkitBoundary",ruleId:t.ruleId,kind:"testkit-path",target:i,message:"Tracked Testkit plumbing must live in testkit.config.* or __testkit__/ suites, or move into @gfdelarue/testkit"}))}const f=new Map;for(const t of w.sort(b)){const e=B(t);f.has(e)||f.set(e,t)}return[...f.values()]}function E(r,n,a,s){return[r,n,a,s].join("\0")}function q(r,n){return(!n.include.length||p(r,n.include))&&!p(r,n.exclude)}function A(){return Promise.all([import("eslint"),import("@typescript-eslint/parser")])}
1
+ import m from"node:path";import{posixPath as j}from"../../process/files/paths.js";import{LINT_RULE_NAMES as b}from"./options.js";import{compareFindings as B,findingKey as C,isTypeScriptLikePath as L,matchesAnyPathPattern as p,normalizeFinding as g,SOURCE_IGNORES as M}from"./shared.js";import{createSyntaxPolicy as F}from"./rules/syntax.js";import{createUnitPolicy as R}from"./rules/unit.js";import{createEngineImportPolicy as U}from"./rules/engine-imports.js";export async function lintProject({productDir:n,files:r,trackedFiles:a,options:s}){const T=await q(),[{ESLint:y},h]=T;if(y.version!=="10.7.0"||h.version!=="8.65.0")throw new Error("Testkit lint requires its managed eslint@10.7.0 and @typescript-eslint/parser@8.65.0 installation");const k=new Map,u=b.filter(t=>s.rules[t].enabled),x=Object.fromEntries(u.filter(t=>t!=="testkitBoundary").map(t=>{const e=s.rules[t],i={meta:{type:"problem",schema:[],messages:{violation:"{{message}}"}},defaultOptions:[],create(o){return(()=>{const P=j(m.relative(n,o.filename)),f={context:o,file:P,report:(l,O,S,d)=>{const _=g({file:P,ruleName:t,ruleId:e.ruleId,kind:O,target:S,message:d,line:l.loc.start.line,snippet:o.sourceCode.getText(l).split(/\r?\n/u)[0]});k.set(E(o.filename,l.loc.start.line,l.loc.start.column+1,d),_),o.report({node:l,messageId:"violation",data:{message:d}})},options:s};return t==="engineImports"?U(f):t==="unitTestBoundaries"?R(f):F(t,f,r)})()}};return[e.ruleId,i]})),N=new y({cwd:n,overrideConfigFile:!0,allowInlineConfig:!1,errorOnUnmatchedPattern:!1,globInputPaths:!1,warnIgnored:!1,overrideConfig:[{ignores:M},{files:["**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}"],languageOptions:{parser:h,ecmaVersion:"latest",sourceType:"module"},plugins:{testkit:{rules:x}}},...u.filter(t=>t!=="testkitBoundary").map(t=>{const e=s.rules[t];return{files:e.include.length?e.include:["**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}"],ignores:e.exclude,rules:{[`testkit/${e.ruleId}`]:"error"}}})]}),I=[],v=r.filter(L);if(v.length){const t=v.map(i=>m.join(n,i)),e=await N.lintFiles(t);I.push(...e)}const w=I.flatMap(t=>t.messages.map(e=>{if(e.ruleId===null)return g({file:j(m.relative(n,t.filePath)),line:e.line,ruleName:"syntax",ruleId:"syntax",kind:"parse-error",target:e.message,message:e.message});const i=k.get(E(t.filePath,e.line,e.column,e.message));if(!i)throw new Error(`Missing Testkit finding for ${e.ruleId}: ${e.message}`);return i}));if(u.includes("testkitBoundary")){const t=s.rules.testkitBoundary,e=a&&new Set(a);for(const i of r)t.trackedOnly&&e&&!e.has(i)||!$(i,t)||!i.split("/").some(o=>o.toLowerCase().includes("testkit"))||p(i,t.allowed??[])||w.push(g({file:i,ruleName:"testkitBoundary",ruleId:t.ruleId,kind:"testkit-path",target:i,message:"Tracked Testkit plumbing must live in testkit.config.* or __testkit__/ suites, or move into @gfdelarue/testkit"}))}const c=new Map;for(const t of w.sort(B)){const e=C(t);c.has(e)||c.set(e,t)}return[...c.values()]}function E(n,r,a,s){return[n,r,a,s].join("\0")}function $(n,r){return(!r.include.length||p(n,r.include))&&!p(n,r.exclude)}function q(){return Promise.all([import("eslint"),import("@typescript-eslint/parser")])}
@@ -1 +1 @@
1
- import{DEFAULT_TESTKIT_BOUNDARY_ALLOWED as u}from"./shared.js";import{posixPath as m}from"../../process/files/paths.js";import{isUnknownRecord as s}from"../../kernel/unknown-values.js";export const LINT_RULE_NAMES=["engineImports","uiSpecShape","dataSuiteContract","configImports","testkitBoundary","unitTestBoundaries"];const b=new Set(["rules","ui"]),p=new Set(["enabled","exclude","include"]),y=new Set([...p,"allowed","trackedOnly"]),I=new Set(["maxLines","maxTests"]),d="lint levels were removed; set a rule to true or false, or use { enabled: boolean }";export const RULES={engineImports:{ruleId:"engine-imports",defaultEnabled:!0},uiSpecShape:{ruleId:"ui-spec-shape",defaultEnabled:!0},dataSuiteContract:{ruleId:"data-suite-contract",defaultEnabled:!0},configImports:{ruleId:"config-imports",defaultEnabled:!0},testkitBoundary:{ruleId:"testkit-boundary",defaultEnabled:!1},unitTestBoundaries:{ruleId:"unit-test-boundaries",defaultEnabled:!1}};const O=220,S=8;export function normalizeLintConfig(t={}){const n=s(t)?t.lint??{}:{};return normalizeLintOptions(n)}export function normalizeLintOptions(t={}){if(!s(t))throw new Error("lint config must be an object");if(Object.prototype.hasOwnProperty.call(t,"level"))throw new Error(`lint.level was removed; ${d}`);f(t,b,"lint");const n=t.rules??{};if(!s(n))throw new Error("lint.rules must be an object");for(const i of Object.keys(n)){if(i==="missingImports")throw new Error("lint.rules.missingImports was removed; use testkit typecheck for TypeScript import diagnostics");if(!Object.prototype.hasOwnProperty.call(RULES,i))throw new Error(`Unknown lint rule "${i}"`)}const e=i=>{const l=RULES[i];return T({ruleName:i,ruleId:l.ruleId,value:n[i],defaultEnabled:l.defaultEnabled})},r={engineImports:e("engineImports"),configImports:e("configImports"),dataSuiteContract:e("dataSuiteContract"),testkitBoundary:e("testkitBoundary"),uiSpecShape:e("uiSpecShape"),unitTestBoundaries:e("unitTestBoundaries")},o=t.ui===void 0?{}:t.ui;if(!s(o))throw new Error("lint.ui must be an object");return f(o,I,"lint.ui"),{rules:r,ui:{maxLines:w(o.maxLines,O,"lint.ui.maxLines"),maxTests:w(o.maxTests,S,"lint.ui.maxTests")}}}function T({ruleName:t,ruleId:n,value:e,defaultEnabled:r}){if(e===void 0)return a({ruleName:t,ruleId:n,enabled:r});if(typeof e=="boolean")return a({ruleName:t,ruleId:n,enabled:e});if(!s(e))throw new Error(`lint.rules.${t} must be true, false, or a rule config object; ${d}`);if(Object.prototype.hasOwnProperty.call(e,"level"))throw new Error(`lint.rules.${t}.level was removed; ${d}`);return f(e,t==="testkitBoundary"?y:p,`lint.rules.${t}`),a({ruleName:t,ruleId:n,enabled:E(e.enabled,`lint.rules.${t}.enabled`)??!0,include:c(e.include,`lint.rules.${t}.include`),exclude:c(e.exclude,`lint.rules.${t}.exclude`),allowed:t==="testkitBoundary"?h(e.allowed):void 0,trackedOnly:t==="testkitBoundary"?E(e.trackedOnly,`lint.rules.${t}.trackedOnly`):void 0})}function a({ruleName:t,ruleId:n,enabled:e,include:r=[],exclude:o=[],allowed:i,trackedOnly:l}){return{ruleName:t,ruleId:n,enabled:e,include:r,exclude:o,...t==="testkitBoundary"?{allowed:i||u}:{},...t==="testkitBoundary"?{trackedOnly:l!==!1}:{}}}function c(t,n){if(t==null)return[];if(!Array.isArray(t))throw new Error(`${n} must be an array`);return t.map((e,r)=>{const o=typeof e=="string"?e.trim():"";if(!o)throw new Error(`${n}[${String(r)}] must be a non-empty string`);return m(o)})}function h(t){if(t==null)return u;const n=c(t,"lint.rules.testkitBoundary.allowed");return n.length>0?n:u}function w(t,n,e){if(t===void 0)return n;if(typeof t!="number"||!Number.isInteger(t)||t<=0)throw new Error(`${e} must be a positive integer`);return t}function E(t,n){if(t!==void 0){if(typeof t!="boolean")throw new Error(`${n} must be a boolean`);return t}}function f(t,n,e){for(const r of Object.keys(t))if(!n.has(r))throw new Error(`Unknown ${e} option "${r}"`)}
1
+ import{DEFAULT_TESTKIT_BOUNDARY_ALLOWED as u}from"./shared.js";import{posixPath as E}from"../../process/files/paths.js";import{isUnknownRecord as s}from"../../kernel/unknown-values.js";import{migrationText as y}from"../../domain/retired-test-types.js";export const LINT_RULE_NAMES=["engineImports","uiSpecShape","configImports","testkitBoundary","unitTestBoundaries"];const b=new Set(["rules","ui"]),p=new Set(["enabled","exclude","include"]),I=new Set([...p,"allowed","trackedOnly"]),O=new Set(["maxLines","maxTests"]),d="lint levels were removed; set a rule to true or false, or use { enabled: boolean }";export const RULES={engineImports:{ruleId:"engine-imports",defaultEnabled:!0},uiSpecShape:{ruleId:"ui-spec-shape",defaultEnabled:!0},configImports:{ruleId:"config-imports",defaultEnabled:!0},testkitBoundary:{ruleId:"testkit-boundary",defaultEnabled:!1},unitTestBoundaries:{ruleId:"unit-test-boundaries",defaultEnabled:!1}};const T=220,h=8;export function normalizeLintConfig(t={}){const n=s(t)?t.lint??{}:{};return normalizeLintOptions(n)}export function normalizeLintOptions(t={}){if(!s(t))throw new Error("lint config must be an object");if(Object.prototype.hasOwnProperty.call(t,"level"))throw new Error(`lint.level was removed; ${d}`);f(t,b,"lint");const n=t.rules??{};if(!s(n))throw new Error("lint.rules must be an object");for(const o of Object.keys(n)){if(o==="missingImports")throw new Error("lint.rules.missingImports was removed; use testkit typecheck for TypeScript import diagnostics");if(o==="dataSuiteContract")throw new Error(`lint.rules.dataSuiteContract was removed with the data test type in Testkit 0.6.0. ${y("Remove the data test type")}`);if(!Object.prototype.hasOwnProperty.call(RULES,o))throw new Error(`Unknown lint rule "${o}"`)}const e=o=>{const l=RULES[o];return S({ruleName:o,ruleId:l.ruleId,value:n[o],defaultEnabled:l.defaultEnabled})},r={engineImports:e("engineImports"),configImports:e("configImports"),testkitBoundary:e("testkitBoundary"),uiSpecShape:e("uiSpecShape"),unitTestBoundaries:e("unitTestBoundaries")},i=t.ui===void 0?{}:t.ui;if(!s(i))throw new Error("lint.ui must be an object");return f(i,O,"lint.ui"),{rules:r,ui:{maxLines:w(i.maxLines,T,"lint.ui.maxLines"),maxTests:w(i.maxTests,h,"lint.ui.maxTests")}}}function S({ruleName:t,ruleId:n,value:e,defaultEnabled:r}){if(e===void 0)return a({ruleName:t,ruleId:n,enabled:r});if(typeof e=="boolean")return a({ruleName:t,ruleId:n,enabled:e});if(!s(e))throw new Error(`lint.rules.${t} must be true, false, or a rule config object; ${d}`);if(Object.prototype.hasOwnProperty.call(e,"level"))throw new Error(`lint.rules.${t}.level was removed; ${d}`);return f(e,t==="testkitBoundary"?I:p,`lint.rules.${t}`),a({ruleName:t,ruleId:n,enabled:m(e.enabled,`lint.rules.${t}.enabled`)??!0,include:c(e.include,`lint.rules.${t}.include`),exclude:c(e.exclude,`lint.rules.${t}.exclude`),allowed:t==="testkitBoundary"?k(e.allowed):void 0,trackedOnly:t==="testkitBoundary"?m(e.trackedOnly,`lint.rules.${t}.trackedOnly`):void 0})}function a({ruleName:t,ruleId:n,enabled:e,include:r=[],exclude:i=[],allowed:o,trackedOnly:l}){return{ruleName:t,ruleId:n,enabled:e,include:r,exclude:i,...t==="testkitBoundary"?{allowed:o||u}:{},...t==="testkitBoundary"?{trackedOnly:l!==!1}:{}}}function c(t,n){if(t==null)return[];if(!Array.isArray(t))throw new Error(`${n} must be an array`);return t.map((e,r)=>{const i=typeof e=="string"?e.trim():"";if(!i)throw new Error(`${n}[${String(r)}] must be a non-empty string`);return E(i)})}function k(t){if(t==null)return u;const n=c(t,"lint.rules.testkitBoundary.allowed");return n.length>0?n:u}function w(t,n,e){if(t===void 0)return n;if(typeof t!="number"||!Number.isInteger(t)||t<=0)throw new Error(`${e} must be a positive integer`);return t}function m(t,n){if(t!==void 0){if(typeof t!="boolean")throw new Error(`${n} must be a boolean`);return t}}function f(t,n,e){for(const r of Object.keys(t))if(!n.has(r))throw new Error(`Unknown ${e} option "${r}"`)}
@@ -1 +1 @@
1
- import"../../engines/api/index.js";import{findConfigFile as o}from"../../config/loader/index.js";import{findNearestPlaywrightConfigFile as i}from"../../engines/playwright/runtime/config-file.js";export function engineSupportInputs(e){switch(e.task.engineId){case"node-vitest":return{configuration:e.request.vitest,supportModules:s(e)};case"playwright":return{configuration:l(e),supportModules:u(e)}}}export function defaultEnvironmentValues(e){return{...e.baseUrl===null?{}:{BASE_URL:e.baseUrl},...e.databaseUrl===null?{}:{DATABASE_URL:e.databaseUrl}}}export function engineInputEnvironment(e){const t=Object.entries(e.runtimeEnvironment).filter(([r])=>r.toUpperCase()!=="BASE_URL"),n=new Set(t.map(([r])=>r.toUpperCase()));return{...Object.fromEntries(Object.entries(e.environment.env).filter(([r])=>!n.has(r.toUpperCase()))),...Object.fromEntries(t)}}function s(e){const t=o(e.request.productDir);return t===null?{}:{testkitConfig:t}}function u(e){const t=i(e.request.productDir,e.request.ownerRoots[e.task.serviceName]??[]);return t===null?{}:{playwrightConfig:t}}function l(e){const t=e.environment.baseUrl;return t!==null&&a(t)?{...e.environment.ui,allowRemote:!0}:{...e.environment.ui}}function a(e){try{return!p(new URL(e).hostname)}catch{return!1}}function p(e){const t=e.toLowerCase();return t==="localhost"||t==="::1"||t==="0.0.0.0"||t==="127.0.0.1"||t.endsWith(".localhost")||t.startsWith("127.")}
1
+ import"../../engines/api/index.js";import{findNearestPlaywrightConfigFile as o}from"../../engines/playwright/runtime/config-file.js";export function engineSupportInputs(e){switch(e.task.engineId){case"node-vitest":return{configuration:e.request.vitest,supportModules:{}};case"playwright":return{configuration:i(e),supportModules:s(e)}}}export function defaultEnvironmentValues(e){return{...e.baseUrl===null?{}:{BASE_URL:e.baseUrl},...e.databaseUrl===null?{}:{DATABASE_URL:e.databaseUrl}}}export function engineInputEnvironment(e){const t=Object.entries(e.runtimeEnvironment).filter(([r])=>r.toUpperCase()!=="BASE_URL"),n=new Set(t.map(([r])=>r.toUpperCase()));return{...Object.fromEntries(Object.entries(e.environment.env).filter(([r])=>!n.has(r.toUpperCase()))),...Object.fromEntries(t)}}function s(e){const t=o(e.request.productDir,e.request.ownerRoots[e.task.serviceName]??[]);return t===null?{}:{playwrightConfig:t}}function i(e){const t=e.environment.baseUrl;return t!==null&&u(t)?{...e.environment.ui,allowRemote:!0}:{...e.environment.ui}}function u(e){try{return!a(new URL(e).hostname)}catch{return!1}}function a(e){const t=e.toLowerCase();return t==="localhost"||t==="::1"||t==="0.0.0.0"||t==="127.0.0.1"||t.endsWith(".localhost")||t.startsWith("127.")}
@@ -1 +1 @@
1
- import{isDeepStrictEqual as c}from"node:util";import{isUnknownRecord as f}from"../../kernel/unknown-values.js";export function createEnvironment({group:n,setupData:t={},...e}){return{...e,databases:p(e.databases,n,e.databaseUrl,"database"),endpoints:p(e.endpoints,n,e.baseUrl,"endpoint"),env:{...e.env},setupData:t}}export class GroupDefaultConflictError extends Error{}function p(n,t,e,r){if(e===null)return{...n};if(Object.hasOwn(n,t)&&n[t]!==e)throw new GroupDefaultConflictError(`Group "${t}" has a default ${r} and a different ${r} named "${t}"; a group's default ${r} is also named after the group`);return{...n,[t]:e}}export class TaskPreparationError extends Error{cleanupFailures;kind;cause;constructor(t,e,r){super(e.message,{cause:e}),this.name="TaskPreparationError",this.cause=e,this.cleanupFailures=r,this.kind=t}}export function environmentTaskIdentities(n){return("batchTasks"in n?n.batchTasks:[n]).map(environmentTaskIdentity)}const b={baseUrl:"base URL",databaseUrl:"database URL",databases:"database",endpoints:"endpoint",env:"environment value",handles:"handle",setupData:"setup data",ui:"UI values"};export function renderSharedEnvironment(n,t){const[e,...r]=[...new Set(environmentTaskIdentities(n).map(({group:a})=>a))],s=t(e);for(const a of r){const i=t(a),o=Object.keys(b).find(u=>!c(s[u],i[u]));if(o===void 0)continue;const d=h(s[o],i[o]);throw new Error(`Plain Vitest files run in one Vitest invocation, but groups ${e} and ${a} give them a different ${b[o]}${d===void 0?"":` ${d}`}; select one group with --group`)}return s}function h(n,t){if(!(!f(n)||!f(t)))return Object.keys({...n,...t}).find(e=>!c(n[e],t[e]))}export function environmentTaskIdentity({file:n,id:t,targetName:e}){return{id:t,file:n,group:e}}
1
+ import{randomUUID as c}from"node:crypto";import u from"node:path";import{isDeepStrictEqual as f}from"node:util";import{isUnknownRecord as m}from"../../kernel/unknown-values.js";export function createEnvironment({group:n,setupData:t={},...e}){return{...e,databases:b(e.databases,n,e.databaseUrl,"database"),endpoints:b(e.endpoints,n,e.baseUrl,"endpoint"),env:{...e.env},setupData:t}}export class GroupDefaultConflictError extends Error{}function b(n,t,e,r){if(e===null)return{...n};if(Object.hasOwn(n,t)&&n[t]!==e)throw new GroupDefaultConflictError(`Group "${t}" has a default ${r} and a different ${r} named "${t}"; a group's default ${r} is also named after the group`);return{...n,[t]:e}}export class TaskPreparationError extends Error{cleanupFailures;kind;cause;constructor(t,e,r){super(e.message,{cause:e}),this.name="TaskPreparationError",this.cause=e,this.cleanupFailures=r,this.kind=t}}export const PREVIEW_LEASE=Object.freeze({directory:u.join(u.sep,`testkit-preview-${c()}`),id:`testkit-preview-${c()}`});export function environmentTaskIdentities(n){return("batchTasks"in n?n.batchTasks:[n]).map(environmentTaskIdentity)}const h={baseUrl:"base URL",databaseUrl:"database URL",databases:"database",endpoints:"endpoint",env:"environment value",handles:"handle",setupData:"setup data",ui:"UI values"};export function renderSharedEnvironment(n,t){const[e,...r]=[...new Set(environmentTaskIdentities(n).map(({group:o})=>o))],i=t(e);for(const o of r){const s=t(o),a=Object.keys(h).find(p=>!f(i[p],s[p]));if(a===void 0)continue;const d=l(i[a],s[a]);throw new Error(`Plain Vitest files run in one Vitest invocation, but groups ${e} and ${o} give them a different ${h[a]}${d===void 0?"":` ${d}`}; select one group with --group`)}return i}function l(n,t){if(!(!m(n)||!m(t)))return Object.keys({...n,...t}).find(e=>!f(n[e],t[e]))}export function environmentTaskIdentity({file:n,id:t,targetName:e}){return{id:t,file:n,group:e}}
@@ -1 +1 @@
1
- import{resolveRuntimeClosure as he}from"../../config/loader/dependencies.js";import{claimNextTask as ve,collectSuites as ye}from"./planning.js";import{buildRunPlanningMetadata as ke,buildScheduledQueue as Re}from"./scheduler/index.js";import{requireCompatibleSelection as Se}from"./task-batches.js";import{addTrackerError as we,buildServiceTrackers as Ce,finalizeServiceResult as ie,recordGraphError as Fe,recordTaskOutcome as Ee}from"./results.js";import{loadTimings as Ae,saveTimings as Te,writeRunArtifact as be}from"../../evidence/index.js";import{createRunEnvironmentRecord as Ke}from"../../evidence/environment-record.js";import{createRunLogRegistry as xe}from"../../evidence/logs.js";import{createOperationTimingRegistry as Me,timeOperation as B}from"../../evidence/operation-timings.js";import{createRunReporterFromListener as qe}from"./run-events.js";import{createCallerRedaction as Ie}from"./caller-redaction.js";import{createSetupOperationRegistry as ze}from"../../evidence/setup-progress.js";import{createLocalRunEnvironment as Oe}from"../../environment/run-environment.js";import{createConfigDrivenEnvironments as Pe,planConfiguredCapacity as Ne}from"../environments/config-driven.js";import{declaresProvisioning as je,declaresValues as ae,holdBeforeRelease as De,routeEnvironments as Le}from"../environments/routing.js";import{createStaticValueEnvironments as Ge}from"../environments/static-values.js";import{findRuntimeNodeSetupFile as Ve}from"./setup/runtime-node-setup.js";import{createSuppliedEnvironments as Be}from"../environments/supplied.js";import{environmentTaskIdentity as $e}from"./environment.js";import{createTaskLeases as We}from"./task-leases.js";import{createTaskLocks as Ue}from"./scheduler/locks.js";import{readPackageMetadata as He,safeHostname as Qe,safeUsername as _e}from"../../process/host/metadata.js";import{collectGitMetadata as Je}from"../../repo/metadata.js";import{resolveExecutionConfig as Xe}from"../../config/loader/decode-execution.js";import{resolveTaskPolicy as Ye}from"../../config/loader/task-policy.js";import"../../environment/run-environment.js";import{createEngineManager as Ze}from"../../engines/factory.js";import{createWorker as et,runWorker as tt}from"./worker-loop.js";import{ensureRequestedFilesMatch as rt}from"./run-guards.js";import{createLiveSnapshotWriter as nt}from"./live-run.js";import{finalizeRunArtifacts as it}from"./run-finalization.js";import{buildRunArtifact as at}from"../../evidence/reporting.js";import{createOperationReporterBridge as ot}from"./operation-progress.js";import{formatError as $,serializeError as oe}from"../../kernel/error-serialization.js";export async function runAll(e,n,a,r,c=[]){const h=r.fileNames||[];rt(e,n,a,h);const{productDir:s}=r,p=Oe(s),R=Ze(s),v=new Map(c.map(i=>[i.name,i])),t=Date.now(),C=e[0]?.artifacts??null,q=[...new Set(e.flatMap(i=>i.uses.flatMap(m=>Object.keys(v.get(m)?.testkit.serviceEnv??{}))))].sort(),f={git:await Je(s),host:{hostname:Qe(),username:_e()},testkitVersion:He().version},S=e[0]?.redact??[],b=Ie(process.env,S),Y=r.onEvent,y=Y?qe(i=>{Y(b.redact(i))},{debug:r.debug}):null,K=xe(s),j={workerCount:0},I=resolveRunExecutionConfig(e[0],r),D=collectServicePlans(e,v,n,a,r,I,y);y?.setServicePlans?.(D);const z=Ce(D,t),L=i=>{for(const m of z.values())m.skipped||we(m,i);y?.runError?.(i)},ce=a.map(i=>({...i})),W={typeValues:n,suiteSelectors:ce,fileNames:h,groupFilter:r.serviceFilter||null,planning:null};let k=()=>{};const ue=ot(y),T=Me({onChange:i=>{ue(i),k()}}),Z=ze({logRegistry:K,onChange:()=>{k()}}),d=Ke({logRegistry:K,redactKeys:S,setupRegistry:Z,onPublishedChange:()=>{k()}});b.useSourceTargets(()=>d.redactionTargets()),d.recordGroups(D.map(i=>({dbBackend:i.dbBackend,name:i.config.name})));const U=D.filter(i=>!i.skipped),H=r.environments?.supplied??{},{plans:O,provisionedGraphKeys:G,staticGraphKeys:Q}=assignRuntimeGraphs(U,new Set(Object.keys(H)));let g;const o=await p.start({keepAlive:!0,localInfrastructure:G.size>0,redactKeys:S,redactionTargets:()=>d.redactionTargets(),resetResultsBeforePublish:!0});k=nt({productDir:s,runId:o.runId,configs:e,trackers:z,startedAt:t,execution:I,workerState:j,selection:W,archiveConfig:C,declaredEnvironmentKeys:q,metadata:f,environmentRecord:d,operationTimingRegistry:T,reporter:y});const P={artifacts:null},le=async(i,m)=>(o.beginFinalization(),await o.finish(i,A=>{const w=m(A);return P.artifacts={runArtifact:w.runArtifact},w},"normal"));let F,x;const ee=(i,m,u)=>({productDir:s,runId:o.runId,results:i,startedAt:t,finishedAt:m,execution:I,workerCount:j.workerCount,selection:W,archiveConfig:C,declaredEnvironmentKeys:q,metadata:f,environmentRecord:d,operationTimingRegistry:T,reporter:y,runInterruptReason:o.getInterruptReason(),runStatus:u,publishRunFinalization:le});k();let E=null;try{try{if(U.length>0){const u=Ae(s),{capacity:A,queue:w}=await B(T,{name:"testkit.plan",kind:"planning",summary:"plan test execution",scope:{serviceCount:U.length}},()=>({capacity:Ne(O.filter(l=>G.has(l.runtimeKey))),queue:Re(O.map(l=>prepareSchedulerPlan(l,Object.hasOwn(H,l.config.name)?()=>!1:M=>Ve(s,M)!==null)),{timings:u})}));Se(w,{provisioned:G,static:Q}),W.planning=ke(w),d.recordCapacity(A),y?.setTotalFileCount?.(w.length),j.workerCount=Math.max(1,Math.min(I.taskConcurrency,w.length));const te=Array.from({length:j.workerCount},(l,M)=>et(M+1,s));A.graphs.length>0&&o.provision(A.graphs,{reporter:y,environmentRecord:d,logRegistry:K,setupRegistry:Z,operationTimingRegistry:T,skipSchemaSourceVerify:r.skipSchemaSourceVerify});const me=Pe(o,new Map(O.map(l=>[l.config.name,l.config.uses])),s,d),fe=Ge(new Map(O.filter(l=>Q.has(l.runtimeKey)).map(l=>[l.config.name,l.uses])),s,d),de=Be(H,{productDir:s,record:d,signal:o.signal}),re=We(s),pe={recordRunError:L,runId:o.runId,signal:o.signal,isStopRequested:()=>o.isStopRequested(),environments:mt(Le(new Map(O.map(({runtimeKey:l})=>[l,G.has(l)?me:Q.has(l)?fe:de]))),r.environments?.hold),leases:ut(re,d),locks:Ue(),request:ft(s,e,I,r.vitest)},ne=[];try{const M=(await B(T,{name:"testkit.execute",kind:"execution",summary:"execute local worker queue",scope:{workerCount:te.length,taskCount:w.length}},async()=>Promise.allSettled(te.map(_=>tt(_,w,pe,R,z,ne,ve,(J,V,N,X)=>{Ee(J,V,N,X),N.environmentValuesMissing!==void 0&&d.recordMissingValues($e(V),N.environmentValuesMissing),k()},(J,V,N,X,ge)=>{Fe(J,V,N,X,ge),k()},y))))).flatMap(workerResultErrorsForOrchestrator);for(const _ of M)L(_);M.length>0&&k(),d.recordRuntimeStats(o.getStats())}finally{A.graphs.length>0&&await B(T,{name:"testkit.cleanup",kind:"cleanup",summary:"stop managed runtimes and services"},()=>lt(d,()=>o.cleanupAll())),re.close()}Te(s,u,ne)}}catch(u){E=oe(u),L(E.message||$(u)),k()}g=E===null?0:o.isStopRequested()?130:1,x=Date.now(),F=e.map(u=>ie(z.get(u.name),t,x));const i=resolveRunGateFailure(F,r.allowEmpty===!0);await B(T,{name:"testkit.collect",kind:"collection",summary:"close and collect run logs"},()=>K.closeAll());const m=await it(ee(F,x,o.isStopRequested()?"interrupted":E===null&&i===null?null:"failed"));return E!==null&&(g=1),F.some(u=>u.failed||u.infraFailed)&&(g=1),i!==null&&(g=1),m.shouldFailArchivePublication&&(g=1),m.shouldFailArchiveCleanup&&(g=1),(m.runArtifact.run.status==="interrupted"||o.isStopRequested()||o.committedFinalization?.artifactStatus==="interrupted")&&(g=Math.max(g,130)),{runArtifact:m.runArtifact,results:b.redact(F),exitCode:g,...E===null?{}:{failure:b.redact(E)}}}catch(i){const m=oe(i);L(m.message||$(i)),k(),o.beginFinalization(),g=o.isStopRequested()||o.committedFinalization?.artifactStatus==="interrupted"?130:1,x=Date.now(),F=e.map(A=>ie(z.get(A.name),t,x)),await se(K);let u=P.artifacts;if(u===null)try{u=await st(ee(F,x,o.isStopRequested()?"interrupted":"failed"),o,P,m)}catch{if(P.artifacts===null)throw i;u=P.artifacts}return(u.runArtifact.run.status==="interrupted"||o.isStopRequested()||o.committedFinalization?.artifactStatus==="interrupted")&&(g=Math.max(g,130)),{runArtifact:u.runArtifact,results:b.redact(F),exitCode:g,failure:b.redact(E??m)}}finally{o.dispose(),await se(K),ct(d,r.environments?.observeRecord,y)}}async function st(e,n,a,r){return n.finish("failed",c=>{const h=c.artifactStatus==="interrupted"?c:{artifactStatus:"failed",interruptReason:null},s=e.declaredEnvironmentKeys??[],p=at({productDir:e.productDir,runId:e.runId,results:e.results,startedAt:e.startedAt,finishedAt:e.finishedAt,execution:e.execution,workerCount:e.workerCount,typeValues:e.selection.typeValues,suiteSelectors:e.selection.suiteSelectors,fileNames:e.selection.fileNames,groupFilter:e.selection.groupFilter,planning:e.selection.planning??null,archiveConfig:e.archiveConfig,declaredEnvironmentKeys:s,metadata:e.metadata,environment:e.environmentRecord.snapshot(),operationTimings:e.operationTimingRegistry?.listOperations()??[],runInterruptReason:h.interruptReason,runStatus:h.artifactStatus});p.finalizationFailure={...r};const v={runArtifact:be(e.productDir,p,{archiveConfig:e.archiveConfig,declaredEnvironmentKeys:s,redactKeys:e.environmentRecord.redactKeys,redactionTargets:e.environmentRecord.redactionTargets()})};return a.artifacts=v,v},"recovery")}function ct(e,n,a){if(n!==void 0)try{n(e.snapshot())}catch(r){try{a?.warning?.(`Environment record observer failed: ${$(r)}`)}catch{}}}function ut(e,n){return{...e,remove(a){const r=n.releaseFor(a.id);try{e.remove(a)}catch(c){throw r?.releaseFailed(c),c}r?.released()}}}async function lt(e,n){try{await n()}catch(a){throw e.recordCleanup(a),a}e.recordCleanup(null)}async function se(e){try{await e.closeAll()}catch{}}export function workerResultErrorsForOrchestrator(e){return e.status==="rejected"?[$(e.reason)]:[...new Set(e.value.unpersistedErrors)]}export function resolveRunGateFailure(e,n=!1){return e.some(r=>r.failed)?"test failure":e.some(r=>r.infraFailed)?"test infrastructure failure":e.some(r=>r.notRunFileCount>0)?"one or more required test files did not run":e.some(r=>r.skippedFileCount>0)?"one or more selected test files were skipped":e.reduce((r,c)=>r+c.completedFileCount,0)===0&&!n?"no runnable test files executed":null}function mt(e,n){return n===void 0?e:De(e,n)}function ft(e,n,a,r){return{vitest:r,productDir:e,fileTimeoutSeconds:a.fileTimeoutSeconds,ownerRoots:Object.fromEntries(n.map(c=>[c.name,c.roots]))}}export function resolveRunExecutionConfig(e,n){return Xe({cli:{fileTimeoutSeconds:n.fileTimeoutSeconds,taskConcurrency:n.taskConcurrency},repo:e?{fileTimeoutSeconds:e.testkit.execution.fileTimeoutSeconds,taskConcurrency:e.testkit.execution.taskConcurrency}:void 0})}export function assignRuntimeGraphs(e,n){const a=e.filter(t=>t.suites.some(C=>C.files.length>0)),r=new Set(a.filter(t=>!n.has(t.config.name)&&je(t.runtimeConfigs))),c=new Set([...r].map(t=>t.runtimeKey)),h=t=>!r.has(t)&&!n.has(t.config.name)&&ae(t.runtimeConfigs),s=new Set(a.filter(t=>h(t)&&t.runtimeKey!=="").map(t=>t.runtimeKey)),p=new Set(a.map(t=>t.runtimeKey)),R=t=>t.runtimeKey!==""&&!c.has(t.runtimeKey)&&(h(t)||!s.has(t.runtimeKey))?t.runtimeKey:p.has(t.config.name)?`group:${t.config.name}`:t.config.name,v=a.map(t=>r.has(t)?t:{...t,runtimeKey:R(t)});return{plans:v,provisionedGraphKeys:c,staticGraphKeys:new Set(v.filter(t=>!c.has(t.runtimeKey)&&!n.has(t.config.name)&&ae(t.runtimeConfigs)).map(t=>t.runtimeKey))}}export function prepareSchedulerPlan(e,n){return{graphKey:e.runtimeKey,owner:e.config.name,suites:e.suites.map(a=>({...a,tasks:a.files.map(r=>({file:r,hasSetup:n(r),...Ye(e.config.testkit,a,r)}))}))}}export function collectServicePlans(e,n,a,r,c,h,s=null){return e.map(p=>{const R=p.uses.map(f=>{const S=n.get(f);if(S===void 0)throw new Error(`Group "${p.name}" uses unknown service "${f}"`);return S}),v=R.some(f=>f.testkit.database!==void 0)?"local":null,t=ye(p,a,r,c.fileNames||[],c);if(t.length===0)return s?.serviceSkipped?.(p,`no matching files (types=${a.join(",")||"all"} suites=${r.map(f=>f.raw).join(",")||"all"} files=${(c.fileNames||[]).join(",")||"all"})`),{config:p,dbBackend:v,execution:h,skipped:!0,suites:[],runtimeConfigs:[],runtimeNames:[],runtimeKey:null,uses:R};for(const f of t)for(const S of f.skippedFiles)s?.plannedSkip?.({serviceName:p.name,testType:f.testType,engineId:f.engineId,profileId:f.profileId,file:S.path,reason:S.reason});const C=he(R,n),q=C.map(f=>f.name).sort();return{config:p,dbBackend:v,execution:h,skipped:!1,suites:t,runtimeConfigs:C,runtimeNames:q,runtimeKey:q.join("|"),uses:R}})}
1
+ import{resolveRuntimeClosure as we}from"../../config/loader/dependencies.js";import{claimNextTask as Se,collectSuites as Ce}from"./planning.js";import{buildRunPlanningMetadata as Fe,buildScheduledQueue as Ee}from"./scheduler/index.js";import{addTrackerError as be,buildServiceTrackers as Ae,finalizeServiceResult as le,recordGraphError as Te,recordTaskOutcome as Ke}from"./results.js";import{loadTimings as xe,saveTimings as Me,writeRunArtifact as Ie}from"../../evidence/index.js";import{stableJson as qe}from"../../evidence/storage.js";import{createRunEnvironmentRecord as Oe}from"../../evidence/environment-record.js";import{createRunLogRegistry as Pe}from"../../evidence/logs.js";import{createOperationTimingRegistry as ze,timeOperation as U}from"../../evidence/operation-timings.js";import{createRunReporterFromListener as Ne}from"./run-events.js";import{createCallerRedaction as $e}from"./caller-redaction.js";import{createSetupOperationRegistry as je}from"../../evidence/setup-progress.js";import{createLocalRunEnvironment as De}from"../../environment/run-environment.js";import{writeRunMaintenance as Le}from"../../evidence/maintenance.js";import{createConfigDrivenEnvironments as Ge,planConfiguredCapacity as Ve}from"../environments/config-driven.js";import{declaresProvisioning as Be,declaresValues as me,holdBeforeRelease as We,routeEnvironments as Ue}from"../environments/routing.js";import{createStaticValueEnvironments as He}from"../environments/static-values.js";import{findRuntimeNodeSetupFile as Je}from"./setup/runtime-node-setup.js";import{createSuppliedEnvironments as Qe}from"../environments/supplied.js";import{environmentTaskIdentity as _e}from"./environment.js";import{createTaskLeases as Xe}from"./task-leases.js";import{createTaskLocks as Ye}from"./scheduler/locks.js";import{readPackageMetadata as Ze,safeHostname as et,safeUsername as tt}from"../../process/host/metadata.js";import{collectGitMetadata as rt}from"../../repo/metadata.js";import{resolveExecutionConfig as nt}from"../../config/loader/decode-execution.js";import{resolveTaskPolicy as it}from"../../config/loader/task-policy.js";import"../../environment/run-environment.js";import{createEngineManager as at}from"../../engines/factory.js";import{createWorker as ot,runWorker as st}from"./worker-loop.js";import{ensureRequestedFilesMatch as ct}from"./run-guards.js";import{createLiveSnapshotWriter as ut}from"./live-run.js";import{finalizeRunArtifacts as lt}from"./run-finalization.js";import{buildRunArtifact as mt}from"../../evidence/reporting.js";import{createOperationReporterBridge as ft}from"./operation-progress.js";import{formatError as P,serializeError as Y}from"../../kernel/error-serialization.js";export async function runAll(e,i,o,r,m=[]){const R=r.fileNames||[];ct(e,i,o,R);const{productDir:u}=r,p=De(u),y=at(u),v=new Map(m.map(n=>[n.name,n])),t=Date.now(),C=e[0]?.artifacts??null,b=[...new Set(e.flatMap(n=>n.uses.flatMap(l=>Object.keys(v.get(l)?.testkit.serviceEnv??{}))))].sort(),f={git:await rt(u),host:{hostname:et(),username:tt()},testkitVersion:Ze().version},F=e[0]?.redact??[],w=$e(process.env,F),Z=r.onEvent,k=Z?Ne(n=>{Z(w.redact(n))},{debug:r.debug}):null,M=Pe(u),B={workerCount:0},z=resolveRunExecutionConfig(e[0],r),W=collectServicePlans(e,v,i,o,r,z,k);k?.setServicePlans?.(W);const N=Ae(W,t),$=(n,l="product")=>{for(const c of N.values())c.skipped||be(c,n,{classification:l});k?.runError?.(n)},de=o.map(n=>({...n})),H={typeValues:i,suiteSelectors:de,fileNames:R,groupFilter:r.serviceFilter||null,planning:null};let S=()=>{};const pe=ft(k),K=ze({onChange:n=>{pe(n),S()}}),ee=je({logRegistry:M,onChange:()=>{S()}}),d=Oe({logRegistry:M,redactKeys:F,setupRegistry:ee,onPublishedChange:()=>{S()}});w.useSourceTargets(()=>d.redactionTargets()),d.recordGroups(W.map(n=>({dbBackend:n.dbBackend,name:n.config.name})));const J=W.filter(n=>!n.skipped),Q=r.environments?.supplied??{},{plans:I,provisionedGraphKeys:_,staticGraphKeys:te}=assignRuntimeGraphs(J,new Set(Object.keys(Q)));let g;const s=await p.start({keepAlive:!0,localInfrastructure:_.size>0,redactKeys:F,redactionTargets:()=>d.redactionTargets(),resetResultsBeforePublish:!0});S=ut({productDir:u,runId:s.runId,configs:e,trackers:N,startedAt:t,execution:z,workerState:B,selection:H,archiveConfig:C,declaredEnvironmentKeys:b,metadata:f,environmentRecord:d,operationTimingRegistry:K,reporter:k});const j={artifacts:null},D={result:null},re=n=>{const l=w.redact(n);try{return Le(u,s.runId,l),l}catch(c){const h=`Could not write the maintenance record: ${w.redact(P(c))}`;return{...l,status:"failed",error:l.error===null?h:`${l.error}; ${h}`}}},ne=n=>(D.result=n.maintenance,n.maintenance.status==="failed"&&k?.warning?.(`Post-run maintenance failed: ${n.maintenance.error??"unknown error"}`),n.sealed),ge=async(n,l)=>(s.beginFinalization(),ne(await s.finish(n,c=>{const h=l(c);return j.artifacts={runArtifact:h.runArtifact},h},"normal",re)));let A,q;const ie=(n,l,c)=>({productDir:u,runId:s.runId,results:n,startedAt:t,finishedAt:l,execution:z,workerCount:B.workerCount,selection:H,archiveConfig:C,declaredEnvironmentKeys:b,metadata:f,environmentRecord:d,operationTimingRegistry:K,reporter:k,runInterruptReason:s.getInterruptReason(),runStatus:c,publishRunFinalization:ge});S();let T=null,ae=Symbol("no release failure");try{try{if(J.length>0){const c=xe(u),{capacity:h,queue:L}=await U(K,{name:"testkit.plan",kind:"planning",summary:"plan test execution",scope:{serviceCount:J.length}},()=>({capacity:Ve(I.filter(a=>_.has(a.runtimeKey))),queue:Ee(I.map(a=>prepareSchedulerPlan(a,Object.hasOwn(Q,a.config.name)?()=>!1:E=>Je(u,E)!==null)),{timings:c})}));H.planning=Fe(L),d.recordCapacity(h),k?.setTotalFileCount?.(L.length),B.workerCount=Math.max(1,Math.min(z.taskConcurrency,L.length));const oe=Array.from({length:B.workerCount},(a,E)=>ot(E+1,u));h.graphs.length>0&&s.provision(h.graphs,{reporter:k,environmentRecord:d,logRegistry:M,setupRegistry:ee,operationTimingRegistry:K,skipSchemaSourceVerify:r.skipSchemaSourceVerify});const he=Ge(s,new Map(I.map(a=>[a.config.name,a.config.uses])),u,d),ye=He(new Map(I.filter(a=>te.has(a.runtimeKey)).map(a=>[a.config.name,a.uses])),u,d),ve=Qe(Q,{productDir:u,record:d,signal:s.signal}),se=Xe(u),ce=a=>_.has(a)?{kind:"configured",entry:he}:te.has(a)?{kind:"static",entry:ye}:{kind:"supplied",entry:ve},ke={recordRunError:$,runId:s.runId,signal:s.signal,isStopRequested:()=>s.isStopRequested(),environments:yt(Ue(new Map(I.map(({runtimeKey:a})=>[a,ce(a).entry]))),r.environments?.hold),leases:gt(se,d),locks:Ye(),request:vt(u,e,z,r.vitest),environmentKeys:new Map(I.map(({config:a,runtimeKey:E})=>{const{entry:G,kind:O}=ce(E),x=G.preview?.(a.name)??null;return[a.name,qe(x===null?[O,E,a.name]:[O,x])]}))},ue=[];try{const E=(await U(K,{name:"testkit.execute",kind:"execution",summary:"execute local worker queue",scope:{workerCount:oe.length,taskCount:L.length}},async()=>Promise.allSettled(oe.map(G=>st(G,L,ke,y,N,ue,Se,(O,x,V,X)=>{Ke(O,x,V,X),V.environmentValuesMissing!==void 0&&d.recordMissingValues(_e(x),V.environmentValuesMissing),S()},(O,x,V,X,Re)=>{Te(O,x,V,X,Re),S()},k))))).flatMap(workerResultErrorsForOrchestrator);for(const G of E)$(G);E.length>0&&S(),d.recordRuntimeStats(s.getStats())}finally{h.graphs.length>0&&await U(K,{name:"testkit.cleanup",kind:"cleanup",summary:"stop managed runtimes and services"},()=>ht(d,()=>s.cleanupAll()).catch(a=>{throw ae=a,$(Y(a).message||P(a),"infra"),a})),se.close()}Me(u,c,ue)}}catch(c){T=Y(c),c!==ae&&$(T.message||P(c)),S()}g=T===null?0:s.isStopRequested()?130:1,q=Date.now(),A=e.map(c=>le(N.get(c.name),t,q));const n=resolveRunGateFailure(A,r.allowEmpty===!0);await U(K,{name:"testkit.collect",kind:"collection",summary:"close and collect run logs"},()=>M.closeAll());const l=await lt(ie(A,q,s.isStopRequested()?"interrupted":T===null&&n===null?null:"failed"));return T!==null&&(g=1),A.some(c=>c.failed||c.infraFailed)&&(g=1),n!==null&&(g=1),l.shouldFailArchivePublication&&(g=1),l.shouldFailArchiveCleanup&&(g=1),(l.runArtifact.run.status==="interrupted"||s.isStopRequested()||s.committedFinalization?.artifactStatus==="interrupted")&&(g=Math.max(g,130)),{runArtifact:l.runArtifact,results:w.redact(A),exitCode:g,...T===null?{}:{failure:w.redact(T)},...D.result===null?{}:{maintenance:w.redact(D.result)}}}catch(n){const l=Y(n);$(l.message||P(n),"infra"),S(),s.beginFinalization(),g=s.isStopRequested()||s.committedFinalization?.artifactStatus==="interrupted"?130:1,q=Date.now(),A=e.map(h=>le(N.get(h.name),t,q)),await fe(M);let c=j.artifacts;if(c===null)try{c=await dt(ie(A,q,s.isStopRequested()?"interrupted":"failed"),s,j,l,re,ne)}catch{if(j.artifacts===null)throw n;c=j.artifacts}return(c.runArtifact.run.status==="interrupted"||s.isStopRequested()||s.committedFinalization?.artifactStatus==="interrupted")&&(g=Math.max(g,130)),{runArtifact:c.runArtifact,results:w.redact(A),exitCode:g,failure:w.redact(T??l),...D.result===null?{}:{maintenance:w.redact(D.result)}}}finally{s.dispose(),await fe(M),pt(d,r.environments?.observeRecord,k)}}async function dt(e,i,o,r,m,R){const u=await i.finish("failed",p=>{const y=p.artifactStatus==="interrupted"?p:{artifactStatus:"failed",interruptReason:null},v=e.declaredEnvironmentKeys??[],t=mt({productDir:e.productDir,runId:e.runId,results:e.results,startedAt:e.startedAt,finishedAt:e.finishedAt,execution:e.execution,workerCount:e.workerCount,typeValues:e.selection.typeValues,suiteSelectors:e.selection.suiteSelectors,fileNames:e.selection.fileNames,groupFilter:e.selection.groupFilter,planning:e.selection.planning??null,archiveConfig:e.archiveConfig,declaredEnvironmentKeys:v,metadata:e.metadata,environment:e.environmentRecord.snapshot(),operationTimings:e.operationTimingRegistry?.listOperations()??[],runInterruptReason:y.interruptReason,runStatus:y.artifactStatus});t.finalizationFailure={...r};const b={runArtifact:Ie(e.productDir,t,{archiveConfig:e.archiveConfig,declaredEnvironmentKeys:v,redactKeys:e.environmentRecord.redactKeys,redactionTargets:e.environmentRecord.redactionTargets()})};return o.artifacts=b,b},"recovery",m);return R(u)}function pt(e,i,o){if(i!==void 0)try{i(e.snapshot())}catch(r){try{o?.warning?.(`Environment record observer failed: ${P(r)}`)}catch{}}}function gt(e,i){return{...e,remove(o){const r=i.releaseFor(o.id);try{e.remove(o)}catch(m){throw r?.releaseFailed(m),m}r?.released()}}}async function ht(e,i){try{await i()}catch(o){throw e.recordCleanup(o),o}e.recordCleanup(null)}async function fe(e){try{await e.closeAll()}catch{}}export function workerResultErrorsForOrchestrator(e){return e.status==="rejected"?[P(e.reason)]:[...new Set(e.value.unpersistedErrors)]}export function resolveRunGateFailure(e,i=!1){return e.some(r=>r.failed)?"test failure":e.some(r=>r.infraFailed)?"test infrastructure failure":e.some(r=>r.notRunFileCount>0)?"one or more required test files did not run":e.some(r=>r.skippedFileCount>0)?"one or more selected test files were skipped":e.reduce((r,m)=>r+m.completedFileCount,0)===0&&!i?"no runnable test files executed":null}function yt(e,i){return i===void 0?e:We(e,i)}function vt(e,i,o,r){return{vitest:r,productDir:e,fileTimeoutSeconds:o.fileTimeoutSeconds,ownerRoots:Object.fromEntries(i.map(m=>[m.name,m.roots]))}}export function resolveRunExecutionConfig(e,i){return nt({cli:{fileTimeoutSeconds:i.fileTimeoutSeconds,taskConcurrency:i.taskConcurrency},repo:e?{fileTimeoutSeconds:e.testkit.execution.fileTimeoutSeconds,taskConcurrency:e.testkit.execution.taskConcurrency}:void 0})}export function assignRuntimeGraphs(e,i){const o=e.filter(t=>t.suites.some(C=>C.files.length>0)),r=new Set(o.filter(t=>!i.has(t.config.name)&&Be(t.runtimeConfigs))),m=new Set([...r].map(t=>t.runtimeKey)),R=t=>!r.has(t)&&!i.has(t.config.name)&&me(t.runtimeConfigs),u=new Set(o.filter(t=>R(t)&&t.runtimeKey!=="").map(t=>t.runtimeKey)),p=new Set(o.map(t=>t.runtimeKey)),y=t=>t.runtimeKey!==""&&!m.has(t.runtimeKey)&&(R(t)||!u.has(t.runtimeKey))?t.runtimeKey:p.has(t.config.name)?`group:${t.config.name}`:t.config.name,v=o.map(t=>r.has(t)?t:{...t,runtimeKey:y(t)});return{plans:v,provisionedGraphKeys:m,staticGraphKeys:new Set(v.filter(t=>!m.has(t.runtimeKey)&&!i.has(t.config.name)&&me(t.runtimeConfigs)).map(t=>t.runtimeKey))}}export function prepareSchedulerPlan(e,i){return{graphKey:e.runtimeKey,owner:e.config.name,suites:e.suites.map(o=>({...o,tasks:o.files.map(r=>({file:r,hasSetup:i(r),...it(e.config.testkit,o,r)}))}))}}export function collectServicePlans(e,i,o,r,m,R,u=null){return e.map(p=>{const y=p.uses.map(f=>{const F=i.get(f);if(F===void 0)throw new Error(`Group "${p.name}" uses unknown service "${f}"`);return F}),v=y.some(f=>f.testkit.database!==void 0)?"local":null,t=Ce(p,o,r,m.fileNames||[],m);if(t.length===0)return u?.serviceSkipped?.(p,`no matching files (types=${o.join(",")||"all"} suites=${r.map(f=>f.raw).join(",")||"all"} files=${(m.fileNames||[]).join(",")||"all"})`),{config:p,dbBackend:v,execution:R,skipped:!0,suites:[],runtimeConfigs:[],runtimeNames:[],runtimeKey:null,uses:y};for(const f of t)for(const F of f.skippedFiles)u?.plannedSkip?.({serviceName:p.name,testType:f.testType,engineId:f.engineId,profileId:f.profileId,file:F.path,reason:F.reason});const C=we(y,i),b=C.map(f=>f.name).sort();return{config:p,dbBackend:v,execution:R,skipped:!1,suites:t,runtimeConfigs:C,runtimeNames:b,runtimeKey:b.join("|"),uses:y}})}
@@ -1 +1 @@
1
- import{resolveProductDir as g}from"../../process/files/product-dir.js";import{loadRunConfigs as k}from"../../config/loader/managed-configs.js";import{parseFileTimeoutOption as F}from"../../domain/file-timeout.js";import{parseSuiteOption as w,parseTypeOption as O}from"../../domain/suite-selection.js";import{resolveRequestedFiles as R}from"../file-selection.js";import{parseTaskConcurrencyOptions as T}from"../../config/loader/decode-execution.js";import{readEnvironmentFile as h}from"../environments/environment-file.js";import{hasSuppliedInput as E,projectSuppliedEnvironment as V,resolveSuppliedInput as j,suppliedBindings as C}from"../environments/supplied-input.js";import{resolveVitestSelection as I}from"../../engines/catalog.js";export async function buildRunRequest(e,l=null,o=process.cwd(),n=process.cwd(),p=process.env){const a=T(e.taskConcurrency,e.workers),f=e.fileTimeoutSeconds==null?null:F(e.fileTimeoutSeconds),c=O(e.type,l),u=w(e.suite),S=e.file??[],r=g(o,e.dir),m=R(S,r,n),s=e.supplied??{},i=E(s)?j(s,s.environmentFile===void 0?null:h(s.environmentFile,n),p):null,t=I(e.vitest??{},r,p),{groups:d,ownershipNotice:v,services:y}=await k({dir:r,group:e.group,testSelection:{group:e.group,fileNames:m,typeValues:c,suiteSelectors:u},vitest:i===null?t:{...t,host:{...t.host,...C(i)}}});return{groups:d,ownershipNotice:v,services:y,productDir:r,supplied:i===null?null:N(i,d),typeValues:c,suiteSelectors:u,runOptions:{vitest:t,allowEmpty:e.allowEmpty,fileNames:m,taskConcurrency:a,fileTimeoutSeconds:f,serviceFilter:e.group||null,ignoreSkipRules:e.ignoreSkipRules,skipSchemaSourceVerify:e.skipSchemaSourceVerify}}}function N(e,l){return Object.fromEntries(l.map(o=>[o.name,V(e,o.uses)]))}
1
+ import{resolveProductDir as y}from"../../process/files/product-dir.js";import{loadRunConfigs as g}from"../../config/loader/managed-configs.js";import{parseFileTimeoutOption as k}from"../../domain/file-timeout.js";import{parseSuiteOption as F,parseTypeOption as w}from"../../domain/suite-selection.js";import{resolveRequestedFiles as O}from"../file-selection.js";import{parseTaskConcurrencyOptions as R}from"../../config/loader/decode-execution.js";import{readEnvironmentFile as T}from"../environments/environment-file.js";import{hasSuppliedInput as h,projectSuppliedEnvironment as E,resolveSuppliedInput as V,suppliedBindings as j}from"../environments/supplied-input.js";import{resolveVitestSelection as C}from"../../engines/catalog.js";export async function buildRunRequest(e,l=null,o=process.cwd(),n=process.cwd(),p=process.env){const a=R(e.taskConcurrency,e.workers),f=e.fileTimeoutSeconds==null?null:k(e.fileTimeoutSeconds),c=w(e.type,l),u=F(e.suite),S=e.file??[],r=y(o,e.dir),m=O(S,r,n),s=e.supplied??{},i=h(s)?V(s,s.environmentFile===void 0?null:T(s.environmentFile,n),p):null,t=C(e.vitest??{},r,p),{groups:d,services:v}=await g({dir:r,group:e.group,testSelection:{group:e.group,fileNames:m,typeValues:c,suiteSelectors:u},vitest:i===null?t:{...t,host:{...t.host,...j(i)}}});return{groups:d,services:v,productDir:r,supplied:i===null?null:I(i,d),typeValues:c,suiteSelectors:u,runOptions:{vitest:t,allowEmpty:e.allowEmpty,fileNames:m,taskConcurrency:a,fileTimeoutSeconds:f,serviceFilter:e.group||null,ignoreSkipRules:e.ignoreSkipRules,skipSchemaSourceVerify:e.skipSchemaSourceVerify}}}function I(e,l){return Object.fromEntries(l.map(o=>[o.name,E(e,o.uses)]))}
@@ -1 +1 @@
1
- import{resolveCommittedRunFinalization as z}from"../../evidence/finalization.js";import{collectTestkitStorageInventory as T,writeRunArtifact as k}from"../../evidence/index.js";import{buildRunArtifact as w}from"../../evidence/reporting.js";import{isUnknownRecord as x}from"../../kernel/unknown-values.js";export async function finalizeRunArtifacts({productDir:t,runId:e,results:i,startedAt:a,finishedAt:u,execution:c,workerCount:r,selection:n,archiveConfig:d=null,declaredEnvironmentKeys:m=[],metadata:F,environmentRecord:p,operationTimingRegistry:b=null,reporter:h,runInterruptReason:g=null,runStatus:l=null,publishRunFinalization:A}){const o=w({productDir:t,runId:e,results:i,startedAt:a,finishedAt:u,execution:c,workerCount:r,typeValues:n.typeValues,suiteSelectors:n.suiteSelectors,fileNames:n.fileNames,groupFilter:n.groupFilter,planning:n.planning??null,archiveConfig:d,declaredEnvironmentKeys:m,metadata:F,environment:p.snapshot(),operationTimings:b?.listOperations()??[],runInterruptReason:g,runStatus:l}),S=O(o.storage),v=T(t);o.storage={...S??{},testkit:v};const R=l==="failed"||i.some(s=>s.failed||s.infraFailed)?"failed":"passed",y=s=>{N(o,s);const f=C({archiveConfig:d,declaredEnvironmentKeys:m,productDir:t,redactKeys:p.redactKeys,redactionTargets:p.redactionTargets(),runArtifact:o});return h?.runSummary?.(i,u-a,f.runArtifact.run.status==="interrupted"?"interrupted":f.runArtifact.run.status==="failed"?"failed":"passed"),f};return A?await A(R,y):y(z(R,{interrupted:l==="interrupted",interruptReason:l==="interrupted"?g:null}))}function C({archiveConfig:t,declaredEnvironmentKeys:e,productDir:i,redactKeys:a,redactionTargets:u,runArtifact:c}){const r=k(i,c,{archiveConfig:t,declaredEnvironmentKeys:e,redactKeys:a,redactionTargets:u});return{runArtifact:r,shouldFailArchiveCleanup:r.archive.cleanup?.status==="failed",shouldFailArchivePublication:r.archive.publication.status==="failed"&&r.archive.publication.required===!0}}function N(t,e){if(t.run.status=e.artifactStatus,e.artifactStatus!=="interrupted"){delete t.run.interruptReason;return}t.run.interruptReason=e.interruptReason??"run interrupted"}function O(t){return x(t)?t:null}
1
+ import{resolveCommittedRunFinalization as z}from"../../evidence/finalization.js";import{collectTestkitStorageInventory as T,writeRunArtifact as k}from"../../evidence/index.js";import{buildRunArtifact as w}from"../../evidence/reporting.js";import{isUnknownRecord as x}from"../../kernel/unknown-values.js";import{formatError as C}from"../../kernel/error-serialization.js";export async function finalizeRunArtifacts({productDir:t,runId:r,results:n,startedAt:a,finishedAt:u,execution:c,workerCount:e,selection:i,archiveConfig:d=null,declaredEnvironmentKeys:m=[],metadata:h,environmentRecord:f,operationTimingRegistry:F=null,reporter:b,runInterruptReason:g=null,runStatus:o=null,publishRunFinalization:y}){const l=w({productDir:t,runId:r,results:n,startedAt:a,finishedAt:u,execution:c,workerCount:e,typeValues:i.typeValues,suiteSelectors:i.suiteSelectors,fileNames:i.fileNames,groupFilter:i.groupFilter,planning:i.planning??null,archiveConfig:d,declaredEnvironmentKeys:m,metadata:h,environment:f.snapshot(),operationTimings:F?.listOperations()??[],runInterruptReason:g,runStatus:o}),S=O(l.storage),v=V(t);l.storage={...S??{},testkit:v};const A=o==="failed"||n.some(s=>s.failed||s.infraFailed)?"failed":"passed",R=s=>{N(l,s);const p=I({archiveConfig:d,declaredEnvironmentKeys:m,productDir:t,redactKeys:f.redactKeys,redactionTargets:f.redactionTargets(),runArtifact:l});return b?.runSummary?.(n,u-a,p.runArtifact.run.status==="interrupted"?"interrupted":p.runArtifact.run.status==="failed"?"failed":"passed"),p};return y?await y(A,R):R(z(A,{interrupted:o==="interrupted",interruptReason:o==="interrupted"?g:null}))}function I({archiveConfig:t,declaredEnvironmentKeys:r,productDir:n,redactKeys:a,redactionTargets:u,runArtifact:c}){const e=k(n,c,{archiveConfig:t,declaredEnvironmentKeys:r,redactKeys:a,redactionTargets:u});return{runArtifact:e,shouldFailArchiveCleanup:e.archive.cleanup?.status==="failed",shouldFailArchivePublication:e.archive.publication.status==="failed"&&e.archive.publication.required===!0}}function N(t,r){if(t.run.status=r.artifactStatus,r.artifactStatus!=="interrupted"){delete t.run.interruptReason;return}t.run.interruptReason=r.interruptReason??"run interrupted"}function O(t){return x(t)?t:null}function V(t){try{return T(t)}catch(r){return{status:"failed",error:C(r)}}}
@@ -1 +1 @@
1
- import{isDeepStrictEqual as p}from"node:util";import{resolveExecutionProfile as u}from"../../engines/catalog.js";export const DEFAULT_COMPATIBLE_BATCH_MAX_FILES=25;export function claimCompatibleTaskBatch(e,t,o={}){const r=o.maxFiles??DEFAULT_COMPATIBLE_BATCH_MAX_FILES,s=[t],c=f(t);if(!c&&(!isBatchableEngineTask(t)||r<=1))return s;for(let i=0;i<e.length&&(c||s.length<r);){const n=e[i];if(c?n.engineId!==t.engineId||n.profileId!==t.profileId:!isCompatibleEngineBatchTask(t,n)){i+=1;continue}s.push(n),e.splice(i,1)}return s}export function buildTaskBatch(e){if(e.length<=1)return e[0]??null;const t=e[0];return{...t,batchId:a(e),batchTasks:[t,e[1],...e.slice(2)],batchFiles:e.map(o=>o.file)}}export function expandTaskResultOutcomes(e){return e?e.outcomes!==void 0?[...e.outcomes]:[e]:[]}export function isBatchableEngineTask(e){return u(e).taskBatching==="compatible"&&e.runtimeIsolation==="shared"&&e.resourceCost===1&&e.locks.length===0&&!e.hasSetup}export function isCompatibleEngineBatchTask(e,t){return!isBatchableEngineTask(e)||!isBatchableEngineTask(t)?!1:t.graphKey===e.graphKey&&t.targetName===e.targetName&&t.serviceName===e.serviceName&&t.testType===e.testType&&t.engineId===e.engineId&&t.profileId===e.profileId}const m=[["source","services"],["locks","locks"]];export function requireCompatibleSelection(e,t){const o=e.filter(f),[r]=o,s=i=>t.provisioned.has(i)?["configured",i]:[t.static.has(i)?"static":"supplied"],c=({graphKey:i,locks:n})=>({locks:n,source:s(i)});for(const i of o.length>1?o:[]){if(i.hasSetup||i.runtimeIsolation!=="shared"){const l=i.hasSetup?"a setup module":`${i.runtimeIsolation} isolation`;throw new Error(`${i.file} in group ${i.serviceName} needs ${l}, which plain Vitest files run together cannot use`)}const n=m.find(([l])=>!p(c(i)[l],c(r)[l]));if(n!==void 0)throw new Error(`Plain Vitest files run in one Vitest invocation, but ${r.file} in group ${r.serviceName} and ${i.file} in group ${i.serviceName} need different ${n[1]}; select one group with --group`)}}function f(e){return u(e).taskBatching==="selection"}function a(e){return`${e[0].engineId}-batch-${e.map(t=>t.id).join("-")}`}
1
+ import{resolveExecutionProfile as c}from"../../engines/catalog.js";export const DEFAULT_COMPATIBLE_BATCH_MAX_FILES=25;export function claimCompatibleTaskBatch(e,t,n={}){const r=n.maxFiles??DEFAULT_COMPATIBLE_BATCH_MAX_FILES,o=[t],l=p(t);if(l?f(t):!isBatchableEngineTask(t)||r<=1)return o;for(let u=0;u<e.length&&(l||o.length<r);){const i=e[u];if(l?i.engineId!==t.engineId||i.profileId!==t.profileId||f(i)||!m(t,i,n.environmentKeys):!isCompatibleEngineBatchTask(t,i)){u+=1;continue}o.push(i),e.splice(u,1)}return o}export function buildTaskBatch(e){if(e.length<=1)return e[0]??null;const t=e[0];return{...t,batchId:g(e),batchTasks:[t,e[1],...e.slice(2)],batchFiles:e.map(n=>n.file)}}export function expandTaskResultOutcomes(e){return e?e.outcomes!==void 0?[...e.outcomes]:[e]:[]}export function isBatchableEngineTask(e){return c(e).taskBatching==="compatible"&&e.resourceCost===1&&!f(e)}function f(e){return e.hasSetup||e.locks.length>0||e.runtimeIsolation!=="shared"}export function isCompatibleEngineBatchTask(e,t){return!isBatchableEngineTask(e)||!isBatchableEngineTask(t)?!1:t.graphKey===e.graphKey&&t.targetName===e.targetName&&t.serviceName===e.serviceName&&t.testType===e.testType&&t.engineId===e.engineId&&t.profileId===e.profileId}function m(e,t,n=new Map){if(t.targetName===e.targetName)return!0;const r=n.get(e.targetName);return r!==void 0&&r===n.get(t.targetName)}function p(e){return c(e).taskBatching==="selection"}function g(e){return`${e[0].engineId}-batch-${e.map(t=>t.id).join("-")}`}
@@ -1 +1 @@
1
- import{buildTaskDeadline as U,createDeadlineSignal as J,EngineExecutionBridgeError as I,executeEngineTask as H,normalizeTimeoutMs as Q}from"./engine-execution.js";import{preparationFailure as V,settlePreparedTask as X,taskStartedFailure as Y}from"./engine-execution-failures.js";import{GroupDefaultConflictError as N}from"./environment.js";import{formatError as Z,toError as x}from"../../kernel/error-serialization.js";import{formatEngineInvocationStack as ee}from"./engine-failure-stack.js";import{DEFAULT_ENGINE_REPORTER_CALLBACK_TIMEOUT_MS as _,invokeBoundedReporterCallback as te,invokeEngineReporterCallback as L}from"./engine-execution-reporting.js";import{drainRuntimeFailedTasks as ie}from"./runtime-failures.js";import{buildTimingObservation as ae}from"./scheduler/observations.js";import{buildTaskBatch as ne,claimCompatibleTaskBatch as re,expandTaskResultOutcomes as se}from"./task-batches.js";export function createWorker(e,a){return{workerId:e,productDir:a,currentGraphKey:null,graphSwitches:0,taskCount:0}}export async function runWorker(e,a,t,l,n,u,c,k,g,m=null){const v=Date.now(),w=[],q=[];try{for(;!t.isStopRequested();){const o=c(a,e.currentGraphKey,i=>t.locks.available(i.locks)&&t.environments.canAcquire(i));if(!o){const i=ie(a,t.environments);if(i.length>0){const s=Date.now(),r=new Set;for(const p of i)k(n,p.task,{status:"not_run",reason:p.reason,durationMs:0,startedAt:s,finishedAt:s,error:null,infraFailed:p.infraFailed,blockedByRuntime:p.blockedByRuntime,failureDetails:p.failureDetails}),r.has(p.graph.key)||(g(n,p.graph,p.message,s,{classification:"infra"}),r.add(p.graph.key));e.taskCount+=i.length;continue}if(a.length===0)break;await pe(10);continue}const E=t.leases.allocate(o);t.locks.acquire(o.locks,E.id);let M=null,T=[o],D=o,O=!1,R=null;const d={phase:"acquire",prepared:null};let C=[],F=[],B=null;try{T=re(a,o),D=ne(T)??o,e.currentGraphKey!==null&&e.currentGraphKey!==o.graphKey&&(e.graphSwitches+=1),e.currentGraphKey=o.graphKey;const i=await t.environments.acquire(D,E);M=i,t.leases.create(E),d.phase="execute";const s=await l.withEngine(o.engineId,t.signal,async r=>{let p=null;if(T.length===1){d.phase="start",await L("taskStarted",()=>m?.taskStarted?.(o,{name:o.targetName}),{signal:t.signal,timeoutMs:_}),d.phase="prepare";const K=Q(t.request.fileTimeoutSeconds),y=U(Date.now(),K),b=J(t.signal,y);try{d.prepared=await i.prepare(o,{deadlineMs:y,signal:b.signal,timeoutMs:K})}finally{b.dispose()}p={deadlineMs:y,prepared:d.prepared===null?null:{artifacts:d.prepared.artifacts,handles:d.prepared.handles,setupData:d.prepared.setupData},taskId:String(o.id)},d.phase="execute"}return H(r,{environment:d.prepared?.environment??i.environment,lease:E,request:t.request,started:p,task:D},t,m)});d.phase="mapping",C=se(s),F=resolveWorkerOutcomeMappings(T,C),F.some(({outcome:r})=>r.infraFailed&&r.blockedByRuntime)&&(O=!0)}catch(i){const s=d.phase==="start"?Y(i,String(o.id)):d.phase==="prepare"?V(i,String(o.id)):i,r=d.phase==="acquire"?fe(i,t):ue(s);R={disposition:r,error:s},O=M!==null&&r.runtimeImpact!=="none"}finally{if(d.prepared!==null){const i=await d.prepared.release(),s=await X(R===null?{outcomes:C}:{error:R.error},i,String(o.id),r=>L("taskFinished",()=>m?.taskFinished?.(o,r),{signal:t.signal,timeoutMs:_}));s!==null&&(R={disposition:s.disposition,error:s},O||=s.disposition.runtimeImpact!=="none")}B=await le(t.leases,M,E,O),t.locks.release(o.locks,E.id)}const f=[];let S=null;const $=()=>{if(S!==null)return S;try{S=de(t.environments,o)}catch(i){f.push(j("Runtime failure graph resolution failed",i)),S=A(o)}return S};if(R===null){for(const{outcome:s,task:r}of F)await P({operationErrors:f,outcome:s,recordTaskOutcome:k,recordTiming:!0,reporter:m,reportTaskFinished:!1,task:r,timingUpdates:u,trackers:n});e.taskCount+=F.length;const i=F.filter(({outcome:s})=>s.infraFailed&&s.blockedByRuntime);if(i.length>0){const s=i.map(({outcome:r})=>r.reason??r.error??"Runtime readiness failed before engine execution").join("; ");w.push(s),await G(f,"Runtime error reporter failed",()=>m?.runtimeError?.(o,s)),await h(f,"Runtime graph failure recording failed",()=>{t.environments.markGraphFailed(o.graphKey,s)}),await h(f,"Result graph error recording failed",()=>{g(n,$(),s,Date.now(),{classification:"infra"})})}}else{const{disposition:i,error:s}=R,r=Z(s),p=oe(T,s);if(i.status!=="cancelled"&&w.push(r),i.notifyRuntimeError&&await G(f,"Runtime error reporter failed",()=>m?.runtimeError?.(p,r)),i.status!=="cancelled"){i.runtimeImpact==="fail-graph"&&await h(f,"Runtime graph failure recording failed",()=>{t.environments.markGraphFailed(o.graphKey,r)});const y=s instanceof N?A(o):$();await h(f,"Result graph error recording failed",()=>{g(n,y,r,Date.now(),{classification:i.classification??"product"})})}const K=Date.now();for(const y of T){const b=s instanceof I&&s.completedOutcomesByTaskId.has(String(y.id)),z=ce(y,D,s,i,r,K);await P({operationErrors:f,outcome:z,recordTaskOutcome:k,recordTiming:b,reporter:m,reportTaskFinished:!b,task:y,timingUpdates:u,trackers:n})}e.taskCount+=T.length}if(B!==null){const i=B.message;w.push(i),await G(f,"Runtime error reporter failed",()=>m?.runtimeError?.(o,i)),B.recovered||await h(f,"Runtime graph failure recording failed",()=>{t.environments.markGraphFailed(o.graphKey,i)}),await h(f,"Result graph error recording failed",()=>{g(n,$(),i,Date.now(),{classification:"infra"})})}if(f.length>0){const i=[...f];for(const r of i)w.push(r.message);const s=i.map(r=>r.message).join("; ");await h(f,"Result graph error recording failed while reporting a Testkit operation failure",()=>{g(n,$(),s,Date.now(),{classification:"infra"})});for(const r of f.slice(i.length))w.push(r.message);f.length>i.length&&q.push(...i.map(r=>r.message),...f.slice(i.length).map(r=>r.message))}}}finally{e.currentGraphKey=null}return{workerId:e.workerId,failed:w.length>0,durationMs:Date.now()-v,taskCount:e.taskCount,graphSwitches:e.graphSwitches,errors:w,unpersistedErrors:q}}async function P({operationErrors:e,outcome:a,recordTaskOutcome:t,recordTiming:l,reporter:n,reportTaskFinished:u,task:c,timingUpdates:k,trackers:g}){await h(e,`Task outcome recording failed for ${c.file}`,()=>{t(g,c,a)}),u&&await G(e,`Task-finished reporter failed for ${c.file}`,()=>n?.taskFinished?.(c,a)),l&&await h(e,`Task timing recording failed for ${c.file}`,()=>{const m=ae(c,a);m&&k.push(m)})}async function h(e,a,t){try{await t()}catch(l){e.push(j(a,l))}}async function G(e,a,t){await h(e,a,()=>te(a,t,{timeoutMs:_}))}function j(e,a){const t=x(a);return new Error(`${e}: ${t.message}`,{cause:t})}function oe(e,a){const t=e[0];if(!(a instanceof I))return t;if(a.failingTaskId!==null){const l=e.find(n=>String(n.id)===a.failingTaskId);if(l!==void 0)return l}return e.find(l=>!a.completedOutcomesByTaskId.has(String(l.id)))??t}function A(e){return{key:e.graphKey,targetNames:[e.targetName]}}async function le(e,a,t,l){const n=async u=>{await a?.release({invalidate:u}),e.remove(t)};try{return await n(l),null}catch(u){const c=x(u);try{return await n(!0),{message:`Runtime lease release failed but recovered on idempotent retry: ${c.message}`,recovered:!0}}catch(k){const g=x(k);return{message:`Runtime lease release failed: ${c.message}; idempotent retry also failed: ${g.message}`,recovered:!1}}}}function ce(e,a,t,l,n,u){const c=ee(t),k={kind:"engine-invocation",key:"engine_invocation_failed",title:"Engine invocation failed",count:1,...l.classification===void 0?{}:{classification:l.classification},message:n,...c===void 0?{}:{stack:c}},g=t instanceof I?t.completedOutcomesByTaskId.get(String(e.id)):void 0;if(g!==void 0)return g;const m=t instanceof I?t.artifactReferencesByTaskId.get(String(e.id))??[]:[];return{task:e,status:l.status,error:l.status==="failed"?n:null,reason:l.status==="failed"?null:n,infraFailed:l.classification==="infra",blockedByRuntime:l.status==="not_run",durationMs:0,startedAt:u,finishedAt:u,artifacts:[...m],failureDetails:l.status==="cancelled"?[]:[k],..."batchTasks"in a?{runtimeBatch:{id:a.batchId,index:a.batchTasks.findIndex(v=>v.id===e.id&&v.file===e.file),fileCount:a.batchTasks.length,files:a.batchTasks.map(v=>v.file)}}:{}}}function ue(e){return e instanceof I?e.disposition:{classification:"infra",notifyRuntimeError:!0,runtimeImpact:"none",status:"not_run"}}function fe(e,a){return a.signal.aborted&&e===a.signal.reason?{classification:void 0,notifyRuntimeError:!1,runtimeImpact:"none",status:"cancelled"}:{classification:"infra",notifyRuntimeError:!0,runtimeImpact:e instanceof N?"none":"fail-graph",status:"not_run"}}export function resolveWorkerOutcomeMappings(e,a){const t=new Map;for(const n of e){const u=W(n);if(t.has(u))throw new Error(`Worker claimed duplicate task ${n.id.toString()} (${n.file})`);t.set(u,n)}const l=new Map;for(const n of a){const u=W(n.task),c=t.get(u);if(!c)throw new Error(`Task runner returned an outcome for unclaimed task ${n.task.id.toString()} (${n.task.file})`);if(l.has(u))throw new Error(`Task runner returned duplicate outcomes for claimed task ${c.id.toString()} (${c.file})`);l.set(u,{outcome:n,task:c})}for(const n of e)if(!l.has(W(n)))throw new Error(`Task runner did not return an outcome for claimed task ${n.id.toString()} (${n.file})`);return[...l.values()]}function W(e){return JSON.stringify([typeof e.id,e.id,e.file])}function de(e,a){return e.getGraph(a.graphKey)??A(a)}function pe(e){return new Promise(a=>setTimeout(a,e))}
1
+ import{buildTaskDeadline as U,createDeadlineSignal as J,EngineExecutionBridgeError as I,executeEngineTask as H,normalizeTimeoutMs as Q}from"./engine-execution.js";import{preparationFailure as V,settlePreparedTask as X,taskStartedFailure as Y}from"./engine-execution-failures.js";import{GroupDefaultConflictError as N}from"./environment.js";import{formatError as Z,toError as x}from"../../kernel/error-serialization.js";import{formatEngineInvocationStack as ee}from"./engine-failure-stack.js";import{DEFAULT_ENGINE_REPORTER_CALLBACK_TIMEOUT_MS as _,invokeBoundedReporterCallback as te,invokeEngineReporterCallback as L}from"./engine-execution-reporting.js";import{drainRuntimeFailedTasks as ie}from"./runtime-failures.js";import{buildTimingObservation as ae}from"./scheduler/observations.js";import{buildTaskBatch as ne,claimCompatibleTaskBatch as re,expandTaskResultOutcomes as se}from"./task-batches.js";export function createWorker(e,a){return{workerId:e,productDir:a,currentGraphKey:null,graphSwitches:0,taskCount:0}}export async function runWorker(e,a,t,l,n,u,c,k,g,m=null){const v=Date.now(),w=[],q=[];try{for(;!t.isStopRequested();){const o=c(a,e.currentGraphKey,i=>t.locks.available(i.locks)&&t.environments.canAcquire(i));if(!o){const i=ie(a,t.environments);if(i.length>0){const s=Date.now(),r=new Set;for(const p of i)k(n,p.task,{status:"not_run",reason:p.reason,durationMs:0,startedAt:s,finishedAt:s,error:null,infraFailed:p.infraFailed,blockedByRuntime:p.blockedByRuntime,failureDetails:p.failureDetails}),r.has(p.graph.key)||(g(n,p.graph,p.message,s,{classification:"infra"}),r.add(p.graph.key));e.taskCount+=i.length;continue}if(a.length===0)break;await pe(10);continue}const E=t.leases.allocate(o);t.locks.acquire(o.locks,E.id);let M=null,T=[o],D=o,O=!1,R=null;const d={phase:"acquire",prepared:null};let C=[],F=[],B=null;try{T=re(a,o,{environmentKeys:t.environmentKeys}),D=ne(T)??o,e.currentGraphKey!==null&&e.currentGraphKey!==o.graphKey&&(e.graphSwitches+=1),e.currentGraphKey=o.graphKey;const i=await t.environments.acquire(D,E);M=i,t.leases.create(E),d.phase="execute";const s=await l.withEngine(o.engineId,t.signal,async r=>{let p=null;if(T.length===1){d.phase="start",await L("taskStarted",()=>m?.taskStarted?.(o,{name:o.targetName}),{signal:t.signal,timeoutMs:_}),d.phase="prepare";const $=Q(t.request.fileTimeoutSeconds),y=U(Date.now(),$),b=J(t.signal,y);try{d.prepared=await i.prepare(o,{deadlineMs:y,signal:b.signal,timeoutMs:$})}finally{b.dispose()}p={deadlineMs:y,prepared:d.prepared===null?null:{artifacts:d.prepared.artifacts,handles:d.prepared.handles,setupData:d.prepared.setupData},taskId:String(o.id)},d.phase="execute"}return H(r,{environment:d.prepared?.environment??i.environment,lease:E,request:t.request,started:p,task:D},t,m)});d.phase="mapping",C=se(s),F=resolveWorkerOutcomeMappings(T,C),F.some(({outcome:r})=>r.infraFailed&&r.blockedByRuntime)&&(O=!0)}catch(i){const s=d.phase==="start"?Y(i,String(o.id)):d.phase==="prepare"?V(i,String(o.id)):i,r=d.phase==="acquire"?fe(i,t):ue(s);R={disposition:r,error:s},O=M!==null&&r.runtimeImpact!=="none"}finally{if(d.prepared!==null){const i=await d.prepared.release(),s=await X(R===null?{outcomes:C}:{error:R.error},i,String(o.id),r=>L("taskFinished",()=>m?.taskFinished?.(o,r),{signal:t.signal,timeoutMs:_}));s!==null&&(R={disposition:s.disposition,error:s},O||=s.disposition.runtimeImpact!=="none")}B=await le(t.leases,M,E,O),t.locks.release(o.locks,E.id)}const f=[];let S=null;const K=()=>{if(S!==null)return S;try{S=de(t.environments,o)}catch(i){f.push(j("Runtime failure graph resolution failed",i)),S=A(o)}return S};if(R===null){for(const{outcome:s,task:r}of F)await P({operationErrors:f,outcome:s,recordTaskOutcome:k,recordTiming:!0,reporter:m,reportTaskFinished:!1,task:r,timingUpdates:u,trackers:n});e.taskCount+=F.length;const i=F.filter(({outcome:s})=>s.infraFailed&&s.blockedByRuntime);if(i.length>0){const s=i.map(({outcome:r})=>r.reason??r.error??"Runtime readiness failed before engine execution").join("; ");w.push(s),await G(f,"Runtime error reporter failed",()=>m?.runtimeError?.(o,s)),await h(f,"Runtime graph failure recording failed",()=>{t.environments.markGraphFailed(o.graphKey,s)}),await h(f,"Result graph error recording failed",()=>{g(n,K(),s,Date.now(),{classification:"infra"})})}}else{const{disposition:i,error:s}=R,r=Z(s),p=oe(T,s);if(i.status!=="cancelled"&&w.push(r),i.notifyRuntimeError&&await G(f,"Runtime error reporter failed",()=>m?.runtimeError?.(p,r)),i.status!=="cancelled"){i.runtimeImpact==="fail-graph"&&await h(f,"Runtime graph failure recording failed",()=>{t.environments.markGraphFailed(o.graphKey,r)});const y=s instanceof N?A(o):K();await h(f,"Result graph error recording failed",()=>{g(n,y,r,Date.now(),{classification:i.classification??"product"})})}const $=Date.now();for(const y of T){const b=s instanceof I&&s.completedOutcomesByTaskId.has(String(y.id)),z=ce(y,D,s,i,r,$);await P({operationErrors:f,outcome:z,recordTaskOutcome:k,recordTiming:b,reporter:m,reportTaskFinished:!b,task:y,timingUpdates:u,trackers:n})}e.taskCount+=T.length}if(B!==null){const i=B.message;w.push(i),await G(f,"Runtime error reporter failed",()=>m?.runtimeError?.(o,i)),B.recovered||await h(f,"Runtime graph failure recording failed",()=>{t.environments.markGraphFailed(o.graphKey,i)}),await h(f,"Result graph error recording failed",()=>{g(n,K(),i,Date.now(),{classification:"infra"})})}if(f.length>0){const i=[...f];for(const r of i)w.push(r.message);const s=i.map(r=>r.message).join("; ");await h(f,"Result graph error recording failed while reporting a Testkit operation failure",()=>{g(n,K(),s,Date.now(),{classification:"infra"})});for(const r of f.slice(i.length))w.push(r.message);f.length>i.length&&q.push(...i.map(r=>r.message),...f.slice(i.length).map(r=>r.message))}}}finally{e.currentGraphKey=null}return{workerId:e.workerId,failed:w.length>0,durationMs:Date.now()-v,taskCount:e.taskCount,graphSwitches:e.graphSwitches,errors:w,unpersistedErrors:q}}async function P({operationErrors:e,outcome:a,recordTaskOutcome:t,recordTiming:l,reporter:n,reportTaskFinished:u,task:c,timingUpdates:k,trackers:g}){await h(e,`Task outcome recording failed for ${c.file}`,()=>{t(g,c,a)}),u&&await G(e,`Task-finished reporter failed for ${c.file}`,()=>n?.taskFinished?.(c,a)),l&&await h(e,`Task timing recording failed for ${c.file}`,()=>{const m=ae(c,a);m&&k.push(m)})}async function h(e,a,t){try{await t()}catch(l){e.push(j(a,l))}}async function G(e,a,t){await h(e,a,()=>te(a,t,{timeoutMs:_}))}function j(e,a){const t=x(a);return new Error(`${e}: ${t.message}`,{cause:t})}function oe(e,a){const t=e[0];if(!(a instanceof I))return t;if(a.failingTaskId!==null){const l=e.find(n=>String(n.id)===a.failingTaskId);if(l!==void 0)return l}return e.find(l=>!a.completedOutcomesByTaskId.has(String(l.id)))??t}function A(e){return{key:e.graphKey,targetNames:[e.targetName]}}async function le(e,a,t,l){const n=async u=>{await a?.release({invalidate:u}),e.remove(t)};try{return await n(l),null}catch(u){const c=x(u);try{return await n(!0),{message:`Runtime lease release failed but recovered on idempotent retry: ${c.message}`,recovered:!0}}catch(k){const g=x(k);return{message:`Runtime lease release failed: ${c.message}; idempotent retry also failed: ${g.message}`,recovered:!1}}}}function ce(e,a,t,l,n,u){const c=ee(t),k={kind:"engine-invocation",key:"engine_invocation_failed",title:"Engine invocation failed",count:1,...l.classification===void 0?{}:{classification:l.classification},message:n,...c===void 0?{}:{stack:c}},g=t instanceof I?t.completedOutcomesByTaskId.get(String(e.id)):void 0;if(g!==void 0)return g;const m=t instanceof I?t.artifactReferencesByTaskId.get(String(e.id))??[]:[];return{task:e,status:l.status,error:l.status==="failed"?n:null,reason:l.status==="failed"?null:n,infraFailed:l.classification==="infra",blockedByRuntime:l.status==="not_run",durationMs:0,startedAt:u,finishedAt:u,artifacts:[...m],failureDetails:l.status==="cancelled"?[]:[k],..."batchTasks"in a?{runtimeBatch:{id:a.batchId,index:a.batchTasks.findIndex(v=>v.id===e.id&&v.file===e.file),fileCount:a.batchTasks.length,files:a.batchTasks.map(v=>v.file)}}:{}}}function ue(e){return e instanceof I?e.disposition:{classification:"infra",notifyRuntimeError:!0,runtimeImpact:"none",status:"not_run"}}function fe(e,a){return a.signal.aborted&&e===a.signal.reason?{classification:void 0,notifyRuntimeError:!1,runtimeImpact:"none",status:"cancelled"}:{classification:"infra",notifyRuntimeError:!0,runtimeImpact:e instanceof N?"none":"fail-graph",status:"not_run"}}export function resolveWorkerOutcomeMappings(e,a){const t=new Map;for(const n of e){const u=W(n);if(t.has(u))throw new Error(`Worker claimed duplicate task ${n.id.toString()} (${n.file})`);t.set(u,n)}const l=new Map;for(const n of a){const u=W(n.task),c=t.get(u);if(!c)throw new Error(`Task runner returned an outcome for unclaimed task ${n.task.id.toString()} (${n.task.file})`);if(l.has(u))throw new Error(`Task runner returned duplicate outcomes for claimed task ${c.id.toString()} (${c.file})`);l.set(u,{outcome:n,task:c})}for(const n of e)if(!l.has(W(n)))throw new Error(`Task runner did not return an outcome for claimed task ${n.id.toString()} (${n.file})`);return[...l.values()]}function W(e){return JSON.stringify([typeof e.id,e.id,e.file])}function de(e,a){return e.getGraph(a.graphKey)??A(a)}function pe(e){return new Promise(a=>setTimeout(a,e))}
@@ -1 +1 @@
1
- import{createEnvironmentMaintenance as l}from"../../environment/maintenance.js";import{runtimePlanning as p}from"../../environment/runtime-planning.js";import{collectBundleCacheStatus as d}from"../../engines/bundle-cache.js";import{collectDirectorySummary as h}from"../../process/files/directory-status.js";export function collectStatusModel(t,{allConfigs:e=[t]}={}){const n=t.productDir,i=p.collectDesiredRuntimeGraphs(e),{runtimeGraphs:r,runs:o}=l(n).inspect(i,t.name),u=h(t.stateDir),s=d(n,t.name),a=S({runtimeGraphs:r,bundles:s}),m=u.exists||r.some(c=>c.exists)||o.total>0||s.exists;return{schemaVersion:1,name:t.name,product:{dir:n,configFile:t.configFile||null,services:e.map(c=>c.name).sort(),selectedService:t.name,dependencies:[...t.testkit.dependsOn].sort()},hasState:m,runs:o,serviceState:u,runtimeGraphs:r,caches:{bundles:s},warnings:a}}function S({runtimeGraphs:t,bundles:e}){const n=[],i=t.reduce((r,o)=>r+o.staleRuntimeDirs.length,0);if(i>0&&n.push(`${i.toString()} stale runtime ${i===1?"directory":"directories"} found outside the configured runtime set.`),e.duplicatedSourceCount>0&&n.push(`${e.duplicatedSourceCount.toString()} source file${e.duplicatedSourceCount===1?"":"s"} have duplicate bundle versions.`),e.unmanagedFileCount>0&&n.push(`${e.unmanagedFileCount.toString()} bundle cache file${e.unmanagedFileCount===1?"":"s"} are unmanaged by the manifest.`),(e.sourcemapFileCount??0)>0||e.sourcemapStatus==="detected"){const r=e.sourcemapFileCount==null?"Bundle files":`${e.sourcemapFileCount.toString()} bundle file${e.sourcemapFileCount===1?"":"s"}`;n.push(`${r} contain inline sourcemaps.`)}return n}
1
+ import{createEnvironmentMaintenance as l}from"../../environment/maintenance.js";import{runtimePlanning as d}from"../../environment/runtime-planning.js";import{collectBundleCacheStatus as p}from"../../engines/bundle-cache.js";import{collectDirectorySummary as h}from"../../process/files/directory-status.js";import{readRunMaintenance as f}from"../../evidence/maintenance.js";import{formatError as S}from"../../kernel/error-serialization.js";export function collectStatusModel(t,{allConfigs:e=[t]}={}){const n=t.productDir,o=d.collectDesiredRuntimeGraphs(e),{runtimeGraphs:r,runs:i}=l(n).inspect(o,t.name),s=h(t.stateDir),a=p(n,t.name),u=[...$({runtimeGraphs:r,bundles:a}),...C(n)],m=s.exists||r.some(c=>c.exists)||i.total>0||a.exists;return{schemaVersion:1,name:t.name,product:{dir:n,configFile:t.configFile||null,services:e.map(c=>c.name).sort(),selectedService:t.name,dependencies:[...t.testkit.dependsOn].sort()},hasState:m,runs:i,serviceState:s,runtimeGraphs:r,caches:{bundles:a},warnings:u}}function $({runtimeGraphs:t,bundles:e}){const n=[],o=t.reduce((r,i)=>r+i.staleRuntimeDirs.length,0);if(o>0&&n.push(`${o.toString()} stale runtime ${o===1?"directory":"directories"} found outside the configured runtime set.`),e.duplicatedSourceCount>0&&n.push(`${e.duplicatedSourceCount.toString()} source file${e.duplicatedSourceCount===1?"":"s"} have duplicate bundle versions.`),e.unmanagedFileCount>0&&n.push(`${e.unmanagedFileCount.toString()} bundle cache file${e.unmanagedFileCount===1?"":"s"} are unmanaged by the manifest.`),(e.sourcemapFileCount??0)>0||e.sourcemapStatus==="detected"){const r=e.sourcemapFileCount==null?"Bundle files":`${e.sourcemapFileCount.toString()} bundle file${e.sourcemapFileCount===1?"":"s"}`;n.push(`${r} contain inline sourcemaps.`)}return n}function C(t){try{const e=f(t);return e?.status!=="failed"?[]:[`Run ${e.runId}'s post-run maintenance failed: ${e.error??"unknown error"}`]}catch(e){return[`The last run's maintenance record could not be read: ${S(e)}`]}}
@@ -1 +1 @@
1
- import c from"node:fs";import f from"node:path";import{inspectRunManifests as d}from"../../process/runs/inspection.js";import{resolveProductDir as m}from"../../process/files/product-dir.js";import{asUnknownRecord as o,displayString as l,isUnknownRecord as p,optionalString as i}from"../../kernel/unknown-values.js";export async function collectRunStatus(t){if(t.runId){const e=m(process.cwd(),t.dir);if(!c.statSync(e).isDirectory())throw new Error(`Product directory is not a directory: ${e}`);return buildRunStatus({productDir:e},t)}const{loadConfigContext:r}=await import("../../config/loader/index.js"),n=await r({dir:t.dir,plain:!1,retired:[]});return buildRunStatus(n,t)}export function buildRunStatus(t,r={}){const n=d(t.productDir,r.runId||void 0),e=S(f.join(t.productDir,".testkit","results","live.json"));if(r.full)return Promise.resolve({productDir:t.productDir,mode:"full",runs:n,live:e});const s={productDir:t.productDir,mode:"summary",runs:n.map(A),live:b(e)};return s.live&&(s.live.state=describeLiveArtifactState(s)),Promise.resolve(s)}export function latestOperation(t){if(!Array.isArray(t))return null;const r=t.filter(p);return[...r].reverse().find(n=>n.status==="running")??r.at(-1)??null}export function describeLiveArtifactState(t){const r=o(t.live),n=o(r?.run),e=l(n?.id,"unknown"),s=l(n?.status,"unknown"),a=y(t,e);return s==="running"&&!a?{runId:e,status:"stale",reason:"no active run matches this live artifact"}:{runId:e,status:s,reason:i(n?.interruptReason)}}function y(t,r){if(!r||r==="unknown")return!1;for(const n of t.runs??[])if(n.active&&v(r,n.runId))return!0;return!1}function v(t,r){if(!r)return!1;const n=typeof r=="string"?r:typeof r=="number"&&Number.isFinite(r)?r.toString():null;return n?n===t||n.startsWith(`${t}:`):!1}function A(t){const r=g(t.status);return{runId:t.runId,pid:t.pid,status:t.status||"unknown",startedAt:t.startedAt||null,heartbeatAt:t.heartbeatAt||null,interruptReason:t.interruptReason||null,active:t.active,terminal:r,stale:!t.active&&!r,session:h(t.session)}}function g(t){return typeof t=="string"&&["finished","failed","interrupted"].includes(t)}function h(t){const r=o(t);return r?{kind:i(r.kind),status:i(r.status),stage:i(r.stage)}:null}function b(t){const r=o(t);if(!r)return null;const e=o(r.timings)?.operations??[],s=Array.isArray(e)?e:[],a=o(r.product),u=o(r.run);return{present:!0,schemaVersion:k(r.schemaVersion),generatedAt:i(r.generatedAt),product:a?{name:i(a.name),directory:i(a.directory)}:null,run:u?{id:i(u.id),status:i(u.status),startedAt:i(u.startedAt),finishedAt:i(u.finishedAt),durationMs:w(u.durationMs),interruptReason:i(u.interruptReason),testkitVersion:i(u.testkitVersion)}:null,summary:r.summary??null,operation:latestOperation(s),operationCount:s.length,artifactRef:".testkit/results/live.json",truncated:!0}}function w(t){const r=Number(t);return Number.isFinite(r)?r:null}function k(t){return typeof t=="number"&&Number.isFinite(t)?t:null}function S(t){try{return JSON.parse(c.readFileSync(t,"utf8"))}catch{return null}}
1
+ import c from"node:fs";import f from"node:path";import{inspectRunManifests as d}from"../../process/runs/inspection.js";import{resolveProductDir as m}from"../../process/files/product-dir.js";import{asUnknownRecord as o,displayString as l,isUnknownRecord as p,optionalString as i}from"../../kernel/unknown-values.js";export async function collectRunStatus(t){if(t.runId){const e=m(process.cwd(),t.dir);if(!c.statSync(e).isDirectory())throw new Error(`Product directory is not a directory: ${e}`);return buildRunStatus({productDir:e},t)}const{loadConfigContext:r}=await import("../../config/loader/index.js"),n=await r({dir:t.dir,allowUnmigratedServices:!0,plain:!1,retired:[]});return buildRunStatus(n,t)}export function buildRunStatus(t,r={}){const n=d(t.productDir,r.runId||void 0),e=k(f.join(t.productDir,".testkit","results","live.json"));if(r.full)return Promise.resolve({productDir:t.productDir,mode:"full",runs:n,live:e});const s={productDir:t.productDir,mode:"summary",runs:n.map(g),live:w(e)};return s.live&&(s.live.state=describeLiveArtifactState(s)),Promise.resolve(s)}export function latestOperation(t){if(!Array.isArray(t))return null;const r=t.filter(p);return[...r].reverse().find(n=>n.status==="running")??r.at(-1)??null}export function describeLiveArtifactState(t){const r=o(t.live),n=o(r?.run),e=l(n?.id,"unknown"),s=l(n?.status,"unknown"),a=y(t,e);return s==="running"&&!a?{runId:e,status:"stale",reason:"no active run matches this live artifact"}:{runId:e,status:s,reason:i(n?.interruptReason)}}function y(t,r){if(!r||r==="unknown")return!1;for(const n of t.runs??[])if(n.active&&v(r,n.runId))return!0;return!1}function v(t,r){if(!r)return!1;const n=typeof r=="string"?r:typeof r=="number"&&Number.isFinite(r)?r.toString():null;return n?n===t||n.startsWith(`${t}:`):!1}function g(t){const r=A(t.status);return{runId:t.runId,pid:t.pid,status:t.status||"unknown",startedAt:t.startedAt||null,heartbeatAt:t.heartbeatAt||null,interruptReason:t.interruptReason||null,active:t.active,terminal:r,stale:!t.active&&!r,session:h(t.session)}}function A(t){return typeof t=="string"&&["finished","failed","interrupted"].includes(t)}function h(t){const r=o(t);return r?{kind:i(r.kind),status:i(r.status),stage:i(r.stage)}:null}function w(t){const r=o(t);if(!r)return null;const e=o(r.timings)?.operations??[],s=Array.isArray(e)?e:[],a=o(r.product),u=o(r.run);return{present:!0,schemaVersion:S(r.schemaVersion),generatedAt:i(r.generatedAt),product:a?{name:i(a.name),directory:i(a.directory)}:null,run:u?{id:i(u.id),status:i(u.status),startedAt:i(u.startedAt),finishedAt:i(u.finishedAt),durationMs:b(u.durationMs),interruptReason:i(u.interruptReason),testkitVersion:i(u.testkitVersion)}:null,summary:r.summary??null,operation:latestOperation(s),operationCount:s.length,artifactRef:".testkit/results/live.json",truncated:!0}}function b(t){const r=Number(t);return Number.isFinite(r)?r:null}function S(t){return typeof t=="number"&&Number.isFinite(t)?t:null}function k(t){try{return JSON.parse(c.readFileSync(t,"utf8"))}catch{return null}}
@@ -1,4 +1,4 @@
1
- import{attachErrorDiagnostics as S}from"../../kernel/error-serialization.js";import{isPathWithin as b}from"../../process/files/paths.js";import{resolveProductDir as $}from"../../process/files/product-dir.js";import l from"fs";import i from"path";import{createHash as C}from"crypto";import{createRequire as O}from"module";import{fileURLToPath as _}from"url";import{resolveVitestSelection as M}from"../../engines/catalog.js";import{NODE_VITEST_PACKAGE_REQUIREMENTS as A}from"../../engines/installations/package-requirements.js";import{PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS as N}from"../../engines/installations/package-requirements.js";import{hasDiscoveryErrors as R,buildDiscoveryErrorFromDiagnostics as I,detectNextApp as F,loadDiscoveredConfigContext as D}from"../../config/loader/index.js";import{managedHostProcessInfrastructureError as G,runManagedHostProcess as U}from"../../process/index.js";import{findNearestPlaywrightConfigFile as J}from"../../engines/playwright/runtime/config-file.js";import{isUnknownRecord as k}from"../../kernel/unknown-values.js";const L=600*1e3,y=i.resolve(i.dirname(_(import.meta.url)),"..","..",".."),x=O(i.join(y,"package.json")),v=()=>x("typescript");export class TestkitTypecheckError extends Error{result;results;constructor(n,t,o){super(`testkit typecheck failed for ${n}`),this.result=t,this.results=o,S(this,{result:t,results:o})}}export async function runTestkitTypecheck(e={}){w(e.timeoutMs);const n=$(process.cwd(),e.dir),t=M(e.vitest??{},n),{context:o,discovery:s}=await D({dir:n,vitest:t});return o.ownershipNotice!==null&&e.notice?.(o.ownershipNotice),runTestkitTypecheckForContext(o,s,e)}export async function runTestkitTypecheckForContext(e,n,t={}){const o=w(t.timeoutMs);if(R(e.discovery.diagnostics))throw I(e.discovery.diagnostics);const s=e.productDir,r=i.join(s,".testkit","_typecheck");l.mkdirSync(r,{recursive:!0});const c=[];if(e.configFile){const p=z({productDir:s,configFile:e.configFile,outputDir:r});c.push({label:"config",cwd:s,tsconfigPath:p})}const a=n.files.filter(p=>/\.[cm]?tsx?$/u.test(p.path)).map(p=>({engineId:p.engineId,path:p.path})),u=new Set(n.files.filter(p=>p.engineId==="playwright").map(p=>p.group));for(const p of e.groups){if(!u.has(p.name))continue;const h=J(s,p.roots);h&&a.push({engineId:"playwright",path:h})}const d=q(s,a);for(const p of d){const h=K({...p,outputDir:r,productDir:s});c.push({label:W(p.engineId,p.scopeName),cwd:p.cwd,tsconfigPath:h})}const g=[];for(const p of c){const h=await Q(p,o,t.signal);if(g.push(h),!h.ok)throw new TestkitTypecheckError(p.label,h,g)}return{ok:!0,productDir:s,results:g}}function z({productDir:e,configFile:n,outputDir:t}){const o=i.join(t,"config.tsconfig.json"),s=E(e),r={...s?{extends:f(o,s)}:{},compilerOptions:buildTypecheckCompilerOptions({tsconfigPath:o,extendsPath:s,libs:["ES2022"],rootDir:f(o,e),types:["node"]}),files:[f(o,n)],include:[],exclude:[m(o,e,"node_modules"),m(o,e,"dist"),m(o,e,".testkit")]};return l.writeFileSync(o,`${JSON.stringify(r,null,2)}
2
- `),o}function K({productDir:e,cwd:n,engineId:t,extendsPath:o,files:s,outputDir:r,scopeName:c}){const a=i.join(r,`${t}.${Y(c)}.tsconfig.json`),u=t==="playwright",d=u&&F(n),g={...o?{extends:f(a,o)}:{},compilerOptions:{...buildTypecheckCompilerOptions({engineId:t,tsconfigPath:a,extendsPath:o,libs:H(t),...d?{extraPaths:nextRuntimeTypePaths({tsconfigPath:a,serviceDir:n})}:{},types:["node"]}),...u?{allowJs:!0,checkJs:!1}:{}},files:s.map(p=>f(a,p)),include:d?[...l.existsSync(i.join(n,"next-env.d.ts"))?[f(a,i.join(n,"next-env.d.ts"))]:[],m(a,n,"tests/playwright-fixtures/**/*.ts"),m(a,n,"tests/playwright-fixtures/**/*.tsx"),m(a,n,"tests/playwright-fixtures/**/*.mts"),m(a,n,".next/types/**/*.ts"),m(a,n,".next/dev/types/**/*.ts"),m(a,e,".next-testkit/**/dist/types/**/*.ts"),m(a,e,".next-testkit/**/dist/dev/types/**/*.ts")]:[],exclude:["node_modules",".next/cache",".next/dev"]};return l.writeFileSync(a,`${JSON.stringify(g,null,2)}
3
- `),a}function q(e,n){const t=new Map,o=new Map;for(const s of n){const r=i.resolve(e,s.path),c=[s.engineId,r].join("\0");o.set(c,{...s,path:r})}for(const s of o.values()){const r=s.path,c=s.engineId==="playwright"?T(i.dirname(r),e,["tsconfig.playwright.json"]):null,a=c??T(i.dirname(r),e),u=a?i.dirname(a):e,d=V(e,u),g=`${s.engineId}\0${a??""}\0${d}`,p=t.get(g);if(p){p.files.push(r);continue}t.set(g,{cwd:u,engineId:s.engineId,extendsPath:a,files:[r,...c?B(c):[]],scopeName:d})}return[...t.values()].map(s=>({...s,files:[...new Set(s.files)].sort((r,c)=>r.localeCompare(c))})).sort((s,r)=>P(s.engineId)-P(r.engineId)||s.scopeName.localeCompare(r.scopeName))}function B(e){const n=v(),t=s=>{throw new Error(`${e}: ${n.flattenDiagnosticMessageText(s.messageText,`
4
- `)}`)},o=n.getParsedCommandLineOfConfigFile(e,{},{...n.sys,onUnRecoverableConfigFileDiagnostic:t});for(const s of o?.errors??[])s.code!==18002&&s.code!==18003&&t(s);return o?.fileNames??[]}function H(e){return e==="playwright"?["ES2022","DOM","DOM.Iterable"]:["ES2022"]}function P(e){return["node-vitest","playwright"].indexOf(e)}function W(e,n){return n==="repo"?e:`${e}:${n}`}function V(e,n){const t=i.relative(e,n);return t===""?"repo":t.split(i.sep).join("/")}function Y(e){const n=e.replace(/[^a-zA-Z0-9_-]+/g,"-");if(n===e)return e;const t=C("sha256").update(e).digest("hex").slice(0,12);return`${n}-${t}`}function Q({label:e,cwd:n,tsconfigPath:t},o,s){const r=Z(n);return U({args:[...r.args,"--noEmit","-p",t],cwd:n,displayLabel:`Testkit typecheck ${e}`,env:process.env,executable:r.command,signal:s,timeoutMs:o}).then(c=>{const a=G(`Testkit typecheck ${e}`,c);if(a)throw a;return{label:e,tsconfigPath:t,ok:c.exitCode===0,exitCode:c.exitCode,stdout:c.stdout,stderr:c.stderr}})}function w(e){const n=e??L;if(!Number.isSafeInteger(n)||n<=0)throw new Error("Testkit typecheck timeout must be a positive safe integer in milliseconds");return n}function Z(e){let n=e;for(;;){const o=i.join(n,"node_modules","typescript","bin","tsc");if(l.existsSync(o))return{command:process.execPath,args:[o]};const s=i.dirname(n);if(s===n)break;n=s}const t=i.join(y,"node_modules","typescript","bin","tsc");if(l.existsSync(t))return{command:process.execPath,args:[t]};throw new Error(`TypeScript compiler not found from ${e} upward`)}function E(e,n=["tsconfig.json","tsconfig.build.json"]){for(const t of n){const o=i.join(e,t);if(l.existsSync(o))return o}return null}function T(e,n,t){const o=i.resolve(n);let s=i.resolve(e);for(;;){if(!b(o,s))return null;const r=E(s,t);if(r)return r;if(s===o)return null;const c=i.dirname(s);if(c===s)return null;s=c}}function f(e,n){const t=i.relative(i.dirname(e),n).split(i.sep).join("/");return t.startsWith("../")||i.isAbsolute(t)?t:`./${t}`}function m(e,n,t){return i.join(f(e,n),t).split(i.sep).join("/")}function X(e){const n={};for(const[t,o]of Object.entries(j("@gfdelarue/testkit",y)))!k(o)||typeof o.types!="string"||(n[`@gfdelarue/testkit${t.slice(1)}`]=[f(e,i.join(y,o.types))]);return n}const ee=Object.freeze({packages:Object.freeze(A.filter(({authoringResolution:e})=>e==="package-exports").map(({packageName:e})=>Object.freeze({name:e}))),supportedExports:"exact-manifest-exports"}),te=Object.freeze({packages:Object.freeze(N.map(({packageName:e})=>Object.freeze({name:e}))),supportedExports:"exact-manifest-exports"});function ne(e,n){const t=oe(e);if(t===null)return{};const o={},s=f(n,i.join(y,"dist","app","typecheck","unavailable.d.ts"));for(const r of t.packages){const c=se(r.name),a=j(r.name,c);o[`${r.name}/*`]=[s];for(const u of Object.keys(a).sort()){if(u!=="."&&!u.startsWith("./")||u.includes("*"))continue;const d=u==="."?r.name:`${r.name}${u.slice(1)}`,g=ie(d,r.name,c);o[d]=[g===null?s:f(n,g)]}}return o}function oe(e){switch(e){case"node-vitest":return ee;case"playwright":return te;case void 0:return null}}function se(e){const n=re(e);let t;try{t=x.resolve(`${e}/package.json`)}catch(r){throw new Error(`Testkit typecheck requires managed public package ${e}`,{cause:r})}const o=l.realpathSync.native(i.dirname(t)),s=JSON.parse(l.readFileSync(i.join(o,"package.json"),"utf8"));return requireManagedPublicPackageIdentity(s,e,n),o}export function requireManagedPublicPackageIdentity(e,n,t){if(!k(e)||e.name!==n||e.version!==t)throw new Error(`Testkit managed public package has invalid identity: expected ${n}@${t}`)}function re(e){const n=JSON.parse(l.readFileSync(i.join(y,"package.json"),"utf8"));if(!k(n)||!k(n.dependencies))throw new Error("Testkit package has invalid dependency metadata");const t=n.dependencies[e];if(typeof t!="string"||!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u.test(t))throw new Error(`Testkit managed public package ${e} must be an exact root dependency`);return t}function j(e,n){const t=JSON.parse(l.readFileSync(i.join(n,"package.json"),"utf8"));if(typeof t!="object"||t===null||Array.isArray(t)||!("name"in t)||t.name!==e||!("exports"in t)||typeof t.exports!="object"||t.exports===null||Array.isArray(t.exports))throw new Error(`Testkit managed public package has invalid exports: ${e}`);return t.exports}function ie(e,n,t){const o=v(),s=o.resolveModuleName(e,i.join(y,"__testkit_managed_public_types__.ts"),{module:o.ModuleKind.ESNext,moduleResolution:o.ModuleResolutionKind.Bundler,resolveJsonModule:!0,target:o.ScriptTarget.ES2022},o.sys).resolvedModule;if(s===void 0)return null;const r=l.realpathSync.native(s.resolvedFileName);if(!b(t,r))throw new Error(`Managed public package type ${e} resolved outside ${n}`);return r}export function buildTypecheckCompilerOptions({engineId:e,tsconfigPath:n,extendsPath:t,rootDir:o,extraPaths:s={},libs:r,types:c}){const u={...t?pe({tsconfigPath:n,extendsPath:t}):{},...s,...X(n),...ne(e,n)};return{baseUrl:null,lib:[...r],module:"ESNext",moduleResolution:"Bundler",noEmit:!0,...o?{rootDir:o}:{},target:"ES2022",typeRoots:ce(c,n),types:[...c],paths:u}}function ce(e,n){const t=new Set;for(const o of e){const s=ae(o);let r;try{r=x.resolve(`${s}/package.json`)}catch(a){throw new Error(`Testkit typecheck requires installed type package ${s}`,{cause:a})}const c=i.dirname(r);t.add(i.dirname(c))}return[...t].map(o=>f(n,o))}function ae(e){return e==="node"?`@types/${e}`:e}function pe({tsconfigPath:e,extendsPath:n}){const t=v(),o=t.getParsedCommandLineOfConfigFile(n,{},{...t.sys,onUnRecoverableConfigFileDiagnostic:()=>{}}),s=o?.options.paths;if(!s||Object.keys(s).length===0)return{};const r=o.options.baseUrl||(typeof o.options.pathsBasePath=="string"?o.options.pathsBasePath:i.dirname(n)),c={};for(const[a,u]of Object.entries(s))c[a]=u.map(d=>f(e,i.resolve(r,d)));return c}export function nextRuntimeTypePaths({tsconfigPath:e,serviceDir:n}){const t=ue(n,[i.join("next","types.d.ts"),i.join("next","types.js")]);if(!t)return{};const o=f(e,t);return{"next/types":[o],"next/types.js":[o]}}function ue(e,n){let t=i.resolve(e);for(;;){for(const s of n){const r=i.join(t,"node_modules",s);if(l.existsSync(r))return r}const o=i.dirname(t);if(o===t)return null;t=o}}
1
+ import{attachErrorDiagnostics as F}from"../../kernel/error-serialization.js";import{isPathWithin as b}from"../../process/files/paths.js";import{resolveProductDir as _}from"../../process/files/product-dir.js";import f from"fs";import i from"path";import{createHash as M}from"crypto";import{createRequire as O}from"module";import{fileURLToPath as A}from"url";import{resolveVitestSelection as R}from"../../engines/catalog.js";import{NODE_VITEST_PACKAGE_REQUIREMENTS as I}from"../../engines/installations/package-requirements.js";import{PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS as N}from"../../engines/installations/package-requirements.js";import{hasDiscoveryErrors as D,buildDiscoveryErrorFromDiagnostics as G,detectNextApp as L,loadDiscoveredConfigContext as U}from"../../config/loader/index.js";import{managedHostProcessInfrastructureError as J,runManagedHostProcess as z}from"../../process/index.js";import{findNearestPlaywrightConfigFile as B}from"../../engines/playwright/runtime/config-file.js";import{isUnknownRecord as x}from"../../kernel/unknown-values.js";const j=/\.[cm]?tsx?$/u,K=600*1e3,k=i.resolve(i.dirname(A(import.meta.url)),"..","..",".."),v=O(i.join(k,"package.json")),P=()=>v("typescript");export class TestkitTypecheckError extends Error{result;results;constructor(t,n,s){super(`testkit typecheck failed for ${t}`),this.result=n,this.results=s,F(this,{result:n,results:s})}}export async function runTestkitTypecheck(e={}){T(e.timeoutMs);const t=_(process.cwd(),e.dir),n=R(e.vitest??{},t),{context:s,discovery:o}=await U({dir:t,group:e.group,vitest:n});return runTestkitTypecheckForContext(s,o,e)}export async function runTestkitTypecheckForContext(e,t,n={}){const s=T(n.timeoutMs);if(D(e.discovery.diagnostics))throw G(e.discovery.diagnostics);const o=e.productDir,r=i.join(o,".testkit","_typecheck");f.mkdirSync(r,{recursive:!0});const c=[];if(e.configFile){const p=q({productDir:o,configFile:e.configFile,outputDir:r});c.push({label:"config",cwd:o,tsconfigPath:p})}const u=Y(e),l=t.files.filter(p=>j.test(p.path)).flatMap(p=>(u.get(p.path)??[[]]).map(g=>({engineId:p.engineId,path:p.path,setupFiles:g}))),a=new Set(t.files.filter(p=>p.engineId==="playwright").map(p=>p.group));for(const p of e.groups){if(!a.has(p.name))continue;const g=B(o,p.roots);g&&l.push({engineId:"playwright",path:g,setupFiles:[]})}const m=W(o,l);for(const p of m){const g=H({...p,outputDir:r,productDir:o});c.push({label:Z(p,o),cwd:p.cwd,tsconfigPath:g})}const y=[];for(const p of c){const g=await te(p,s,n.signal);if(y.push(g),!g.ok)throw new TestkitTypecheckError(p.label,g,y)}return{ok:!0,productDir:o,results:y}}function q({productDir:e,configFile:t,outputDir:n}){const s=i.join(n,"config.tsconfig.json"),o=S(e),r={...o?{extends:d(s,o)}:{},compilerOptions:buildTypecheckCompilerOptions({tsconfigPath:s,extendsPath:o,libs:["ES2022"],rootDir:d(s,e),types:["node"]}),files:[d(s,t)],include:[],exclude:[h(s,e,"node_modules"),h(s,e,"dist"),h(s,e,".testkit")]};return f.writeFileSync(s,`${JSON.stringify(r,null,2)}
2
+ `),s}function H({productDir:e,cwd:t,engineId:n,extendsPath:s,files:o,outputDir:r,scopeName:c,setupFiles:u}){const l=u.length===0?"":`.setup-${w(u)}`,a=i.join(r,`${n}.${ee(c)}${l}.tsconfig.json`),m=n==="playwright",y=m&&L(t),p={...s?{extends:d(a,s)}:{},compilerOptions:{...buildTypecheckCompilerOptions({engineId:n,tsconfigPath:a,extendsPath:s,libs:Q(n,s),...y?{extraPaths:nextRuntimeTypePaths({tsconfigPath:a,serviceDir:t})}:{},types:["node"]}),...m?{allowJs:!0,checkJs:!1}:{}},files:o.map(g=>d(a,g)),include:y?[...f.existsSync(i.join(t,"next-env.d.ts"))?[d(a,i.join(t,"next-env.d.ts"))]:[],h(a,t,"tests/playwright-fixtures/**/*.ts"),h(a,t,"tests/playwright-fixtures/**/*.tsx"),h(a,t,"tests/playwright-fixtures/**/*.mts"),h(a,t,".next/types/**/*.ts"),h(a,t,".next/dev/types/**/*.ts"),h(a,e,".next-testkit/**/dist/types/**/*.ts"),h(a,e,".next-testkit/**/dist/dev/types/**/*.ts")]:[],exclude:["node_modules",".next/cache",".next/dev"]};return f.writeFileSync(a,`${JSON.stringify(p,null,2)}
3
+ `),a}function W(e,t){const n=new Map,s=new Map;for(const o of t){const r=i.resolve(e,o.path),c=[o.engineId,r,...o.setupFiles].join("\0");s.set(c,{...o,path:r})}for(const o of s.values()){const r=o.path,c=o.engineId==="playwright"?C(i.dirname(r),e,["tsconfig.playwright.json"]):null,u=c??C(i.dirname(r),e),l=u?i.dirname(u):e,a=X(e,l),m=[o.engineId,u??"",a,...o.setupFiles].join("\0"),y=n.get(m);if(y){y.files.push(r);continue}n.set(m,{cwd:l,engineId:o.engineId,extendsPath:u,files:[r,...o.setupFiles,...c?V(c):[]],scopeName:a,setupFiles:o.setupFiles})}return[...n.values()].map(o=>({...o,files:[...new Set(o.files)].sort((r,c)=>r.localeCompare(c))})).sort((o,r)=>E(o.engineId)-E(r.engineId)||o.scopeName.localeCompare(r.scopeName)||o.setupFiles.join("\0").localeCompare(r.setupFiles.join("\0")))}function Y(e){const t=new Map;for(const{file:n,setupFiles:s}of e.plainFiles){const o=[...new Set(s.filter(c=>j.test(c)))].sort((c,u)=>c.localeCompare(u)),r=t.get(n)??[];r.some(c=>c.join("\0")===o.join("\0"))||r.push(o),t.set(n,r)}return t}function V(e){const t=P(),n=o=>{throw new Error(`${e}: ${t.flattenDiagnosticMessageText(o.messageText,`
4
+ `)}`)},s=t.getParsedCommandLineOfConfigFile(e,{},{...t.sys,onUnRecoverableConfigFileDiagnostic:n});for(const o of s?.errors??[])o.code!==18002&&o.code!==18003&&n(o);return s?.fileNames??[]}function Q(e,t){return e==="playwright"?["ES2022","DOM","DOM.Iterable"]:t?void 0:["ES2022"]}function E(e){return["node-vitest","playwright"].indexOf(e)}function Z({engineId:e,scopeName:t,setupFiles:n},s){const o=t==="repo"?e:`${e}:${t}`;if(n.length===0)return o;const r=n.map(c=>i.relative(s,c).split(i.sep).join("/"));return`${o} with ${r.join(", ")}`}function X(e,t){const n=i.relative(e,t);return n===""?"repo":n.split(i.sep).join("/")}function ee(e){const t=e.replace(/[^a-zA-Z0-9_-]+/g,"-");return t===e?e:`${t}-${w([e])}`}function w(e){return M("sha256").update(e.join("\0")).digest("hex").slice(0,12)}function te({label:e,cwd:t,tsconfigPath:n},s,o){const r=ne(t);return z({args:[...r.args,"--noEmit","-p",n],cwd:t,displayLabel:`Testkit typecheck ${e}`,env:process.env,executable:r.command,signal:o,timeoutMs:s}).then(c=>{const u=J(`Testkit typecheck ${e}`,c);if(u)throw u;return{label:e,tsconfigPath:n,ok:c.exitCode===0,exitCode:c.exitCode,stdout:c.stdout,stderr:c.stderr}})}function T(e){const t=e??K;if(!Number.isSafeInteger(t)||t<=0)throw new Error("Testkit typecheck timeout must be a positive safe integer in milliseconds");return t}function ne(e){let t=e;for(;;){const s=i.join(t,"node_modules","typescript","bin","tsc");if(f.existsSync(s))return{command:process.execPath,args:[s]};const o=i.dirname(t);if(o===t)break;t=o}const n=i.join(k,"node_modules","typescript","bin","tsc");if(f.existsSync(n))return{command:process.execPath,args:[n]};throw new Error(`TypeScript compiler not found from ${e} upward`)}function S(e,t=["tsconfig.json","tsconfig.build.json"]){for(const n of t){const s=i.join(e,n);if(f.existsSync(s))return s}return null}function C(e,t,n){const s=i.resolve(t);let o=i.resolve(e);for(;;){if(!b(s,o))return null;const r=S(o,n);if(r)return r;if(o===s)return null;const c=i.dirname(o);if(c===o)return null;o=c}}function d(e,t){const n=i.relative(i.dirname(e),t).split(i.sep).join("/");return n.startsWith("../")||i.isAbsolute(n)?n:`./${n}`}function h(e,t,n){return i.join(d(e,t),n).split(i.sep).join("/")}function oe(e){const t={};for(const[n,s]of Object.entries($("@gfdelarue/testkit",k)))!x(s)||typeof s.types!="string"||(t[`@gfdelarue/testkit${n.slice(1)}`]=[d(e,i.join(k,s.types))]);return t}const se=Object.freeze({packages:Object.freeze(I.filter(({authoringResolution:e})=>e==="package-exports").map(({packageName:e})=>Object.freeze({name:e}))),supportedExports:"exact-manifest-exports"}),re=Object.freeze({packages:Object.freeze(N.map(({packageName:e})=>Object.freeze({name:e}))),supportedExports:"exact-manifest-exports"});function ie(e,t){const n=ce(e);if(n===null)return{};const s={},o=d(t,i.join(k,"dist","app","typecheck","unavailable.d.ts"));for(const r of n.packages){const c=ae(r.name),u=$(r.name,c);s[`${r.name}/*`]=[o];for(const l of Object.keys(u).sort()){if(l!=="."&&!l.startsWith("./")||l.includes("*"))continue;const a=l==="."?r.name:`${r.name}${l.slice(1)}`,m=ue(a,r.name,c);s[a]=[m===null?o:d(t,m)]}}return s}function ce(e){switch(e){case"node-vitest":return se;case"playwright":return re;case void 0:return null}}function ae(e){const t=pe(e);let n;try{n=v.resolve(`${e}/package.json`)}catch(r){throw new Error(`Testkit typecheck requires managed public package ${e}`,{cause:r})}const s=f.realpathSync.native(i.dirname(n)),o=JSON.parse(f.readFileSync(i.join(s,"package.json"),"utf8"));return requireManagedPublicPackageIdentity(o,e,t),s}export function requireManagedPublicPackageIdentity(e,t,n){if(!x(e)||e.name!==t||e.version!==n)throw new Error(`Testkit managed public package has invalid identity: expected ${t}@${n}`)}function pe(e){const t=JSON.parse(f.readFileSync(i.join(k,"package.json"),"utf8"));if(!x(t)||!x(t.dependencies))throw new Error("Testkit package has invalid dependency metadata");const n=t.dependencies[e];if(typeof n!="string"||!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u.test(n))throw new Error(`Testkit managed public package ${e} must be an exact root dependency`);return n}function $(e,t){const n=JSON.parse(f.readFileSync(i.join(t,"package.json"),"utf8"));if(typeof n!="object"||n===null||Array.isArray(n)||!("name"in n)||n.name!==e||!("exports"in n)||typeof n.exports!="object"||n.exports===null||Array.isArray(n.exports))throw new Error(`Testkit managed public package has invalid exports: ${e}`);return n.exports}function ue(e,t,n){const s=P(),o=s.resolveModuleName(e,i.join(k,"__testkit_managed_public_types__.ts"),{module:s.ModuleKind.ESNext,moduleResolution:s.ModuleResolutionKind.Bundler,resolveJsonModule:!0,target:s.ScriptTarget.ES2022},s.sys).resolvedModule;if(o===void 0)return null;const r=f.realpathSync.native(o.resolvedFileName);if(!b(n,r))throw new Error(`Managed public package type ${e} resolved outside ${t}`);return r}export function buildTypecheckCompilerOptions({engineId:e,tsconfigPath:t,extendsPath:n,rootDir:s,extraPaths:o={},libs:r,types:c}){const l={...n?de({tsconfigPath:t,extendsPath:n}):{},...o,...oe(t),...ie(e,t)};return{baseUrl:null,...r?{lib:[...r]}:{},module:"ESNext",moduleResolution:"Bundler",noEmit:!0,...s?{rootDir:s}:{},target:"ES2022",typeRoots:le(c,t),types:[...c],paths:l}}function le(e,t){const n=new Set;for(const s of e){const o=fe(s);let r;try{r=v.resolve(`${o}/package.json`)}catch(u){throw new Error(`Testkit typecheck requires installed type package ${o}`,{cause:u})}const c=i.dirname(r);n.add(i.dirname(c))}return[...n].map(s=>d(t,s))}function fe(e){return e==="node"?`@types/${e}`:e}function de({tsconfigPath:e,extendsPath:t}){const n=P(),s=n.getParsedCommandLineOfConfigFile(t,{},{...n.sys,onUnRecoverableConfigFileDiagnostic:()=>{}}),o=s?.options.paths;if(!o||Object.keys(o).length===0)return{};const r=s.options.baseUrl||(typeof s.options.pathsBasePath=="string"?s.options.pathsBasePath:i.dirname(t)),c={};for(const[u,l]of Object.entries(o))c[u]=l.map(a=>d(e,i.resolve(r,a)));return c}export function nextRuntimeTypePaths({tsconfigPath:e,serviceDir:t}){const n=ge(t,[i.join("next","types.d.ts"),i.join("next","types.js")]);if(!n)return{};const s=d(e,n);return{"next/types":[s],"next/types.js":[s]}}function ge(e,t){let n=i.resolve(e);for(;;){for(const o of t){const r=i.join(n,"node_modules",o);if(f.existsSync(r))return r}const s=i.dirname(n);if(s===n)return null;n=s}}
@@ -1 +1 @@
1
- import{Args as i,Flags as e}from"./framework/definitions.js";import{defineCommand as t}from"./framework/command.js";import{runArgs as n,runFlags as o,sharedFlags as r,suppliedEnvironmentFlags as l,testSelectionFlags as a,vitestSelectionFlags as s}from"./command-flags.js";import{publicTestTypeListText as u}from"../domain/test-types.js";export const commandCatalog=Object.freeze({artifacts:t({summary:"List, verify, or inspect artifacts from immutable Testkit runs",enableJsonFlag:!0,args:{file:i.string({description:"Optional test file selector",required:!1})},flags:{...a,kind:e.string({description:"Limit artifacts to one kind"}),format:e.string({description:"Output format",options:["list","text"],default:"list"}),run:e.string({description:"Read one immutable run ID instead of latest"}),list:e.boolean({description:"List retained immutable runs",default:!1}),verify:e.boolean({description:"Verify the selected run manifest and checksums",default:!1})}}),"bug file":t({summary:"Run a recorded bug's test and file the bug as an issue",enableJsonFlag:!0,args:{id:i.string({description:"Draft id that `testkit bug record` printed",required:!0})},flags:{dir:e.string({description:"Product directory"}),...l,...s}}),"bug guide":t({summary:"Print the bug record format, the severities, and the category lists",enableJsonFlag:!0}),"bug record":t({summary:"Record a confirmed bug as a local draft",enableJsonFlag:!0,args:{file:i.string({description:"Bug record JSON file, or - to read standard input",required:!0})},flags:{dir:e.string({description:"Product directory"}),...s}}),"campaign finish":t({summary:"Finish the active campaign and write its pull request summary",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"})}}),"campaign start":t({summary:"Start a bug-hunting campaign and print the agent's brief",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"}),id:e.string({description:"Campaign id, instead of one made from the target and the date"}),target:e.string({description:"What the agent should hunt, in one line of at most 200 characters",required:!0})}}),"campaign status":t({summary:"Show the active campaign, its recorded bugs, and the area map coverage",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"})}}),"ci report":t({summary:"Post the last run as a commit status, a step summary, and one pull request comment",enableJsonFlag:!0,flags:{context:e.string({description:"Commit status context, instead of testkit"}),dir:e.string({description:"Product directory"})}}),cleanup:t({summary:"Clean stale local testkit state",enableJsonFlag:!0,flags:{...r,"dry-run":e.boolean({description:"Show cleanup actions without deleting state",default:!1}),cache:e.string({description:"Clean cache state: runtime, bundles, or all",multiple:!0,options:["runtime","bundles","all"]}),resources:e.boolean({description:"Clean Testkit-owned Docker resources that are stale or orphaned",default:!1})}}),"db schema refresh":t({summary:"Refresh a source database schema cache",enableJsonFlag:!0,flags:r}),"db schema verify":t({summary:"Verify local schema replay against the source database schema",enableJsonFlag:!0,flags:{...r,"skip-schema-source-verify":e.boolean({description:"Skip the check that local schema replay matches the source database schema",default:!1})}}),destroy:t({summary:"Destroy local testkit state",enableJsonFlag:!0,flags:r}),discover:t({summary:"Discover managed tests and report their metadata",enableJsonFlag:!0,flags:{...a,...s,type:e.string({char:"t",multiple:!0,description:`Filter by suite type(s): ${u({includeAll:!0})}`}),suite:e.string({char:"s",multiple:!0,description:"Filter by suite selector(s)"}),file:e.string({char:"f",multiple:!0,description:"Filter by exact file path(s)"}),"runnable-only":e.boolean({description:"Show only files not skipped by repo rules",default:!1}),strict:e.boolean({description:"Fail instead of reporting discovery/config diagnostics",default:!1}),output:e.string({description:"Write machine-readable discovery JSON to a file"}),"output-mode":e.string({description:"Human-readable output mode",options:["compact","verbose"],default:"compact"})}}),doctor:t({summary:"Run built-in config, discovery, and hygiene checks",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"}),typecheck:e.boolean({description:"Include generated TypeScript checks",default:!0,allowNo:!0})}}),"guard unsafe-entrypoint":t({summary:"Fail a local script that must be run through Testkit",flags:{command:e.string({char:"c",description:"Disabled command name shown in the error message",required:!0}),use:e.string({char:"u",description:"Replacement command shown in the error message",required:!0})}}),lint:t({summary:"Run built-in Testkit repository hygiene checks",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"})}}),"report prepare":t({summary:"Prepare a local report with optional template, bug records, and selected run evidence",enableJsonFlag:!0,args:{directory:i.string({description:"New bundle directory",required:!0})},flags:{dir:e.string({description:"Product directory containing bug records and runs"}),template:e.string({description:"Copy this file unchanged to report.md"}),instructions:e.string({description:"Print this repository-owned drafting guide for the author"}),bug:e.string({description:"Include this recorded bug ID as context",multiple:!0}),run:e.string({description:"Immutable run ID containing the selected artifacts"}),artifact:e.string({description:"Exact artifact ref.path from testkit artifacts --json",multiple:!0})}}),"report publish":t({summary:"Publish a prepared directory at one Git revision without changing your checkout",enableJsonFlag:!0,args:{directory:i.string({description:"Directory containing only the files to publish",required:!0})},flags:{dir:e.string({description:"Product directory used to resolve provider credentials"}),repository:e.string({description:"Destination GitHub or Gitea repository URL, or owner/name",required:!0}),branch:e.string({description:"Destination branch",required:!0}),path:e.string({description:"Bundle directory within the destination repository",required:!0}),message:e.string({description:"Publication commit message"})}}),"run status":t({summary:"Show active Testkit run progress",enableJsonFlag:!0,flags:{...r,run:e.string({description:"Specific run id to show"}),full:e.boolean({description:"Include the full live status payload in JSON output"})}}),"run stop":t({summary:"Stop active Testkit run work",enableJsonFlag:!0,flags:{...r,run:e.string({description:"Specific run id to stop; defaults to the newest active run"}),all:e.boolean({description:"Stop all active runs for this product",default:!1}),reason:e.string({description:"Operator-visible reason recorded with cancelled runs and dirty slots"})}}),run:t({summary:"Run test suites",enableJsonFlag:!0,args:n,flags:o}),"setup playwright":t({summary:"Install the managed Playwright Chromium runtime",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"}),force:e.boolean({default:!1,description:"Force Playwright to repair the browser installation"}),"with-deps":e.boolean({default:!1,description:"Install required host dependencies with Chromium"})}}),status:t({summary:"Show local testkit state",enableJsonFlag:!0,flags:r}),stop:t({summary:"Stop all Testkit-owned runs",enableJsonFlag:!0,flags:{...r,reason:e.string({description:"Operator-visible reason recorded with cancelled runs"})}}),typecheck:t({summary:"Typecheck testkit config, helpers, and suites",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"}),...s}}),workspace:t({summary:"Inspect Testkit workstation data for a product",enableJsonFlag:!0,flags:{...a,"target-limit":e.integer({description:"Maximum number of quick-run target previews",default:24}),"no-status":e.boolean({description:"Skip runtime status collection",default:!1})}})});
1
+ import{Args as i,Flags as e}from"./framework/definitions.js";import{defineCommand as t}from"./framework/command.js";import{runArgs as n,runFlags as o,sharedFlags as r,suppliedEnvironmentFlags as l,testSelectionFlags as s,vitestSelectionFlags as a}from"./command-flags.js";import{publicTestTypeListText as u}from"../domain/test-types.js";export const commandCatalog=Object.freeze({artifacts:t({summary:"List, verify, or inspect artifacts from immutable Testkit runs",enableJsonFlag:!0,args:{file:i.string({description:"Optional test file selector",required:!1})},flags:{...s,kind:e.string({description:"Limit artifacts to one kind"}),format:e.string({description:"Output format",options:["list","text"],default:"list"}),run:e.string({description:"Read one immutable run ID instead of latest"}),list:e.boolean({description:"List retained immutable runs",default:!1}),verify:e.boolean({description:"Verify the selected run manifest and checksums",default:!1})}}),"bug file":t({summary:"Run a recorded bug's test and file the bug as an issue",enableJsonFlag:!0,args:{id:i.string({description:"Draft id that `testkit bug record` printed",required:!0})},flags:{dir:e.string({description:"Product directory"}),...l,...a}}),"bug guide":t({summary:"Print the bug record format, the severities, and the category lists",enableJsonFlag:!0}),"bug record":t({summary:"Record a confirmed bug as a local draft",enableJsonFlag:!0,args:{file:i.string({description:"Bug record JSON file, or - to read standard input",required:!0})},flags:{dir:e.string({description:"Product directory"}),...a}}),"campaign finish":t({summary:"Finish the active campaign and write its pull request summary",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"})}}),"campaign start":t({summary:"Start a bug-hunting campaign and print the agent's brief",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"}),id:e.string({description:"Campaign id, instead of one made from the target and the date"}),target:e.string({description:"What the agent should hunt, in one line of at most 200 characters",required:!0})}}),"campaign status":t({summary:"Show the active campaign, its recorded bugs, and the area map coverage",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"})}}),"ci report":t({summary:"Post the last run as a commit status, a step summary, and one pull request comment",enableJsonFlag:!0,flags:{context:e.string({description:"Commit status context, instead of testkit"}),dir:e.string({description:"Product directory"})}}),cleanup:t({summary:"Clean stale local testkit state",enableJsonFlag:!0,flags:{...r,"dry-run":e.boolean({description:"Show cleanup actions without deleting state",default:!1}),cache:e.string({description:"Clean cache state: runtime, bundles, or all",multiple:!0,options:["runtime","bundles","all"]}),resources:e.boolean({description:"Clean Testkit-owned Docker resources that are stale or orphaned",default:!1})}}),"db schema refresh":t({summary:"Refresh a source database schema cache",enableJsonFlag:!0,flags:r}),"db schema verify":t({summary:"Verify local schema replay against the source database schema",enableJsonFlag:!0,flags:{...r,"skip-schema-source-verify":e.boolean({description:"Skip the check that local schema replay matches the source database schema",default:!1})}}),destroy:t({summary:"Remove runtime state, databases, and Docker resources; run results and other .testkit files stay",enableJsonFlag:!0,flags:r}),discover:t({summary:"Discover managed tests and report their metadata",enableJsonFlag:!0,flags:{...s,...a,type:e.string({char:"t",multiple:!0,description:`Filter by suite type(s): ${u({includeAll:!0})}`}),suite:e.string({char:"s",multiple:!0,description:"Filter by suite selector(s)"}),file:e.string({char:"f",multiple:!0,description:"Filter by exact file path(s)"}),"runnable-only":e.boolean({description:"Show only files not skipped by repo rules",default:!1}),strict:e.boolean({description:"Fail instead of reporting discovery/config diagnostics",default:!1}),output:e.string({description:"Write machine-readable discovery JSON to a file"}),"output-mode":e.string({description:"Human-readable output mode",options:["compact","verbose"],default:"compact"})}}),doctor:t({summary:"Run built-in config, discovery, and hygiene checks",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"}),typecheck:e.boolean({description:"Include generated TypeScript checks",default:!0,allowNo:!0})}}),"guard unsafe-entrypoint":t({summary:"Fail a local script that must be run through Testkit",flags:{command:e.string({char:"c",description:"Disabled command name shown in the error message",required:!0}),use:e.string({char:"u",description:"Replacement command shown in the error message",required:!0})}}),lint:t({summary:"Run built-in Testkit repository hygiene checks",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"})}}),"report prepare":t({summary:"Prepare a local report with optional template, bug records, and selected run evidence",enableJsonFlag:!0,args:{directory:i.string({description:"New bundle directory",required:!0})},flags:{dir:e.string({description:"Product directory containing bug records and runs"}),template:e.string({description:"Copy this file unchanged to report.md"}),instructions:e.string({description:"Print this repository-owned drafting guide for the author"}),bug:e.string({description:"Include this recorded bug ID as context",multiple:!0}),run:e.string({description:"Immutable run ID containing the selected artifacts"}),artifact:e.string({description:"Exact artifact ref.path from testkit artifacts --json",multiple:!0})}}),"report publish":t({summary:"Publish a prepared directory at one Git revision without changing your checkout",enableJsonFlag:!0,args:{directory:i.string({description:"Directory containing only the files to publish",required:!0})},flags:{dir:e.string({description:"Product directory used to resolve provider credentials"}),repository:e.string({description:"Destination GitHub or Gitea repository URL, or owner/name",required:!0}),branch:e.string({description:"Destination branch",required:!0}),path:e.string({description:"Bundle directory within the destination repository",required:!0}),message:e.string({description:"Publication commit message"})}}),"run status":t({summary:"Show active Testkit run progress",enableJsonFlag:!0,flags:{...r,run:e.string({description:"Specific run id to show"}),full:e.boolean({description:"Include the full live status payload in JSON output"})}}),"run stop":t({summary:"Stop active Testkit run work",enableJsonFlag:!0,flags:{...r,run:e.string({description:"Specific run id to stop; defaults to the newest active run"}),all:e.boolean({description:"Stop all active runs for this product",default:!1}),reason:e.string({description:"Operator-visible reason recorded with cancelled runs and dirty slots"})}}),run:t({summary:"Run test suites",enableJsonFlag:!0,args:n,flags:o}),"setup playwright":t({summary:"Install the managed Playwright Chromium runtime",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"}),force:e.boolean({default:!1,description:"Force Playwright to repair the browser installation"}),"with-deps":e.boolean({default:!1,description:"Install required host dependencies with Chromium"})}}),status:t({summary:"Show local testkit state",enableJsonFlag:!0,flags:r}),stop:t({summary:"Stop all Testkit-owned runs",enableJsonFlag:!0,flags:{...r,reason:e.string({description:"Operator-visible reason recorded with cancelled runs"})}}),typecheck:t({summary:"Typecheck testkit config, helpers, and suites",enableJsonFlag:!0,flags:{dir:e.string({description:"Product directory"}),group:s.group,...a}}),workspace:t({summary:"Inspect Testkit workstation data for a product",enableJsonFlag:!0,flags:{...s,"target-limit":e.integer({description:"Maximum number of quick-run target previews",default:24}),"no-status":e.boolean({description:"Skip runtime status collection",default:!1})}})});
@@ -1 +1 @@
1
- import{RETIRED_TEST_TYPES as o,rejectRetiredTestType as p}from"../domain/retired-test-types.js";import{publicTestTypeList as c,publicTestTypeListText as n}from"../domain/test-types.js";import{CliUsageError as l}from"./framework/errors.js";import{Args as u,Flags as e}from"./framework/index.js";export const sharedFlags={dir:e.string({description:"Explicit product directory"}),service:e.string({description:"Limit the operation to one service"})},testSelectionFlags={dir:sharedFlags.dir,group:e.string({description:"Limit the operation to one test group"}),service:e.string({description:"Deprecated alias for --group"})};export function selectedGroup(s,i){const{group:r,service:t}=s;if(t===void 0)return r??null;if(r!==void 0&&r!==t)throw new l(`--group ${r} and --service ${t} select different groups; pass only --group`);return i(`--service selects a test group on this command and will be removed; use --group ${t}`),t}export const vitestSelectionFlags={"vitest-config":e.string({description:"Run plain test files with this Vitest config, relative to the product directory"}),"vitest-project":e.string({description:"Run plain test files from this Vitest project only"}),"vitest-runner":e.string({description:"Run plain test files with the repository's Vitest (repo) or Testkit's own (managed)",options:["repo","managed"]})},suppliedEnvironmentFlags={"base-url":e.string({description:"Supply the default endpoint, BASE_URL, instead of provisioning it"}),endpoint:e.string({multiple:!0,description:"Supply a named endpoint as NAME=URL"}),database:e.string({multiple:!0,description:"Supply a named PostgreSQL database as NAME=URL"}),env:e.string({multiple:!0,description:"Supply an environment value as NAME=VALUE"}),"env-from":e.string({multiple:!0,description:"Supply an environment value from a host variable as NAME=HOST_KEY"}),"environment-file":e.string({description:"Supply values, prepared setup data and handle descriptors from a version 1 environment file"})};export function runTypeArgument(s=o){return u.string({check:i=>{p(i,`Type "${i}"`,s)},description:`Optional suite type shortcut: ${n({includeAll:!0})}`,required:!1,options:c({includeAll:!0})})}export const runArgs={type:runTypeArgument()},runFlags={...testSelectionFlags,...suppliedEnvironmentFlags,...vitestSelectionFlags,type:e.string({char:"t",multiple:!0,description:`Run specific suite type(s): ${n({includeAll:!0})}`}),suite:e.string({char:"s",multiple:!0,description:"Run specific suite(s)"}),file:e.string({char:"f",multiple:!0,description:"Run specific file(s)"}),"task-concurrency":e.string({description:"Maximum number of concurrent test tasks for the whole run"}),workers:e.string({description:"Deprecated alias for --task-concurrency; removed in 0.3.0"}),"file-timeout-seconds":e.string({description:"Per-file wall-clock timeout in seconds"}),"allow-empty":e.boolean({description:"Permit a successful run when no runnable files execute",default:!1}),"ignore-skip-rules":e.boolean({description:"Run files even if testkit.config.ts marks them skipped",default:!1}),"skip-schema-source-verify":e.boolean({description:"Skip the check that local schema replay matches the source database schema",default:!1}),"output-mode":e.string({description:"Reporter mode",options:["compact","debug","events"]}),debug:e.boolean({description:"Alias for --output-mode debug",default:!1})};
1
+ import{RETIRED_TEST_TYPES as s,rejectRetiredTestType as n}from"../domain/retired-test-types.js";import{publicTestTypeList as o,publicTestTypeListText as r}from"../domain/test-types.js";import{CliUsageError as p}from"./framework/errors.js";import{Args as c,Flags as e}from"./framework/index.js";export const sharedFlags={dir:e.string({description:"Explicit product directory"}),service:e.string({description:"Limit the operation to one service"})},testSelectionFlags={dir:sharedFlags.dir,group:e.string({description:"Limit the operation to one test group"}),service:e.string({description:"Removed in 0.6.0; use --group"})};export function selectedGroup(t){if(t.service!==void 0)throw new p(`Testkit 0.6.0 removed --service from run, discover, artifacts, and workspace; use --group ${t.service}`);return t.group??null}export const vitestSelectionFlags={"vitest-config":e.string({description:"Run plain test files with this Vitest config, relative to the product directory"}),"vitest-project":e.string({description:"Run plain test files from this Vitest project only"}),"vitest-runner":e.string({description:"Run plain test files with the repository's Vitest (repo) or Testkit's own (managed)",options:["repo","managed"]})},suppliedEnvironmentFlags={"base-url":e.string({description:"Supply the default endpoint, BASE_URL, instead of provisioning it"}),endpoint:e.string({multiple:!0,description:"Supply a named endpoint as NAME=URL"}),database:e.string({multiple:!0,description:"Supply a named PostgreSQL database as NAME=URL"}),env:e.string({multiple:!0,description:"Supply an environment value as NAME=VALUE"}),"env-from":e.string({multiple:!0,description:"Supply an environment value from a host variable as NAME=HOST_KEY"}),"environment-file":e.string({description:"Supply values, prepared setup data and handle descriptors from a version 1 environment file"})};export function runTypeArgument(t=s){return c.string({check:i=>{n(i,`Type "${i}"`,t)},description:`Optional suite type shortcut: ${r({includeAll:!0})}`,required:!1,options:o({includeAll:!0})})}export const runArgs={type:runTypeArgument()},runFlags={...testSelectionFlags,...suppliedEnvironmentFlags,...vitestSelectionFlags,type:e.string({char:"t",multiple:!0,description:`Run specific suite type(s): ${r({includeAll:!0})}`}),suite:e.string({char:"s",multiple:!0,description:"Run specific suite(s)"}),file:e.string({char:"f",multiple:!0,description:"Run specific file(s)"}),"task-concurrency":e.string({description:"Maximum number of concurrent test tasks for the whole run"}),workers:e.string({description:"Deprecated alias for --task-concurrency"}),"file-timeout-seconds":e.string({description:"Per-file wall-clock timeout in seconds"}),"allow-empty":e.boolean({description:"Permit a successful run when no runnable files execute",default:!1}),"ignore-skip-rules":e.boolean({description:"Run files even if testkit.config.ts marks them skipped",default:!1}),"skip-schema-source-verify":e.boolean({description:"Skip the check that local schema replay matches the source database schema",default:!1}),"output-mode":e.string({description:"Reporter mode",options:["compact","debug","events"]}),debug:e.boolean({description:"Alias for --output-mode debug",default:!1})};
@@ -1,3 +1,3 @@
1
- import{asUnknownRecord as c}from"../../kernel/unknown-values.js";import d from"node:fs";import{inspectArtifacts as p}from"../../app/inspect/artifacts.js";import{selectedGroup as l}from"../command-flags.js";export default function m({args:i,flags:e,json:n,log:o,notice:s}){const r=p({dir:e.dir,mode:e.list?"runs":e.verify?"verify":"artifacts",file:i.file||null,runId:e.run||null,group:l(e,s),kind:e.kind,includePayload:n||e.format==="text"});if(r.mode==="runs"){const{runs:t}=r;if(n)return{ok:!0,runs:t};t.length===0&&o("No immutable Testkit runs found.");for(const u of t)o(`${u.runId} ${u.status||"unknown"} ${u.finishedAt||u.startedAt||"unknown-time"}`);return{ok:!0,count:t.length}}const a=r.runId;if(r.mode==="verify"){const{verification:t}=r;return t.ok||(process.exitCode=1),n?{ok:t.ok,verification:t}:(o(t.ok?`Verified ${a??"unknown"}: ${String(t.checkedFiles)} files (${t.manifestDigest??"unknown-digest"})`:`Integrity verification failed for ${a??"unknown"}: ${t.errors.join("; ")}`),{ok:t.ok,verification:t})}const{entries:f}=r;if(n)return{ok:!0,runId:a,artifacts:f.map(t=>({file:t.file.path,group:t.group.name,suite:{engineId:t.suite.engineId,name:t.suite.name,profileId:t.suite.profileId,testType:t.suite.testType},ref:t.artifactRef,payload:t.payload}))};if(e.format==="text")o(h(f));else for(const t of k(f))o(t);return{ok:!0,runId:a,count:f.length}}function k(i){if(i.length===0)return["No artifacts matched."];const e=[];for(const n of i)e.push(`${n.artifactRef.name}${n.artifactRef.kind?` [${n.artifactRef.kind}]`:""}`),n.artifactRef.summary&&e.push(` ${n.artifactRef.summary}`),e.push(` ${n.artifactRef.path}`);return e}function h(i){return i.length===0?"No artifacts matched.":i.map(e=>$(e)).join(`
1
+ import{asUnknownRecord as s}from"../../kernel/unknown-values.js";import d from"node:fs";import{inspectArtifacts as c}from"../../app/inspect/artifacts.js";import{selectedGroup as p}from"../command-flags.js";export default function l({args:i,flags:e,json:n,log:o}){const r=c({dir:e.dir,mode:e.list?"runs":e.verify?"verify":"artifacts",file:i.file||null,runId:e.run||null,group:p(e),kind:e.kind,includePayload:n||e.format==="text"});if(r.mode==="runs"){const{runs:t}=r;if(n)return{ok:!0,runs:t};t.length===0&&o("No immutable Testkit runs found.");for(const u of t)o(`${u.runId} ${u.status||"unknown"} ${u.finishedAt||u.startedAt||"unknown-time"}`);return{ok:!0,count:t.length}}const a=r.runId;if(r.mode==="verify"){const{verification:t}=r;return t.ok||(process.exitCode=1),n?{ok:t.ok,verification:t}:(o(t.ok?`Verified ${a??"unknown"}: ${String(t.checkedFiles)} files (${t.manifestDigest??"unknown-digest"})`:`Integrity verification failed for ${a??"unknown"}: ${t.errors.join("; ")}`),{ok:t.ok,verification:t})}const{entries:f}=r;if(n)return{ok:!0,runId:a,artifacts:f.map(t=>({file:t.file.path,group:t.group.name,suite:{engineId:t.suite.engineId,name:t.suite.name,profileId:t.suite.profileId,testType:t.suite.testType},ref:t.artifactRef,payload:t.payload}))};if(e.format==="text")o(k(f));else for(const t of m(f))o(t);return{ok:!0,runId:a,count:f.length}}function m(i){if(i.length===0)return["No artifacts matched."];const e=[];for(const n of i)e.push(`${n.artifactRef.name}${n.artifactRef.kind?` [${n.artifactRef.kind}]`:""}`),n.artifactRef.summary&&e.push(` ${n.artifactRef.summary}`),e.push(` ${n.artifactRef.path}`);return e}function k(i){return i.length===0?"No artifacts matched.":i.map(e=>h(e)).join(`
2
2
 
3
- `)}function $(i){if(typeof i.payload?.text=="string")return i.payload.text.trimEnd();const e=c(i.payload?.data);return typeof e?.text=="string"?e.text.trimEnd():i.artifactRef.contentType==="application/json"&&d.existsSync(i.absolutePath)?d.readFileSync(i.absolutePath,"utf8").trimEnd():JSON.stringify(i.payload?.data??i.payload??null,null,2)}
3
+ `)}function h(i){if(typeof i.payload?.text=="string")return i.payload.text.trimEnd();const e=s(i.payload?.data);return typeof e?.text=="string"?e.text.trimEnd():i.artifactRef.contentType==="application/json"&&d.existsSync(i.absolutePath)?d.readFileSync(i.absolutePath,"utf8").trimEnd():JSON.stringify(i.payload?.data??i.payload??null,null,2)}
@@ -1 +1 @@
1
- import{executeDiscoverOperation as n}from"../../app/discover/index.js";import{renderDiscoverResult as p}from"../renderers/discover/text.js";import{selectedGroup as c}from"../command-flags.js";export default async function d({flags:t,json:o,log:u,notice:e}){const r=await n({diagnostics:t.strict?"error":"report",dir:t.dir,file:t.file||[],group:c(t,e),notice:e,output:t.output,runnableOnly:t["runnable-only"],suite:t.suite||[],type:t.type||[],vitest:t},process.cwd());if(!o)for(const i of p(r,{outputMode:t["output-mode"]}))u(i);return r}
1
+ import{executeDiscoverOperation as i}from"../../app/discover/index.js";import{renderDiscoverResult as n}from"../renderers/discover/text.js";import{selectedGroup as p}from"../command-flags.js";export default async function c({flags:t,json:r,log:o}){const e=await i({diagnostics:t.strict?"error":"report",dir:t.dir,file:t.file||[],group:p(t),output:t.output,runnableOnly:t["runnable-only"],suite:t.suite||[],type:t.type||[],vitest:t},process.cwd());if(!r)for(const u of n(e,{outputMode:t["output-mode"]}))o(u);return e}
@@ -1,2 +1,2 @@
1
- export default function t({flags:e}){throw Object.assign(new Error(`${e.command} is disabled because DB-touching tests must run through the isolated testkit harness.
1
+ export default function t({flags:e}){throw Object.assign(new Error(`${e.command} is disabled because this repository runs its tests through Testkit.
2
2
  Use ${e.use} instead.`),{exitCode:1})}
@@ -1,2 +1,2 @@
1
- import{applyKnownFailures as m,loadBugPolicy as l}from"../../app/bugs/gate.js";import{buildRunRequest as a}from"../../app/run/request.js";import{selectedGroup as w}from"../command-flags.js";import{executeRunRequest as y}from"../operations/run/operation.js";import{renderKnownFailures as k}from"../renderers/bug/text.js";export default async function v({args:n,flags:e,json:u,log:p,notice:i,setExitCode:c}){const d=w(e,i),t=await a({dir:e.dir,group:d??void 0,taskConcurrency:e["task-concurrency"],workers:e.workers,fileTimeoutSeconds:e["file-timeout-seconds"],type:e.type,suite:e.suite,file:e.file,allowEmpty:e["allow-empty"],ignoreSkipRules:e["ignore-skip-rules"],skipSchemaSourceVerify:e["skip-schema-source-verify"],supplied:{baseUrl:e["base-url"],database:e.database,endpoint:e.endpoint,env:e.env,envFrom:e["env-from"],environmentFile:e["environment-file"]},vitest:e},n.type||null,process.cwd(),process.cwd());t.ownershipNotice!==null&&i(t.ownershipNotice);const s=await l(t.productDir),o=await y(t,{outputMode:e["output-mode"]||"compact",json:u,debug:e.debug}),r=await m({env:process.env,exitCode:o.exitCode,failedOutsideTests:o.failure!==void 0,policy:s,productDir:t.productDir,run:o.runArtifact});return r.knownFailures!==null&&(o.outputMode==="compact"||o.outputMode==="debug")&&p(k(r.knownFailures).join(`
2
- `)),c(r.exitCode),r.knownFailures===null?o:{...o,...r}}
1
+ import{applyKnownFailures as a,loadBugPolicy as m}from"../../app/bugs/gate.js";import{buildRunRequest as l}from"../../app/run/request.js";import{selectedGroup as w}from"../command-flags.js";import{executeRunRequest as y}from"../operations/run/operation.js";import{renderKnownFailures as k}from"../renderers/bug/text.js";export default async function v({args:r,flags:e,json:i,log:u,notice:c,setExitCode:d}){const p=w(e),t=await l({dir:e.dir,group:p??void 0,taskConcurrency:e["task-concurrency"],workers:e.workers,fileTimeoutSeconds:e["file-timeout-seconds"],type:e.type,suite:e.suite,file:e.file,allowEmpty:e["allow-empty"],ignoreSkipRules:e["ignore-skip-rules"],skipSchemaSourceVerify:e["skip-schema-source-verify"],supplied:{baseUrl:e["base-url"],database:e.database,endpoint:e.endpoint,env:e.env,envFrom:e["env-from"],environmentFile:e["environment-file"]},vitest:e},r.type||null,process.cwd(),process.cwd()),s=await m(t.productDir),n=await y(t,{outputMode:e["output-mode"]||"compact",json:i,debug:e.debug}),o=await a({env:process.env,exitCode:n.exitCode,failedOutsideTests:n.failure!==void 0,policy:s,productDir:t.productDir,run:n.runArtifact});return o.knownFailures!==null&&(n.outputMode==="compact"||n.outputMode==="debug")&&u(k(o.knownFailures).join(`
2
+ `)),n.maintenance?.status==="failed"&&c(`Post-run maintenance failed: ${n.maintenance.error??"unknown error"}. The run's result is unchanged.`),d(o.exitCode),o.knownFailures===null?n:{...n,...o}}
@@ -1 +1 @@
1
- import{runTestkitTypecheck as s,TestkitTypecheckError as u}from"../../app/typecheck/index.js";import{runWithCliProcessSignal as f}from"../process-signal.js";import{renderTypecheckResult as m}from"../renderers/typecheck/text.js";export default async function p({flags:r,json:i,log:e,notice:n}){const o=await f(t=>s({dir:r.dir,notice:n,signal:t,vitest:r})).catch(t=>{if(!i&&t instanceof u)for(const c of[t.result.stdout,t.result.stderr])c.trim()&&e(c.trimEnd());throw t});if(!i)for(const t of m(o))e(t);return o}
1
+ import{runTestkitTypecheck as n,TestkitTypecheckError as u}from"../../app/typecheck/index.js";import{runWithCliProcessSignal as s}from"../process-signal.js";import{renderTypecheckResult as f}from"../renderers/typecheck/text.js";export default async function p({flags:r,json:i,log:e}){const o=await s(t=>n({dir:r.dir,group:r.group,signal:t,vitest:r})).catch(t=>{if(!i&&t instanceof u)for(const c of[t.result.stdout,t.result.stderr])c.trim()&&e(c.trimEnd());throw t});if(!i)for(const t of f(o))e(t);return o}
@@ -1 +1 @@
1
- import{inspectWorkspace as a}from"../../app/inspect/index.js";import{selectedGroup as u}from"../command-flags.js";export default async function l({flags:r,json:e,log:t,notice:i}){const s=await a({dir:r.dir,group:u(r,i),notice:i,status:!r["no-status"],targetLimit:r["target-limit"]});if(!e&&(t(`${s.product.name} \xB7 Testkit workspace`),s.discovery&&t(` ${String(s.discovery.summary.groups)} groups \xB7 ${String(s.discovery.summary.suites)} suites \xB7 ${String(s.discovery.summary.files)} files`),s.runs.live?t(` live ${s.runs.live.status} \xB7 ${String(s.runs.live.files.passed)}/${String(s.runs.live.files.total)} files complete`):s.runs.latest&&t(` latest ${s.runs.latest.status} \xB7 ${String(s.runs.latest.files.passed)}/${String(s.runs.latest.files.total)} files passed`),s.warnings.length>0))for(const n of s.warnings)t(` warning: ${n}`);return s}
1
+ import{inspectWorkspace as n}from"../../app/inspect/index.js";import{selectedGroup as a}from"../command-flags.js";export default async function u({flags:i,json:r,log:t}){const s=await n({dir:i.dir,group:a(i),status:!i["no-status"],targetLimit:i["target-limit"]});if(!r&&(t(`${s.product.name} \xB7 Testkit workspace`),s.discovery&&t(` ${String(s.discovery.summary.groups)} groups \xB7 ${String(s.discovery.summary.suites)} suites \xB7 ${String(s.discovery.summary.files)} files`),s.runs.live?t(` live ${s.runs.live.status} \xB7 ${String(s.runs.live.files.passed)}/${String(s.runs.live.files.total)} files complete`):s.runs.latest&&t(` latest ${s.runs.latest.status} \xB7 ${String(s.runs.latest.files.passed)}/${String(s.runs.latest.files.total)} files passed`),s.warnings.length>0))for(const e of s.warnings)t(` warning: ${e}`);return s}
@@ -0,0 +1 @@
1
+ export const DATABASE_FIXTURE_DISCOVERY=Object.freeze({roots:Object.freeze([".testkit-fixture"])});
@@ -1 +1 @@
1
- import{clearRepoConfig as I,getRepoConfig as O,registerRepoConfig as $}from"./runtime.js";import{normalizeDatabaseEnvToken as b,normalizeNextPresetEnv as N,normalizePresetEnv as A}from"./preset-env.js";const P=String;export function defineConfig(e){return e||{}}function F(e={}){return{...e,...e.maxConnections?{maxConnections:e.maxConnections}:{},...e.reservedConnections?{reservedConnections:e.reservedConnections}:{},...e.runtimeConnections?{runtimeConnections:e.runtimeConnections}:{}}}function v(e,n="baseUrl"){const t=b(e,"service name",!1);return`{${b(n,"endpoint field",!1)}:${t}}`}function R(e={}){const n=E(e.migrate),t=E(e.seed),r=E(e.verify);return{inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0,migrate:n,seed:t,verify:r}}function z(e,n={}){return{kind:"command",run:e,...U(n)}}function _(e,n={}){return{kind:"sql-file",path:e,...U(n)}}function u(e,n={}){return{kind:"module",target:e,...U(n)}}function U(e={}){return{...e.cwd!==void 0?{cwd:e.cwd}:{},...e.inputs!==void 0?{inputs:[...e.inputs]}:{},...e.args!==void 0?{args:e.args}:{}}}function q(e,n={}){if(typeof e!="string"||e.trim().length===0)throw new Error("database.schema.fromEnv(...) requires a non-empty env var name");return{kind:"env",env:e.trim(),...n}}function f(e){return`@gfdelarue/testkit/config/database-steps#${e}`}function M(e={}){return u(f("verifySeed"),{args:e})}function V(e={}){return u(f("verifyRows"),{args:e})}function X(e={}){return u(f("runSql"),{args:e})}function G(e={}){return u(f("seedRows"),{args:e})}function H(e={}){return u(f("materializePostgresBinding"),{args:e})}function L(e={}){return u(f("updateRows"),{args:e})}function W(){return{kind:"now"}}function J(e){return{kind:"env",name:b(e,"database.values.env(...) name",!1)}}function K(e){return{kind:"json",value:e}}function Q(e){return{kind:"postgres-connection-from-env",prefix:b(e,"database.values.postgresConnectionFromEnv(...) prefix",!1)}}function Y(e={}){const{discovery:n,envFiles:t,template:r,inputs:s,migrate:o,seed:a,verify:d,...c}=e,i=r||D(e)?R({inputs:s,migrate:o,seed:a,verify:d,...r||{}}):void 0;return{discovery:n||{roots:[".testkit-fixture"]},envFiles:t,local:!1,database:F(i?{...c,template:i}:c)}}function D(e={}){return["inputs","migrate","seed","verify"].some(n=>Object.prototype.hasOwnProperty.call(e,n))}function B(e={}){return{...e}}function Z(e={}){return{kind:"tsc",cwd:e.cwd,entry:e.entry||"src/index.ts",tsconfig:e.tsconfig||"tsconfig.json",outDir:e.outDir||"dist",inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0}}function ee(e={}){return{kind:"next",cwd:e.cwd,distDir:e.distDir||"dist",tsconfig:e.tsconfig||"tsconfig.json",inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0}}function ne(e={}){const{baseUrl:n,build:t,buildInputs:r,cwd:s=".",entry:o="src/index.ts",env:a,envFiles:d,outDir:c="dist",port:i,readyPath:g="/health",readyTimeoutMs:S,shutdownTimeoutMs:p,readyUrl:h,runtime:m,start:C,toolchain:k,tsconfig:T="tsconfig.json",...l}=e,y=A(a),x=n||"http://127.0.0.1:{port}",w=t===void 0?Z({cwd:s,entry:o,tsconfig:T,outDir:c,inputs:r}):t,j=C||re(w,o);return{...l,envFiles:d,runtime:{...m||{},build:w,toolchain:k??m?.toolchain},local:{cwd:s,start:j,...i===void 0?{}:{port:i},baseUrl:x,readyUrl:h??`${x}${g}`,readyTimeoutMs:S,...p===void 0?{}:{shutdownTimeoutMs:p},env:y}}}function te(e={}){const{api:n,baseUrl:t,build:r,buildInputs:s,cwd:o=".",dependsOn:a,env:d,envFiles:c,mode:i="dev",port:g,readyTimeoutMs:S,shutdownTimeoutMs:p,readyUrl:h,runtime:m,start:C,toolchain:k,...T}=e,l={...N({api:n}),...A(d)},y=t||"http://127.0.0.1:{port}",x=r===void 0?i==="start"?ee({cwd:o,inputs:s}):null:r,w=C||(i==="start"?"{bin:next} start --port {port}":"{bin:next} dev -p {port}");return{...T,envFiles:c,dependsOn:Array.isArray(a)?[...a]:a,runtime:{...m||{},build:x,toolchain:k??m?.toolchain},local:{cwd:o,start:w,...g===void 0?{}:{port:g},baseUrl:y,readyUrl:h??y,readyTimeoutMs:S,...p===void 0?{}:{shutdownTimeoutMs:p},env:i==="start"?{NEXT_DIST_DIR:l.NEXT_DIST_DIR||".next-testkit/{runtimeId}/dist",NEXT_TSCONFIG_PATH:l.NEXT_TSCONFIG_PATH||".next-testkit/{runtimeId}/tsconfig.json",...l}:l}}}export const app={node:ne,next:te},database={schema:{fromEnv:q},steps:{materializePostgresBinding:H,runSql:X,seedRows:G,updateRows:L,verifyRows:V,verifySeed:M},values:{env:J,json:K,now:W,postgresConnectionFromEnv:Q},postgres(e={}){const{template:n,sourceSchema:t,inputs:r,migrate:s,seed:o,verify:a,...d}=e,c=t===void 0?d:{...d,sourceSchema:t},i=n||D(e)?R({inputs:r,migrate:s,seed:o,verify:a,...n||{}}):void 0;return F(i?{...c,template:i}:c)},fixture:Y},endpoint={baseUrl(e){return v(e,"baseUrl")},readyUrl(e){return v(e,"readyUrl")},publicBaseUrl(e){return v(e,"publicBaseUrl")},privateBaseUrl(e){return v(e,"privateBaseUrl")},serviceContextUrl(e){return v(e,"serviceContextUrl")}},step={command:z,module:u,sqlFile:_},presets={nodeNext(e={}){const n=e.workers;if(e.taskConcurrency!=null&&n!=null&&e.taskConcurrency!==n)throw new Error("presets.nodeNext taskConcurrency and workers must match when both are provided.");return{execution:{taskConcurrency:e.taskConcurrency??n??1,fileTimeoutSeconds:e.fileTimeoutSeconds??120},toolchains:{node:B({install:e.install??"download",...e.node?{node:e.node}:{},...e.npm?{npm:e.npm}:{}})}}}},toolchain={node:B};export{I as clearRepoConfig,O as getRepoConfig,$ as registerRepoConfig};function re(e,n){return e?.kind==="tsc"?`node {prepareDir}/${ie(n||e.entry||"src/index.ts",e.outDir||"dist")}`:`{bin:tsx} ${n||"src/index.ts"}`}function E(e){return e==null?[]:(Array.isArray(e)?e:[e]).map(t=>typeof t=="string"?z(t):t)}function ie(e,n){const r=P(e||"src/index.ts").replaceAll("\\","/").replace(/\.[cm]?[jt]sx?$/i,".js"),s=r.startsWith("src/")?r.slice(4):r;return`${n}/${s}`.replace(/\/+/g,"/")}
1
+ import{normalizeDatabaseEnvToken as S,normalizeNextPresetEnv as O,normalizePresetEnv as A}from"./preset-env.js";import{DATABASE_FIXTURE_DISCOVERY as j}from"./database-fixture-discovery.js";const _=String;export function defineConfig(e){return e||{}}function D(e={}){return{...e,...e.maxConnections?{maxConnections:e.maxConnections}:{},...e.reservedConnections?{reservedConnections:e.reservedConnections}:{},...e.runtimeConnections?{runtimeConnections:e.runtimeConnections}:{}}}function v(e,n="baseUrl"){const t=S(e,"service name",!1);return`{${S(n,"endpoint field",!1)}:${t}}`}function F(e={}){const n=E(e.migrate),t=E(e.seed),r=E(e.verify);return{inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0,migrate:n,seed:t,verify:r}}function z(e,n={}){return{kind:"command",run:e,...k(n)}}function $(e,n={}){return{kind:"sql-file",path:e,...k(n)}}function u(e,n={}){return{kind:"module",target:e,...k(n)}}function k(e={}){return{...e.cwd!==void 0?{cwd:e.cwd}:{},...e.inputs!==void 0?{inputs:[...e.inputs]}:{},...e.args!==void 0?{args:e.args}:{}}}function N(e,n={}){if(typeof e!="string"||e.trim().length===0)throw new Error("database.schema.fromEnv(...) requires a non-empty env var name");return{kind:"env",env:e.trim(),...n}}function f(e){return`@gfdelarue/testkit/config/database-steps#${e}`}function P(e={}){return u(f("verifySeed"),{args:e})}function q(e={}){return u(f("verifyRows"),{args:e})}function V(e={}){return u(f("runSql"),{args:e})}function X(e={}){return u(f("seedRows"),{args:e})}function M(e={}){return u(f("materializePostgresBinding"),{args:e})}function G(e={}){return u(f("updateRows"),{args:e})}function H(){return{kind:"now"}}function L(e){return{kind:"env",name:S(e,"database.values.env(...) name",!1)}}function W(e){return{kind:"json",value:e}}function Y(e){return{kind:"postgres-connection-from-env",prefix:S(e,"database.values.postgresConnectionFromEnv(...) prefix",!1)}}function J(e={}){const{discovery:n,envFiles:t,template:r,inputs:s,migrate:o,seed:a,verify:d,...c}=e,i=r||R(e)?F({inputs:s,migrate:o,seed:a,verify:d,...r||{}}):void 0;return{discovery:n||{roots:[...j.roots]},envFiles:t,local:!1,database:D(i?{...c,template:i}:c)}}function R(e={}){return["inputs","migrate","seed","verify"].some(n=>Object.prototype.hasOwnProperty.call(e,n))}function B(e={}){return{...e}}function K(e={}){return{kind:"tsc",cwd:e.cwd,entry:e.entry||"src/index.ts",tsconfig:e.tsconfig||"tsconfig.json",outDir:e.outDir||"dist",inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0}}function Q(e={}){return{kind:"next",cwd:e.cwd,distDir:e.distDir||"dist",tsconfig:e.tsconfig||"tsconfig.json",inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0}}function Z(e={}){const{baseUrl:n,build:t,buildInputs:r,cwd:s=".",entry:o="src/index.ts",env:a,envFiles:d,outDir:c="dist",port:i,readyPath:g="/health",readyTimeoutMs:b,shutdownTimeoutMs:p,readyUrl:h,runtime:m,start:C,toolchain:T,tsconfig:U="tsconfig.json",...l}=e,y=A(a),x=n||"http://127.0.0.1:{port}",w=t===void 0?K({cwd:s,entry:o,tsconfig:U,outDir:c,inputs:r}):t,I=C||ne(w,o);return{...l,envFiles:d,runtime:{...m||{},build:w,toolchain:T??m?.toolchain},local:{cwd:s,start:I,...i===void 0?{}:{port:i},baseUrl:x,readyUrl:h??`${x}${g}`,readyTimeoutMs:b,...p===void 0?{}:{shutdownTimeoutMs:p},env:y}}}function ee(e={}){const{api:n,baseUrl:t,build:r,buildInputs:s,cwd:o=".",dependsOn:a,env:d,envFiles:c,mode:i="dev",port:g,readyTimeoutMs:b,shutdownTimeoutMs:p,readyUrl:h,runtime:m,start:C,toolchain:T,...U}=e,l={...O({api:n}),...A(d)},y=t||"http://127.0.0.1:{port}",x=r===void 0?i==="start"?Q({cwd:o,inputs:s}):null:r,w=C||(i==="start"?"{bin:next} start --port {port}":"{bin:next} dev -p {port}");return{...U,envFiles:c,dependsOn:Array.isArray(a)?[...a]:a,runtime:{...m||{},build:x,toolchain:T??m?.toolchain},local:{cwd:o,start:w,...g===void 0?{}:{port:g},baseUrl:y,readyUrl:h??y,readyTimeoutMs:b,...p===void 0?{}:{shutdownTimeoutMs:p},env:i==="start"?{NEXT_DIST_DIR:l.NEXT_DIST_DIR||".next-testkit/{runtimeId}/dist",NEXT_TSCONFIG_PATH:l.NEXT_TSCONFIG_PATH||".next-testkit/{runtimeId}/tsconfig.json",...l}:l}}}export const app={node:Z,next:ee},database={schema:{fromEnv:N},steps:{materializePostgresBinding:M,runSql:V,seedRows:X,updateRows:G,verifyRows:q,verifySeed:P},values:{env:L,json:W,now:H,postgresConnectionFromEnv:Y},postgres(e={}){const{template:n,sourceSchema:t,inputs:r,migrate:s,seed:o,verify:a,...d}=e,c=t===void 0?d:{...d,sourceSchema:t},i=n||R(e)?F({inputs:r,migrate:s,seed:o,verify:a,...n||{}}):void 0;return D(i?{...c,template:i}:c)},fixture:J},endpoint={baseUrl(e){return v(e,"baseUrl")},readyUrl(e){return v(e,"readyUrl")},publicBaseUrl(e){return v(e,"publicBaseUrl")},privateBaseUrl(e){return v(e,"privateBaseUrl")},serviceContextUrl(e){return v(e,"serviceContextUrl")}},step={command:z,module:u,sqlFile:$},presets={nodeNext(e={}){const n=e.workers;if(e.taskConcurrency!=null&&n!=null&&e.taskConcurrency!==n)throw new Error("presets.nodeNext taskConcurrency and workers must match when both are provided.");return{execution:{taskConcurrency:e.taskConcurrency??n??1,fileTimeoutSeconds:e.fileTimeoutSeconds??120},toolchains:{node:B({install:e.install??"download",...e.node?{node:e.node}:{},...e.npm?{npm:e.npm}:{}})}}}},toolchain={node:B};function ne(e,n){return e?.kind==="tsc"?`node {prepareDir}/${te(n||e.entry||"src/index.ts",e.outDir||"dist")}`:`{bin:tsx} ${n||"src/index.ts"}`}function E(e){return e==null?[]:(Array.isArray(e)?e:[e]).map(t=>typeof t=="string"?z(t):t)}function te(e,n){const r=_(e||"src/index.ts").replaceAll("\\","/").replace(/\.[cm]?[jt]sx?$/i,".js"),s=r.startsWith("src/")?r.slice(4):r;return`${n}/${s}`.replace(/\/+/g,"/")}