@redue/cli 0.1.0-alpha.3 → 0.1.0-alpha.30

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 (67) hide show
  1. package/CHANGELOG.md +806 -0
  2. package/README.md +157 -99
  3. package/bin/redue.mjs +267 -61
  4. package/docs/README.md +3 -1
  5. package/docs/user/agents.md +333 -15
  6. package/docs/user/configuration.md +28 -2
  7. package/docs/user/direct-typescript.md +219 -0
  8. package/docs/user/getting-started.md +49 -7
  9. package/docs/user/json.md +4 -2
  10. package/docs/user/node-script.md +177 -0
  11. package/docs/user/npm-launcher-notice.md +42 -0
  12. package/docs/user/pilot.md +146 -0
  13. package/docs/user/sandbox.md +312 -0
  14. package/docs/user/shell.md +3 -3
  15. package/docs/user/supported-projects.md +69 -23
  16. package/docs/user/tests-direct.md +143 -0
  17. package/package.json +4 -3
  18. package/src/agent-integration.mjs +467 -0
  19. package/src/agent-policy.md +28 -0
  20. package/src/cached-state.mjs +24 -1
  21. package/src/claude-hook.mjs +616 -0
  22. package/src/cli.mjs +449 -54
  23. package/src/daemon.mjs +442 -93
  24. package/src/decision-profile.mjs +15 -1
  25. package/src/decision-validation.mjs +12 -1
  26. package/src/declared-plan.mjs +38 -6
  27. package/src/direct-run-certificate.mjs +254 -0
  28. package/src/direct-typescript-probe.mjs +27 -0
  29. package/src/direct-typescript.mjs +205 -0
  30. package/src/glob.mjs +8 -0
  31. package/src/history-worker.mjs +21 -13
  32. package/src/index.mjs +108 -21
  33. package/src/installed-inputs.mjs +7 -1
  34. package/src/installed-observation.mjs +23 -0
  35. package/src/landlock.py +527 -0
  36. package/src/linux-inotify.py +39 -10
  37. package/src/node-onboarding.mjs +203 -54
  38. package/src/node-script.mjs +406 -0
  39. package/src/npm-integrity.mjs +124 -0
  40. package/src/npm-typecheck-environment.mjs +36 -0
  41. package/src/npmrc.mjs +16 -0
  42. package/src/observation.mjs +34 -12
  43. package/src/path-identity.mjs +8 -0
  44. package/src/plan-worker.mjs +17 -17
  45. package/src/pnpm-inputs.mjs +122 -57
  46. package/src/pnpm-shim-templates.json +180 -0
  47. package/src/pnpm-shims.mjs +54 -0
  48. package/src/pnpm-typecheck-probe.mjs +11 -6
  49. package/src/presentation.mjs +13 -4
  50. package/src/probe-deadline.mjs +37 -0
  51. package/src/probe-result.mjs +7 -3
  52. package/src/project-location.mjs +34 -0
  53. package/src/python-onboarding.mjs +89 -0
  54. package/src/run-recorder.cjs +91 -0
  55. package/src/sandbox.mjs +653 -0
  56. package/src/setup.mjs +205 -0
  57. package/src/stats.mjs +72 -0
  58. package/src/test-direct.mjs +608 -0
  59. package/src/test-recorder.cjs +435 -0
  60. package/src/typescript-contract-probe.mjs +4 -187
  61. package/src/typescript-input-facts.mjs +92 -0
  62. package/src/typescript-invocation.mjs +92 -0
  63. package/src/typescript-list.mjs +118 -13
  64. package/src/typescript-qualification.mjs +29 -49
  65. package/src/workspace-manifests.mjs +24 -0
  66. package/src/yarn-workspace-inputs.mjs +3 -0
  67. package/src/yarn-workspace-typecheck-probe.mjs +2 -1
@@ -0,0 +1,91 @@
1
+ // Preload for a direct compiler run: node --require <this> <tsc> ... with a
2
+ // pipe on fd 3. Records the answers the compiler received from node:fs, in the
3
+ // terms of queryAnswer, and writes them to fd 3 at exit. It never changes an
4
+ // answer, an output or the exit code; any failure only makes the record unusable.
5
+ 'use strict';
6
+ const fs=require('node:fs'),path=require('node:path'),{createHash}=require('node:crypto');
7
+ const original={readFileSync:fs.readFileSync,statSync:fs.statSync,readdirSync:fs.readdirSync,
8
+ realpathSync:fs.realpathSync,native:fs.realpathSync.native,writeSync:fs.writeSync,openSync:fs.openSync};
9
+ const real=file=>(process.platform==='win32'?original.native:original.realpathSync)(file);
10
+ const facts=new Map(),compilerReads=new Set();let unsupported=null,conflict=null,main=null,compilerRoot=null;
11
+ try{main=real(process.argv[1]);compilerRoot=path.dirname(path.dirname(main));}
12
+ catch{unsupported='main module unavailable';}
13
+ const kindOf=st=>st.isFile()?'f':st.isDirectory()?'d':'o';
14
+ const missing=error=>['ENOENT','ENOTDIR'].includes(error?.code);
15
+ // The compiler tree (lib/<entry>/../..) is covered by the daemon's toolchain
16
+ // identity, not by this record. tsc also stats a case-swapped copy of its own path.
17
+ const inCompiler=full=>full===compilerRoot||full.startsWith(compilerRoot+path.sep)||
18
+ full!==main&&full.toLowerCase()===main.toLowerCase();
19
+ function observe(kind,call,answer) {
20
+ return function(file,...rest){
21
+ let value,full=null;
22
+ // Compiler-tree reads are named only: which lib files a program loads.
23
+ try{if(typeof file==='string'){full=path.resolve(file);
24
+ if(inCompiler(full)){if(kind==='read')compilerReads.add(full);full=null;}}
25
+ else unsupported??=`${kind} of a non-string path`;}
26
+ catch{unsupported??='recorder failure';}
27
+ if(full===null)return call.call(this,file,...rest);
28
+ let recorded;
29
+ try{value=call.call(this,file,...rest);}
30
+ catch(error){recorded=missing(error)?null:{error:error?.code||'error'};note(kind,full,recorded);throw error;}
31
+ try{recorded=answer(value,file);}catch{unsupported??='recorder failure';return value;}
32
+ note(kind,full,recorded);
33
+ return value;
34
+ };
35
+ }
36
+ function note(kind,full,answer) {
37
+ try{const key=kind+'\0'+full,value=JSON.stringify(answer),seen=facts.get(key);
38
+ if(seen===undefined)facts.set(key,value);else if(seen!==value)conflict??=`${kind} ${full}`;}
39
+ catch{unsupported??='recorder failure';}
40
+ }
41
+ fs.readFileSync=observe('read',original.readFileSync,value=>
42
+ createHash('sha256').update(JSON.stringify(typeof value==='string'?value:value.toString('utf8'))).digest('hex'));
43
+ fs.statSync=observe('stat',original.statSync,value=>value?kindOf(value):null);
44
+ fs.readdirSync=observe('readdir',original.readdirSync,(value,dir)=>value.map(entry=>{
45
+ if(typeof entry==='string')return [entry,'?'];
46
+ if(!entry.isSymbolicLink())return [entry.name,kindOf(entry)];
47
+ let target=null;try{target=kindOf(original.statSync(path.join(dir,entry.name)));}catch{}
48
+ return [entry.name,'l',target];
49
+ }).sort((a,b)=>a[0]<b[0]?-1:a[0]>b[0]?1:0));
50
+ const realpath=observe('realpath',original.realpathSync,value=>value);
51
+ realpath.native=observe('realpath',original.native,value=>value);
52
+ fs.realpathSync=realpath;
53
+ // readFileSync opens through fs.openSync; only a writable open is a write.
54
+ // The one write a direct run may make is its build-info file (incremental);
55
+ // it is recorded, and the caller checks it is the configured one.
56
+ const buildInfo=file=>typeof file==='string'&&file.endsWith('.tsbuildinfo');
57
+ fs.openSync=function(file,flags,...rest){
58
+ if(!(flags===undefined||flags==='r'||flags==='rs'||flags===fs.constants.O_RDONLY)){
59
+ if(flags==='w'&&buildInfo(file))note('write',path.resolve(file),null);
60
+ else unsupported??='openSync';
61
+ }
62
+ return original.openSync.call(this,file,flags,...rest);
63
+ };
64
+ // tsc creates the build-info directory one level at a time; each is recorded.
65
+ const mkdirSync=fs.mkdirSync;
66
+ fs.mkdirSync=function(file,options,...rest){
67
+ if(typeof file==='string'&&options===undefined)note('mkdir',path.resolve(file),null);
68
+ else unsupported??='mkdirSync';
69
+ return mkdirSync.call(this,file,options,...rest);
70
+ };
71
+ // Writes, and reads this record cannot answer for, make it unusable. readSync
72
+ // and fstatSync stay open: readFileSync reads through them.
73
+ for(const name of ['writeFileSync','appendFileSync','unlinkSync','utimesSync',
74
+ 'renameSync','rmSync','watch','watchFile','existsSync','lstatSync','accessSync','opendirSync',
75
+ 'readlinkSync','readFile','stat','lstat','readdir','realpath','access','exists','open','opendir',
76
+ 'readlink','createReadStream']){
77
+ const call=fs[name];
78
+ fs[name]=Object.assign(function(...args){unsupported??=name;return call.apply(this,args);},call);
79
+ }
80
+ for(const name of ['readFile','stat','lstat','readdir','realpath','access','open','opendir','readlink']){
81
+ const call=fs.promises[name];
82
+ fs.promises[name]=function(...args){unsupported??=`promises.${name}`;return call.apply(this,args);};
83
+ }
84
+ process.on('exit',()=>{
85
+ try{
86
+ const buffer=Buffer.from(JSON.stringify({schema:1,node:[real(process.execPath),process.version],main,
87
+ unsupported,conflict,compilerReads:[...compilerReads],facts:[...facts].map(([key,value])=>{const at=key.indexOf('\0');
88
+ return [key.slice(0,at),key.slice(at+1),JSON.parse(value)];})}));
89
+ for(let at=0;at<buffer.length;)at+=original.writeSync(3,buffer,at,buffer.length-at);
90
+ }catch{}
91
+ });