@redue/cli 0.1.0-alpha.2 → 0.1.0-alpha.20

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 (60) hide show
  1. package/CHANGELOG.md +467 -0
  2. package/README.md +107 -2
  3. package/bin/redue.mjs +130 -49
  4. package/docs/README.md +2 -1
  5. package/docs/user/agents.md +299 -15
  6. package/docs/user/configuration.md +28 -2
  7. package/docs/user/direct-typescript.md +209 -0
  8. package/docs/user/getting-started.md +23 -2
  9. package/docs/user/json.md +2 -0
  10. package/docs/user/node-script.md +153 -0
  11. package/docs/user/npm-launcher-notice.md +42 -0
  12. package/docs/user/pilot.md +146 -0
  13. package/docs/user/receipt-selection-notice.md +60 -0
  14. package/docs/user/supported-projects.md +49 -21
  15. package/docs/user/tests-direct.md +132 -0
  16. package/package.json +4 -3
  17. package/src/agent-integration.mjs +388 -0
  18. package/src/agent-policy.md +28 -0
  19. package/src/cached-state.mjs +46 -8
  20. package/src/claude-hook.mjs +449 -0
  21. package/src/cli.mjs +263 -40
  22. package/src/daemon.mjs +433 -94
  23. package/src/decision-profile.mjs +15 -1
  24. package/src/decision-validation.mjs +10 -0
  25. package/src/declared-plan.mjs +29 -6
  26. package/src/direct-run-certificate.mjs +252 -0
  27. package/src/direct-typescript-probe.mjs +24 -0
  28. package/src/direct-typescript.mjs +185 -0
  29. package/src/glob.mjs +8 -0
  30. package/src/history-worker.mjs +21 -13
  31. package/src/index.mjs +72 -19
  32. package/src/installed-inputs.mjs +7 -1
  33. package/src/linux-inotify.py +39 -10
  34. package/src/node-onboarding.mjs +157 -48
  35. package/src/node-script.mjs +362 -0
  36. package/src/npm-integrity.mjs +124 -0
  37. package/src/npm-typecheck-environment.mjs +36 -0
  38. package/src/npmrc.mjs +16 -0
  39. package/src/observation.mjs +34 -12
  40. package/src/path-identity.mjs +8 -0
  41. package/src/plan-worker.mjs +17 -17
  42. package/src/pnpm-inputs.mjs +114 -54
  43. package/src/pnpm-shim-templates.json +180 -0
  44. package/src/pnpm-shims.mjs +54 -0
  45. package/src/pnpm-typecheck-probe.mjs +11 -6
  46. package/src/presentation.mjs +9 -1
  47. package/src/probe-deadline.mjs +37 -0
  48. package/src/probe-result.mjs +7 -3
  49. package/src/project-location.mjs +34 -0
  50. package/src/run-recorder.cjs +91 -0
  51. package/src/state-store.mjs +37 -1
  52. package/src/test-direct.mjs +560 -0
  53. package/src/test-recorder.cjs +406 -0
  54. package/src/typescript-contract-probe.mjs +4 -187
  55. package/src/typescript-input-facts.mjs +92 -0
  56. package/src/typescript-invocation.mjs +92 -0
  57. package/src/typescript-list.mjs +108 -13
  58. package/src/typescript-qualification.mjs +29 -49
  59. package/src/workspace-manifests.mjs +22 -0
  60. package/src/yarn-workspace-typecheck-probe.mjs +2 -1
@@ -3,11 +3,14 @@ import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import {createHash} from 'node:crypto';
5
5
  import {discover} from './plan.mjs';
6
- import {InputIndex} from './index.mjs';
6
+ import {InputIndex,dehydrateIndex} from './index.mjs';
7
+ import {directProject,directQualification} from './direct-typescript.mjs';
8
+ import {checkRun} from './typescript-invocation.mjs';
7
9
  import {queriesMatch} from './typescript-list.mjs';
8
10
  import {planGuard,inputKey} from './decision-validation.mjs';
9
- import {timing} from './decision-profile.mjs';
11
+ import {timing,traceBase} from './decision-profile.mjs';
10
12
 
13
+ traceBase(workerData.diagnostic);
11
14
  try {
12
15
  const totalStarted=performance.now();
13
16
  const configStarted=performance.now();
@@ -21,7 +24,16 @@ try {
21
24
  try{
22
25
  guard=planGuard(bundle);
23
26
  const queryStarted=performance.now();
24
- const queriesValid=!workerData.reuse.queries?.length||queriesMatch(workerData.reuse.queries);
27
+ // Cached membership queries load the compiler API; establish its reviewed
28
+ // implementation before that optimization can execute project code.
29
+ // Every direct check (a chain has one per run) uses the root's compiler:
30
+ // its bytes are verified once.
31
+ const directRoots=new Set(config.checks.filter(check=>check.qualification===directQualification)
32
+ .map((check,i)=>directProject(config.root,checkRun(check),{verify:i===0}).tsRoot));
33
+ if(directRoots.size&&(workerData.reuse.queries||[]).some(([kind,,,options])=>
34
+ kind==='readDirectory'&&!directRoots.has(options?.tsRoot)))throw Error('retained compiler implementation changed');
35
+ const queriesValid=guard===workerData.reuse.guard&&
36
+ (!workerData.reuse.queries?.length||queriesMatch(workerData.reuse.queries));
25
37
  timing('worker.compiler_queries',queryStarted,{queries:workerData.reuse.queries?.length||0,matched:queriesValid?1:0});
26
38
  if(guard!==workerData.reuse.guard||!queriesValid)reuseReason='configuration_or_resolution_changed';
27
39
  else {
@@ -104,26 +116,14 @@ try {
104
116
  const outside=new InputIndex({root:boundary,plans},{trackGit:false,includeInstalled:true});
105
117
  outside.coldScan();
106
118
  if(outside.unavailable)throw Error(outside.unavailable);
107
- external[boundary]={files:[...outside.files],
108
- aliasDependencies:[...outside.aliasDependencies].map(([name,refs])=>[name,[...refs]]),
109
- rows:[...outside.checks]
110
- .map(([name,row])=>({name,files:[...row.files],sum:row.sum.toString('hex'),
111
- revision:row.revision,lastReason:row.lastReason})),
112
- eventCount:outside.eventCount,rehashedFiles:outside.rehashedFiles,
113
- rehashedBytes:outside.rehashedBytes,profile:outside.profile};
119
+ external[boundary]=dehydrateIndex(outside);
114
120
  }
115
121
  timing('worker.total',totalStarted,{mode:'cold',files:index.files.size});
116
122
  parentPort.postMessage({ok:true,bundle,discoveryMs,indexingMs,guard,planReused,
117
123
  inputKeys:Object.fromEntries([...index.checks].map(([name,row])=>[name,inputKey(row)])),
118
124
  restartMode:'cold-index',
119
125
  external,
120
- index:{files:[...index.files],
121
- aliasDependencies:[...index.aliasDependencies].map(([name,refs])=>[name,[...refs]]),
122
- rows:[...index.checks].map(([name,row])=>({
123
- name,files:[...row.files],sum:row.sum.toString('hex'),revision:row.revision,
124
- lastReason:row.lastReason})),
125
- eventCount:index.eventCount,rehashedFiles:index.rehashedFiles,
126
- rehashedBytes:index.rehashedBytes,profile:index.profile}});
126
+ index:dehydrateIndex(index)});
127
127
  }
128
128
  } catch(error) {
129
129
  parentPort.postMessage({ok:false,error:error?.message||String(error),
@@ -1,21 +1,24 @@
1
- // Pinned pnpm 12 node-modules installation provider. The engine sees only
1
+ // pnpm 9-12 node-modules installation provider. The engine sees only
2
2
  // repository-relative input sets and resolution relationships, never pnpm
3
3
  // virtual-store names as semantic identities.
4
+ import {probeTimeLeft} from './probe-deadline.mjs';
4
5
  import {compilerFiles} from './typescript-list.mjs';
5
6
  import fs from 'node:fs';
6
7
  import path from 'node:path';
7
8
  import {createRequire} from 'node:module';
8
9
  import {execFileSync,spawnSync} from 'node:child_process';
9
- import micromatch from './glob.mjs';
10
+ import micromatch,{patternMatcher} from './glob.mjs';
10
11
  import YAML from 'yaml';
11
12
  import {resolveLinks} from './installed-inputs.mjs';
12
13
  import {withinPath as within,realObservedPath,samePath} from './path-identity.mjs';
13
14
  import {timing} from './decision-profile.mjs';
15
+ import {npmrc} from './npmrc.mjs';
16
+ import {runConfig,tscRun,tscRuns} from './typescript-invocation.mjs';
14
17
 
15
18
  const rel=(root,file)=>path.relative(root,file).split(path.sep).join('/');
16
19
  const read=file=>JSON.parse(fs.readFileSync(file,'utf8'));
17
20
  const exists=file=>{try{fs.lstatSync(file);return true;}catch{return false;}};
18
- function yaml(file){
21
+ export function yaml(file){
19
22
  const doc=YAML.parseDocument(fs.readFileSync(file,'utf8'),{uniqueKeys:true});
20
23
  if(doc.errors.length)throw Error(`${path.basename(file)} cannot be interpreted safely`);
21
24
  return doc.toJS()||{};
@@ -26,40 +29,67 @@ function safePatterns(values){
26
29
  throw Error('pnpm workspace patterns are unsupported');
27
30
  return values;
28
31
  }
32
+ // The supported pnpm majors. pnpm 9 reads settings from .npmrc, pnpm 10 from
33
+ // pnpm-workspace.yaml first and then .npmrc, pnpm 11 and 12 from
34
+ // pnpm-workspace.yaml only.
35
+ export const pnpmMajors=[9,10,11,12];
36
+ // Settings that move or copy installed files, or run code during install,
37
+ // where the contract does not look; by pnpm-workspace.yaml and .npmrc name.
38
+ // Other settings change only what gets installed, and the installed files are
39
+ // what the contract observes. These are refused when either file sets them,
40
+ // whichever file the installed pnpm reads. Only the project's files are read:
41
+ // user or global rc files and npm_config_* variables at install time are not.
42
+ const refused=[['modulesDir','modules-dir'],['virtualStoreDir','virtual-store-dir'],['lockfileDir','lockfile-dir'],
43
+ ['enableGlobalVirtualStore','enable-global-virtual-store'],['injectWorkspacePackages','inject-workspace-packages'],
44
+ ['sharedWorkspaceLockfile','shared-workspace-lockfile'],['pnpmfile','pnpmfile'],['globalPnpmfile','global-pnpmfile'],
45
+ ['configDependencies','config-dependencies']];
46
+ // Whether a refused setting is set: present at all, except that only
47
+ // sharedWorkspaceLockfile=false and injectWorkspacePackages=true move files.
48
+ const setting=(key,value)=>value!==undefined&&
49
+ (key==='sharedWorkspaceLockfile'?value===false:key==='injectWorkspacePackages'?value===true:true);
29
50
  export function pnpmProjectInfo(root){
30
51
  root=realObservedPath(root);
31
52
  const pkg=read(path.join(root,'package.json'));
32
- const pin=/^pnpm@(12\.\d+\.\d+)(?:\+[^\s]+)?$/.exec(pkg.packageManager||'');
33
- if(!pin)throw Error('an exact pnpm 12 packageManager pin is required');
53
+ // A pin is optional; when present it names pnpm 9-12, and the install must match it.
54
+ const pin=pkg.packageManager===undefined?null:/^pnpm@((\d+)\.\d+\.\d+)(?:\+[^\s]+)?$/.exec(pkg.packageManager);
55
+ if(pkg.packageManager!==undefined&&(!pin||!pnpmMajors.includes(Number(pin[2]))))
56
+ throw Error(`packageManager ${JSON.stringify(String(pkg.packageManager).split('+')[0])} is outside pnpm ${pnpmMajors[0]}-${pnpmMajors.at(-1)}`);
34
57
  const workspaceFile=path.join(root,'pnpm-workspace.yaml');
35
- const settings=exists(workspaceFile)?yaml(workspaceFile):{};
36
- const patterns=safePatterns(settings.packages||[]);
37
- const linker=settings.nodeLinker||'isolated';
38
- return {version:pin[1],linker,patterns,settings};
58
+ const workspace=exists(workspaceFile)?yaml(workspaceFile):{},rc=npmrc(path.join(root,'.npmrc'));
59
+ const patterns=safePatterns(workspace.packages||[]);
60
+ // The linker the given pnpm major reads; without a major, the one any reads.
61
+ const linkerFor=major=>(major===9?rc['node-linker']:major>=11?workspace.nodeLinker:
62
+ workspace.nodeLinker??rc['node-linker'])||'isolated';
63
+ const major=pin?Number(pin[2]):null;
64
+ return {version:pin?.[1]??null,linker:linkerFor(major),linkerFor,patterns,settings:workspace,
65
+ refused:refused.filter(([key,name])=>setting(key,workspace[key])||setting(key,rc[name])).map(([key])=>key)};
39
66
  }
40
67
  export function pnpmInstallInfo(root){
41
68
  const started=performance.now();
42
69
  root=realObservedPath(root);
43
- const pkg=read(path.join(root,'package.json'));
44
- const {version,linker,patterns,settings}=pnpmProjectInfo(root);
70
+ const {version,linkerFor,patterns,settings,refused}=pnpmProjectInfo(root);
45
71
  const workspaceFile=path.join(root,'pnpm-workspace.yaml');
46
- if(!['isolated','hoisted'].includes(linker))throw Error(`pnpm ${linker} linker is recording-only`);
47
- if(settings.modulesDir||settings.virtualStoreDir||settings.enableGlobalVirtualStore)
48
- throw Error('custom pnpm modules or virtual-store location is recording-only');
49
- if(settings.injectWorkspacePackages)
50
- throw Error('injected workspace dependencies are recording-only');
51
- if(settings.sharedWorkspaceLockfile===false)
52
- throw Error('separate workspace lockfiles are recording-only');
53
- if(exists(path.join(root,'.pnpmfile.cjs'))||exists(path.join(root,'.pnpmfile.mjs')))
72
+ if(refused.some(key=>['pnpmfile','globalPnpmfile','configDependencies'].includes(key))||
73
+ exists(path.join(root,'.pnpmfile.cjs'))||exists(path.join(root,'.pnpmfile.mjs')))
54
74
  throw Error('custom pnpm installation hooks need review');
75
+ if(refused.some(key=>['modulesDir','virtualStoreDir','lockfileDir','enableGlobalVirtualStore'].includes(key)))
76
+ throw Error('custom pnpm modules or virtual-store location is recording-only');
77
+ if(refused.includes('injectWorkspacePackages'))throw Error('injected workspace dependencies are recording-only');
78
+ if(refused.includes('sharedWorkspaceLockfile'))throw Error('separate workspace lockfiles are recording-only');
55
79
  const modulesFile=path.join(root,'node_modules','.modules.yaml');
56
80
  if(!exists(modulesFile))throw Error('installed pnpm module metadata is missing');
57
81
  const modules=yaml(modulesFile);
58
- if(modules.nodeLinker!==linker||modules.packageManager!==pkg.packageManager)
82
+ const installed=/^pnpm@((\d+)\.\d+\.\d+)$/.exec(String(modules.packageManager));
83
+ if(!installed||!pnpmMajors.includes(Number(installed[2])))
84
+ throw Error(`installed by ${JSON.stringify(String(modules.packageManager))}, outside pnpm ${pnpmMajors[0]}-${pnpmMajors.at(-1)}`);
85
+ const linker=linkerFor(Number(installed[2]));
86
+ if(!['isolated','hoisted'].includes(linker))throw Error(`pnpm ${linker} linker is recording-only`);
87
+ if(modules.nodeLinker!==linker||version!==null&&installed[1]!==version)
59
88
  throw Error('installed pnpm linker or version differs from project configuration');
60
89
  const virtualStore=path.join(root,'node_modules','.pnpm');
61
- // pnpm 12 on Windows can omit virtualStoreDir when using its project-local
62
- // default. Accept only the observed, ordinary local directory in that case.
90
+ // pnpm can omit virtualStoreDir when using its project-local default
91
+ // (seen with pnpm 12 on Windows). Accept only the observed, ordinary local
92
+ // directory in that case.
63
93
  const declared=modules.virtualStoreDir;
64
94
  const selected=declared===undefined?virtualStore:
65
95
  path.resolve(path.dirname(modulesFile),declared);
@@ -71,18 +101,8 @@ export function pnpmInstallInfo(root){
71
101
  throw Error('nonstandard or incomplete project-local pnpm virtual store');
72
102
  if(!exists(path.join(root,'pnpm-lock.yaml')))
73
103
  throw Error('pnpm lockfile is missing');
74
- if(exists(path.join(root,'.npmrc'))){
75
- // pnpm 12 reads project settings from pnpm-workspace.yaml. Registry/auth
76
- // entries affect acquisition, not a completed local TypeScript invocation.
77
- for(const line of fs.readFileSync(path.join(root,'.npmrc'),'utf8').split(/\r?\n/)){
78
- const trimmed=line.trim();if(!trimmed||/^[#;]/.test(trimmed))continue;
79
- const key=trimmed.split('=')[0].trim();
80
- if(key!=='registry'&&!/^\/\/[^\s]+\/:_authToken$/.test(key))
81
- throw Error('project .npmrc has execution-relevant pnpm settings requiring review');
82
- }
83
- }
84
104
  timing('pnpm.install_metadata',started);
85
- return {version,linker,patterns,settings,modulesFile,
105
+ return {version:installed[1],linker,patterns,settings,modulesFile,
86
106
  configurationInputs:['package.json','pnpm-lock.yaml',
87
107
  ...(exists(workspaceFile)?['pnpm-workspace.yaml']:[]),
88
108
  ...(exists(path.join(root,'.npmrc'))?['.npmrc']:[]),
@@ -96,7 +116,7 @@ export function pnpmWorkspacePackages(root,patterns){
96
116
  const files=execFileSync('git',['ls-files','--cached','--others','--exclude-standard',
97
117
  '-z','--',':(glob)**/package.json'],{cwd:root,
98
118
  env:{...process.env,GIT_OPTIONAL_LOCKS:'0'},maxBuffer:32*1024*1024,
99
- timeout:5000}).toString().split('\0').filter(Boolean);
119
+ timeout:probeTimeLeft(5000)}).toString().split('\0').filter(Boolean);
100
120
  for(const file of files){
101
121
  const dir=path.posix.dirname(file);
102
122
  if(dir==='.'||dir.split('/').includes('node_modules')||
@@ -172,16 +192,37 @@ function packageAt(root,requester,name){
172
192
  }
173
193
  return {physical:null,candidates};
174
194
  }
175
- function parsedTypeScript(root,dir,ts){
176
- const config=path.join(root,dir,'tsconfig.json'),reads=new Set();
195
+ // Files TypeScript may consume from its own include: each directory its
196
+ // include patterns watch for new files (TypeScript's own
197
+ // wildcardDirectories), and each file it lists. node_modules below them is
198
+ // left out, as TypeScript's wildcards leave it out; installed files a program
199
+ // reads are installed inputs. `exclude` entries stay inputs: an import can
200
+ // still reach an excluded file.
201
+ const sourceFiles='*.{ts,tsx,mts,cts,js,jsx,mjs,cjs,json}';
202
+ function sourcePatterns(root,parsed){
203
+ const patterns=new Set(),excluded=new Set();
204
+ for(const [folder,flags] of Object.entries(parsed.wildcardDirectories||{})){
205
+ // TypeScript 4 lowercases these keys on case-insensitive file systems;
206
+ // the native realpath gives the directory's own spelling.
207
+ let at;try{at=fs.realpathSync.native(folder);}catch{at=path.resolve(folder);}
208
+ if(!within(at,root))throw Error('TypeScript source membership escapes the checkout');
209
+ const prefix=rel(root,at)?rel(root,at)+'/':'';
210
+ if(flags&1){patterns.add(`${prefix}**/${sourceFiles}`);excluded.add(`!${prefix}**/node_modules/**`);}
211
+ else patterns.add(prefix+sourceFiles);
212
+ }
213
+ const included=patternMatcher([...patterns,...excluded]);
214
+ for(const file of parsed.fileNames.map(name=>path.resolve(name))){
215
+ if(!within(file,root))throw Error('TypeScript source membership escapes the checkout');
216
+ if(!included(rel(root,file)))patterns.add(rel(root,file));
217
+ }
218
+ return [...patterns,...excluded];
219
+ }
220
+ function parsedTypeScript(root,dir,ts,configName='tsconfig.json'){
221
+ const config=path.join(root,dir,configName),reads=new Set();
177
222
  const host={...ts.sys,readFile(file){reads.add(path.resolve(file));return ts.sys.readFile(file);},
178
223
  onUnRecoverableConfigFileDiagnostic(){}};
179
224
  const parsed=ts.getParsedCommandLineOfConfigFile(config,{},host);
180
225
  if(!parsed||parsed.errors?.length)throw Error('TypeScript configuration unavailable');
181
- const raw=ts.readConfigFile(config,ts.sys.readFile);
182
- if(raw.error||!Array.isArray(raw.config?.include)||raw.config.include.length!==1||
183
- !/^src(?:$|\/)/.test(raw.config.include[0]))
184
- throw Error('TypeScript source file membership is outside the supported src include');
185
226
  if(parsed.options.plugins?.length||parsed.options.incremental||parsed.options.composite||
186
227
  parsed.projectReferences?.length||parsed.options.paths||parsed.options.baseUrl||
187
228
  parsed.options.rootDirs?.length||parsed.options.typeRoots?.length||
@@ -193,16 +234,17 @@ function parsedTypeScript(root,dir,ts){
193
234
  throw Error('TypeScript module resolver is outside the supported Node contract');
194
235
  for(const file of reads)if(!within(realObservedPath(file),root))
195
236
  throw Error('TypeScript configuration escapes the checkout');
196
- return {parsed,configs:[...reads].map(file=>rel(root,file)).sort()};
237
+ return {parsed,configs:[...reads].map(file=>rel(root,file)).sort(),
238
+ sourcePatterns:sourcePatterns(root,parsed)};
197
239
  }
198
- function listedTypeScriptFiles(root,selected,tsc){
240
+ function listedTypeScriptFiles(root,selected,tsc,configName){
199
241
  // --listFilesOnly resolves the compiler's effective module/file set but
200
242
  // performs no typecheck and emits no project outputs.
201
- const out=spawnSync(process.execPath,[tsc,'-p','tsconfig.json','--listFilesOnly'],
243
+ const out=spawnSync(process.execPath,[tsc,'-p',configName,'--listFilesOnly'],
202
244
  {cwd:path.join(root,selected.dir),env:process.env,encoding:'utf8',
203
245
  // The native NTFS public workspace takes 3-5 s to list ~770 inputs;
204
246
  // 5 s sometimes expired despite bounded, progressing compiler work.
205
- timeout:10000,maxBuffer:32*1024*1024,stdio:['ignore','pipe','pipe']});
247
+ timeout:probeTimeLeft(10000),maxBuffer:32*1024*1024,stdio:['ignore','pipe','pipe']});
206
248
  if(out.error||out.signal||out.status!==0)
207
249
  throw Error('TypeScript input listing is unavailable');
208
250
  const files=out.stdout.trim().split(/\r?\n/).filter(Boolean)
@@ -235,17 +277,23 @@ function sharedHardlinkIn(folder){
235
277
  }
236
278
  return false;
237
279
  }
238
- export function pnpmTypecheckInputs(root,workspace,script,{captureQueries=false}={}){
280
+ // `run`: the check's {script, part, args}, or a script name for its only run.
281
+ export function pnpmTypecheckInputs(root,workspace,run,{captureQueries=false}={}){
239
282
  const totalStarted=performance.now();
240
283
  root=realObservedPath(root);
241
284
  const install=pnpmInstallInfo(root),members=pnpmWorkspacePackages(root,install.patterns);
242
285
  const selected=workspace==='.'?{name:'.',dir:'.',manifest:'package.json',
243
286
  pkg:read(path.join(root,'package.json'))}:members.get(workspace);
244
287
  if(!selected)throw Error(`workspace ${workspace} is not declared`);
245
- if(!/^(?:tsc --noEmit|tsc -p (?:\.|tsconfig\.json)(?: --noEmit)?)$/.test(
246
- selected.pkg.scripts?.[script]?.trim()||'')||
247
- selected.pkg.scripts?.['pre'+script]||selected.pkg.scripts?.['post'+script])
248
- throw Error('typecheck must be one standalone TypeScript invocation');
288
+ // A script name stands for its only run.
289
+ if(typeof run==='string'){const runs=tscRuns(selected.pkg.scripts?.[run]);run={script:run,args:runs?.length===1?runs[0].args:[]};}
290
+ const {run:own,issue}=tscRun(selected.pkg.scripts,run);
291
+ if(issue)throw Error(`typecheck must be standalone TypeScript runs: ${issue}`);
292
+ // `tsc -p .` without --noEmit predates the other forms.
293
+ if(!own.noEmit&&!['-p .','-p tsconfig.json'].includes(run.args.join(' ')))
294
+ throw Error('typecheck must pass --noEmit');
295
+ const configName=runConfig(path.join(root,selected.dir),run.args);
296
+ if(!configName)throw Error('TypeScript project is outside the package');
249
297
  const selectedDir=path.join(root,selected.dir),lookup=createRequire(path.join(selectedDir,'package.json'));
250
298
  let tsPackage;try{tsPackage=realObservedPath(lookup.resolve('typescript/package.json'));}
251
299
  catch{throw Error('installed TypeScript compiler cannot be resolved');}
@@ -254,7 +302,8 @@ export function pnpmTypecheckInputs(root,workspace,script,{captureQueries=false}
254
302
  const tsc=path.join(tsRoot,'bin','tsc');
255
303
  if(!exists(tsc))throw Error('installed TypeScript executable is missing');
256
304
  const configStarted=performance.now();
257
- const {configs}=parsedTypeScript(root,selected.dir,ts);
305
+ const {configs,sourcePatterns:sources}=parsedTypeScript(root,selected.dir,ts,configName);
306
+ const isSource=patternMatcher(sources);
258
307
  timing('pnpm.ts_config',configStarted,{configs:configs.length});
259
308
  const closure=new Map(),installed=new Set(),generated=new Set(),
260
309
  links=new Set(),candidates=new Set(),absences=[],instances=new Map();
@@ -304,12 +353,12 @@ export function pnpmTypecheckInputs(root,workspace,script,{captureQueries=false}
304
353
  resolutionMs:Math.round(resolutionMs),workspaceLinks:links.size,
305
354
  candidates:candidates.size});
306
355
  const listingStarted=performance.now();
307
- const captured=captureQueries?compilerFiles(tsRoot,path.join(root,selected.dir)):null;
308
- const files=captured?captured.files.map(realObservedPath):listedTypeScriptFiles(root,selected,tsc);
356
+ const captured=captureQueries?compilerFiles(tsRoot,path.join(root,selected.dir),configName):null;
357
+ const files=captured?captured.files.map(realObservedPath):listedTypeScriptFiles(root,selected,tsc,configName);
309
358
  timing('pnpm.ts_input_listing',listingStarted,{files:files.length});
310
359
  const mappingStarted=performance.now();
311
360
  for(const file of files){
312
- if(within(file,path.join(selectedDir,'src'))||
361
+ if(isSource(rel(root,file))||
313
362
  [...closure.values()].some(member=>within(file,path.join(root,member.dir))))continue;
314
363
  const packageRoot=installedPackageRoot(root,file);
315
364
  if(!packageRoot)throw Error(`TypeScript consumes a file outside the observed pnpm contract: ${rel(root,file)}`);
@@ -320,6 +369,16 @@ export function pnpmTypecheckInputs(root,workspace,script,{captureQueries=false}
320
369
  }
321
370
  timing('pnpm.input_mapping',mappingStarted,{instances:instances.size,
322
371
  installedPatterns:installed.size});
372
+ // A config extended from an installed package is an installed input too:
373
+ // source patterns leave node_modules out.
374
+ for(const config of configs){
375
+ const file=realObservedPath(path.join(root,config));
376
+ if(!within(file,path.join(root,'node_modules')))continue;
377
+ const packageRoot=installedPackageRoot(root,file);
378
+ if(!packageRoot)throw Error(`TypeScript configuration ${config} is outside an installed package`);
379
+ installed.add(`${rel(root,packageRoot)}/**`);
380
+ installed.add(`!${rel(root,packageRoot)}/node_modules/**`);
381
+ }
323
382
  installed.add(`${rel(root,tsRoot)}/**`);
324
383
  installed.add(`!${rel(root,tsRoot)}/node_modules/**`);
325
384
  if(!instances.has(tsRoot))instances.set(tsRoot,{name:'typescript',physicalRoot:rel(root,tsRoot)});
@@ -328,11 +387,12 @@ export function pnpmTypecheckInputs(root,workspace,script,{captureQueries=false}
328
387
  timing('pnpm.hardlink_inspection',sharedStarted,{instances:instances.size,
329
388
  shared:shared.length});
330
389
  const source=[...new Set([...install.configurationInputs,selected.manifest,
331
- ...configs,`${selected.dir==='.'?'':selected.dir+'/'}src/**`,
390
+ ...configs,...sources,
332
391
  ...closure.values().map(member=>member.manifest),...generated])];
333
392
  timing('pnpm.total_discovery',totalStarted,{instances:instances.size,
334
393
  inputFiles:files.length});
335
394
  return {install,workspace:selected,closure:[...closure.values()],source,
395
+ sourcePatterns:sources,args:run.args,
336
396
  installed:[...installed],generated:[...generated],
337
397
  // The read-only state probe consumes this same resolved compiler file set.
338
398
  // It is deliberately omitted from the persisted user-facing input plan.
@@ -0,0 +1,180 @@
1
+ {
2
+ "schema": 1,
3
+ "templates": [
4
+ {
5
+ "versions": [
6
+ "8.0.0",
7
+ "8.1.1",
8
+ "8.2.0",
9
+ "8.3.1",
10
+ "8.4.0",
11
+ "8.5.1",
12
+ "8.6.12",
13
+ "8.7.6",
14
+ "8.8.0",
15
+ "8.9.2",
16
+ "8.10.5",
17
+ "8.11.0",
18
+ "8.12.1",
19
+ "8.13.1",
20
+ "8.14.3",
21
+ "8.15.9",
22
+ "9.0.6",
23
+ "9.1.4",
24
+ "9.2.0",
25
+ "9.3.0",
26
+ "9.4.0",
27
+ "9.5.0",
28
+ "9.6.0",
29
+ "9.7.1",
30
+ "9.8.0",
31
+ "9.9.0",
32
+ "9.10.0",
33
+ "9.11.0",
34
+ "9.12.3",
35
+ "9.13.2",
36
+ "9.14.4",
37
+ "9.15.4",
38
+ "9.15.9",
39
+ "10.0.0",
40
+ "10.1.0",
41
+ "10.2.1",
42
+ "10.3.0",
43
+ "10.4.1",
44
+ "10.5.2",
45
+ "10.6.5",
46
+ "10.7.1",
47
+ "10.8.1",
48
+ "10.9.0"
49
+ ],
50
+ "template": "#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\n\ncase `uname` in\n *CYGWIN*) basedir=`cygpath -w \"$basedir\"`;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n"
51
+ },
52
+ {
53
+ "versions": [
54
+ "10.10.0",
55
+ "10.11.1",
56
+ "10.12.4",
57
+ "10.13.1",
58
+ "10.14.0",
59
+ "10.15.1",
60
+ "10.16.1",
61
+ "10.17.1",
62
+ "10.18.3",
63
+ "10.19.0",
64
+ "10.20.0",
65
+ "10.21.0",
66
+ "10.22.0",
67
+ "10.23.0",
68
+ "10.24.0",
69
+ "10.25.0",
70
+ "10.26.2",
71
+ "10.27.0",
72
+ "10.28.2",
73
+ "10.29.3",
74
+ "10.30.3",
75
+ "10.31.0",
76
+ "10.32.1",
77
+ "10.33.2",
78
+ "10.33.4",
79
+ "10.34.7"
80
+ ],
81
+ "template": "#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\n\ncase `uname` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir=`cygpath -w \"$basedir\"`\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n"
82
+ },
83
+ {
84
+ "versions": [
85
+ "11.0.9",
86
+ "11.1.1",
87
+ "11.1.3",
88
+ "11.2.2",
89
+ "11.3.0",
90
+ "11.4.0",
91
+ "11.5.3",
92
+ "11.6.0"
93
+ ],
94
+ "template": "#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\n\ncase `uname` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir=`cygpath -w \"$basedir\"`\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
95
+ },
96
+ {
97
+ "versions": [
98
+ "11.7.0",
99
+ "11.8.0",
100
+ "11.9.0",
101
+ "11.10.0",
102
+ "11.11.0",
103
+ "11.12.0",
104
+ "11.13.1",
105
+ "11.14.0",
106
+ "11.15.1",
107
+ "11.16.0",
108
+ "11.17.0",
109
+ "11.18.0",
110
+ "11.19.0",
111
+ "11.20.0"
112
+ ],
113
+ "template": "#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
114
+ },
115
+ {
116
+ "versions": [
117
+ "11.21.0",
118
+ "11.22.0",
119
+ "11.23.0",
120
+ "11.24.0",
121
+ "11.25.0",
122
+ "11.26.0",
123
+ "12.0.0",
124
+ "12.1.0",
125
+ "12.2.1",
126
+ "12.3.4"
127
+ ],
128
+ "template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\nlink=\"$0\"\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"$(dirname \"$link\")/$target\" ;;\n esac\ndone\nbasedir=$(dirname \"$(echo \"$link\" | sed -e 's,\\\\,/,g')\")\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
129
+ },
130
+ {
131
+ "versions": [
132
+ "11.27.1"
133
+ ],
134
+ "template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(command -p printf '%s\\n' \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if converted=$(command -p cygpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n elif command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if converted=$(command -p wslpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n exe=\".exe\"\n elif command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
135
+ },
136
+ {
137
+ "versions": [
138
+ "11.28.2"
139
+ ],
140
+ "template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\n#\n# Where no default path is compiled in, as on Nix, `command -p` searches PATH\n# instead, so the helpers run with node_modules and relative entries dropped from\n# PATH.\ncaller_path_set=${PATH+set}\ncaller_path=${PATH-}\nhelper_path=\nrest=$caller_path:\nwhile [ -n \"$rest\" ]; do\n dir=${rest%%:*}\n rest=${rest#*:}\n case \"$dir\" in\n */node_modules/*|*/node_modules) ;;\n /*) helper_path=${helper_path:+$helper_path:}$dir ;;\n esac\ndone\n# An empty PATH searches the current directory.\nPATH=${helper_path:-/}\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(command -p printf '%s\\n' \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_abs=$(CDPATH= cd -P -- \"$basedir\" && pwd -P) || exit $?\nbasedir=\"$basedir_abs\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if converted=$(command -p cygpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n elif command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if converted=$(command -p wslpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n exe=\".exe\"\n elif command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\nif [ -n \"$caller_path_set\" ]; then PATH=$caller_path; else unset PATH; fi\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$msys\" ] && command -v node >/dev/null 2>&1; then\n exec node \"$basedir_win/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
141
+ },
142
+ {
143
+ "versions": [
144
+ "11.28.6",
145
+ "12.8.2",
146
+ "12.9.1",
147
+ "12.10.1",
148
+ "12.11.2",
149
+ "12.12.1",
150
+ "12.13.0",
151
+ "12.14.0"
152
+ ],
153
+ "template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\n#\n# A helper the default path lacks, as in a Nix build sandbox, comes from PATH\n# instead, with node_modules and relative entries dropped from it.\ncaller_path_set=${PATH+set}\ncaller_path=${PATH-}\nhelper_path=\nrest=$caller_path:\nwhile [ -n \"$rest\" ]; do\n dir=${rest%%:*}\n rest=${rest#*:}\n case \"$dir\" in\n */node_modules/*|*/node_modules) ;;\n /*) helper_path=${helper_path:+$helper_path:}$dir ;;\n esac\ndone\n# An empty PATH searches the current directory.\nPATH=${helper_path:-/}\n# A helper comes from PATH only when the default path lacks it and PATH has it.\n# The bash 3.2 that macOS ships as sh answers `command -p -v` from PATH.\nrun_helper() {\n if command -p -v \"$1\" >/dev/null 2>&1 || ! command -v \"$1\" >/dev/null 2>&1; then command -p \"$@\"; else command \"$@\"; fi\n}\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(run_helper readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(run_helper printf '%s\\n' \"$link\" | run_helper sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_abs=$(CDPATH= cd -P -- \"$basedir\" && pwd -P) || exit $?\nbasedir=\"$basedir_abs\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `run_helper uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if converted=$(command -p cygpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n elif command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if converted=$(command -p wslpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n exe=\".exe\"\n elif command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\nif [ -n \"$caller_path_set\" ]; then PATH=$caller_path; else unset PATH; fi\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$msys\" ] && command -v node >/dev/null 2>&1; then\n exec node \"$basedir_win/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
154
+ },
155
+ {
156
+ "versions": [
157
+ "12.4.2"
158
+ ],
159
+ "template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed, and\n# uname go through `command -p`, which searches the system default path instead.\n# A dependency's bin cannot stand in for one of them and take over the shim\n# before it reaches its target. Directories come from `${link%/*}`, which needs\n# no helper at all.\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(echo \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
160
+ },
161
+ {
162
+ "versions": [
163
+ "12.5.1"
164
+ ],
165
+ "template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(command -p printf '%s\\n' \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
166
+ },
167
+ {
168
+ "versions": [
169
+ "12.6.0"
170
+ ],
171
+ "template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(command -p printf '%s\\n' \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if converted=$(command -p cygpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n elif command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if converted=$(command -p wslpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n exe=\".exe\"\n elif command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\n\nbasedir_abs=$(CDPATH= cd -P -- \"$basedir\" && pwd -P) || exit $?\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
172
+ },
173
+ {
174
+ "versions": [
175
+ "12.7.0"
176
+ ],
177
+ "template": "#!/bin/sh\n# Resolve $0 through symlinks so basedir is the shim's real directory.\n# Cap hops at the kernel's ELOOP limit so a cycle cannot hang the shim.\n#\n# A shim runs with node_modules/.bin at the front of PATH, so readlink, sed,\n# uname, and printf go through `command -p`, which searches the system default\n# path instead. A dependency's bin cannot stand in for one of them and take over\n# the shim before it reaches its target. Directories come from `${link%/*}`,\n# which needs no helper at all.\n#\n# Where no default path is compiled in, as on Nix, `command -p` searches PATH\n# instead, so the helpers run with node_modules and relative entries dropped from\n# PATH.\ncaller_path_set=${PATH+set}\ncaller_path=${PATH-}\nhelper_path=\nrest=$caller_path:\nwhile [ -n \"$rest\" ]; do\n dir=${rest%%:*}\n rest=${rest#*:}\n case \"$dir\" in\n */node_modules/*|*/node_modules) ;;\n /*) helper_path=${helper_path:+$helper_path:}$dir ;;\n esac\ndone\n# An empty PATH searches the current directory.\nPATH=${helper_path:-/}\nlink=\"$0\"\n# `${link%/*}` needs a separator to strip. A bare name came from a PATH lookup\n# and stands for a file in the current directory.\ncase \"$link\" in\n */*|*\\\\*) ;;\n *) link=\"./$link\" ;;\nesac\nhops=0\nwhile [ -L \"$link\" ] && [ \"$hops\" -lt 40 ]; do\n hops=$((hops+1))\n target=$(command -p readlink \"$link\")\n case \"$target\" in\n /*) link=\"$target\" ;;\n *) link=\"${link%/*}/$target\" ;;\n esac\ndone\nbasedir=$(command -p printf '%s\\n' \"$link\" | command -p sed -e 's,\\\\,/,g')\nbasedir=\"${basedir%/*}\"\nbasedir_win=\"$basedir\"\nexe=\"\"\nmsys=\"\"\n\ncase `command -p uname -a` in\n *CYGWIN*|*MINGW*|*MSYS*)\n if converted=$(command -p cygpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n elif command -v cygpath > /dev/null 2>&1; then\n basedir_win=`cygpath -w \"$basedir\"`\n fi\n exe=\".exe\"\n msys=\"true\"\n ;;\n *WSL2*)\n if converted=$(command -p wslpath -w \"$basedir\" 2>/dev/null) && [ -n \"$converted\" ]; then\n basedir_win=\"$converted\"\n exe=\".exe\"\n elif command -v wslpath > /dev/null 2>&1; then\n basedir_win=\"$(wslpath -w \"$basedir\" 2> /dev/null)\"\n if [ $? -ne 0 ] || [ -z \"$basedir_win\" ]; then\n basedir_win=\"$basedir\"\n else\n exe=\".exe\"\n fi\n fi\n ;;\nesac\nif [ -n \"$caller_path_set\" ]; then PATH=$caller_path; else unset PATH; fi\n\nbasedir_abs=$(CDPATH= cd -P -- \"$basedir\" && pwd -P) || exit $?\nif [ -z \"$NODE_PATH\" ]; then\n export NODE_PATH=\"@@NODE_PATH@@\"\nelse\n export NODE_PATH=\"@@NODE_PATH@@:$NODE_PATH\"\nfi\nif [ -n \"$exe\" ] && [ -x \"$basedir/node.exe\" ]; then\n exec \"$basedir/node.exe\" \"$basedir_win/@@TARGET@@\" \"$@\"\nelif [ -x \"$basedir/node\" ]; then\n exec \"$basedir/node\" \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif command -v node >/dev/null 2>&1; then\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nelif [ -n \"$exe\" ] && command -v node.exe >/dev/null 2>&1; then\n exec node.exe \"$basedir_win/@@TARGET@@\" \"$@\"\nelse\n exec node \"$basedir_abs/@@TARGET@@\" \"$@\"\nfi\n# cmd-shim-target=@@COMMENT@@\n"
178
+ }
179
+ ]
180
+ }