alchemylab 2.3.0 → 3.0.1
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.
- package/README.md +0 -1
- package/dist/24.js +3 -1
- package/dist/414.js +43 -17
- package/dist/478.js +13 -53
- package/dist/579.js +13 -9
- package/dist/60.js +10 -10
- package/dist/776.js +30 -22
- package/dist/9.js +26 -0
- package/dist/902.js +26 -0
- package/dist/912.js +30 -16
- package/dist/994.js +84 -83
- package/dist/cli.js +5402 -3095
- package/dist/document-textconv.js +174 -115
- package/dist/http-server.js +2934 -2195
- package/dist/index.js +2985 -2246
- package/dist/mcp-direct.js +2910 -2131
- package/dist/plugins/hooks/plugin.js +1 -1
- package/package.json +13 -21
|
@@ -6,82 +6,96 @@ return t[n].call(module.exports,module,module.exports,e),module.loaded=!0,module
|
|
|
6
6
|
const t=String(e??"").trim().toLowerCase().match(/^(\d+(?:\.\d+)?)\s*([bkmg]?)b?$/)
|
|
7
7
|
if(!t)return NaN
|
|
8
8
|
const r={"":1,b:1,k:1024,m:1048576,g:1024**3}[t[2]]
|
|
9
|
-
return Math.round(parseFloat(t[1])*r)}function n(e,t,r,n){return e>0&&r>0?t+r<=e?null:`Not started: this ${n} needs ${
|
|
10
|
-
|
|
9
|
+
return Math.round(parseFloat(t[1])*r)}function n(e,t,r,n){return e>0&&r>0?t+r<=e?null:`Not started: this ${n} needs ${p(r)} of memory, and the boxes already running on this machine have ${p(t)} of the ${p(e)} Docker can give. Stop a box you no longer need (experiment_list shows yours) or try again when one ends.`:null}async function o(){const e=r(process.env.ALCHEMY_BOX_MEMORY_BUDGET)
|
|
10
|
+
if(e>0)return e
|
|
11
|
+
const t=await(0,d.docker)(["info","--format","{{.MemTotal}}"],d.DOCKER_OP_TIMEOUT_MS)
|
|
12
|
+
return 0===t.exit?Number(t.stdout.trim()):NaN}function s(e){if(!Number.isInteger(e)||e<=0)return!0
|
|
13
|
+
try{return process.kill(e,0),!0}catch(e){return"EPERM"===e?.code}}function a(e,t,r=s){return!(!e||!f.has(t)||r(Number(e)))}async function i(){const e=await(0,d.docker)(["ps","-a","--filter","label=alchemy.project","--filter","status=running","--filter","status=created","--format",'{{.ID}}\t{{.Label "alchemy.owner"}}\t{{.Label "alchemy.sandbox"}}'],d.DOCKER_OP_TIMEOUT_MS)
|
|
11
14
|
if(0!==e.exit)return 0
|
|
12
15
|
const t=[]
|
|
13
16
|
for(const r of e.stdout.split("\n").map(e=>e.trim()).filter(Boolean)){const[e,n="",o=""]=r.split("\t")
|
|
14
|
-
|
|
15
|
-
const r=await(0,
|
|
16
|
-
return 0!==r.exit?0:r.stdout.split("\n").map(e=>Number(e.trim())||0).reduce((e,t)=>e+t,0)}function
|
|
17
|
+
a(n,o)?await(0,d.docker)(["rm","-f","-v",e],d.DOCKER_OP_TIMEOUT_MS):t.push(e)}if(!t.length)return 0
|
|
18
|
+
const r=await(0,d.docker)(["inspect","--format","{{.HostConfig.Memory}}",...t],d.DOCKER_OP_TIMEOUT_MS)
|
|
19
|
+
return 0!==r.exit?0:r.stdout.split("\n").map(e=>Number(e.trim())||0).reduce((e,t)=>e+t,0)}async function c(e,t,s=exports.ROOM_WAIT_MS,a=5e3,c=i,l=o){try{const o=r(e),i=await l(),u=Date.now()+s
|
|
20
|
+
for(function(){const e=(0,d.containerLabels)()
|
|
21
|
+
"check"===e["alchemy.purpose"]&&e["alchemy.request"]}();;){const e=n(i,await c(),o,t)
|
|
22
|
+
if(!e)return null
|
|
23
|
+
if(Date.now()>=u)return e
|
|
24
|
+
await new Promise(e=>setTimeout(e,a))}}catch{return null}}function l(e){const t=[]
|
|
17
25
|
for(const r of String(e||"").split(",").map(e=>e.trim()).filter(Boolean)){const e=r.match(/^(\d+)(?:-(\d+))?$/)
|
|
18
26
|
if(!e)continue
|
|
19
27
|
const n=Number(e[1]),o=void 0!==e[2]?Number(e[2]):n
|
|
20
|
-
for(let e=n;e<=o&&e-n<1024;e++)t.push(e)}return t}function
|
|
21
|
-
for(const t of r)for(const r of
|
|
22
|
-
return[...n.keys()].sort((e,t)=>n[e]-n[t]||e-t).slice(0,t).sort((e,t)=>e-t)}exports.TS=void 0,exports.withAdmission=function(e,t,
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
return
|
|
26
|
-
|
|
27
|
-
if(!e||Date.now()>=u)return e
|
|
28
|
-
await new Promise(e=>setTimeout(e,s))}}catch{return null}}(e,t)
|
|
29
|
-
return s?{refused:s}:{value:await o()}})
|
|
30
|
-
return p=s.catch(()=>{}),s},exports.pickCores=async function(e,t,r="standard"){try{const n=await(0,l.docker)(["info","--format","{{.NCPU}}"],l.DOCKER_OP_TIMEOUT_MS),o=Number(n.stdout.trim())
|
|
28
|
+
for(let e=n;e<=o&&e-n<1024;e++)t.push(e)}return t}function u(e,t,r){const n=new Array(e).fill(0)
|
|
29
|
+
for(const t of r)for(const r of l(t))r<e&&n[r]++
|
|
30
|
+
return[...n.keys()].sort((e,t)=>n[e]-n[t]||e-t).slice(0,t).sort((e,t)=>e-t)}exports.TS=exports.FY=exports.ROOM_WAIT_MS=exports.Lt=exports.kz=exports.IDLE_GRACE_MS=void 0,exports.waitForRoom=c,exports.withAdmission=function(e,t,r,n){h++,h>1&&n?.(`waiting behind ${h-1} other box start(s)`,(h-1)*exports.FY)
|
|
31
|
+
const o=m.then(async()=>{n?.("waiting for room to start its box",exports.FY)
|
|
32
|
+
const o=await c(e,t)
|
|
33
|
+
return o?{refused:o}:{value:await r()}})
|
|
34
|
+
return m=o.catch(()=>{}),o.catch(()=>{}).then(()=>{h--}),o},exports.pickCores=async function(e,t,r="standard"){try{const n=await(0,d.docker)(["info","--format","{{.NCPU}}"],d.DOCKER_OP_TIMEOUT_MS),o=Number(n.stdout.trim())
|
|
31
35
|
if(!(o>0))return{cpus:e??t}
|
|
32
|
-
const s=await(0,
|
|
33
|
-
return Math.min(r,Math.max(2,Math.ceil(t/2)))}(t,r)}(r,o,o-
|
|
34
|
-
return f>=o?{cpus:p}:{cpus:p,cpuset:
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
36
|
+
const s=await(0,d.docker)(["ps","-a","-q","--filter","label=alchemy.project","--filter","status=running","--filter","status=created"],d.DOCKER_OP_TIMEOUT_MS),a=0===s.exit?s.stdout.split("\n").map(e=>e.trim()).filter(Boolean):[],i=a.length?(await(0,d.docker)(["inspect","--format","{{.HostConfig.CpusetCpus}}",...a],d.DOCKER_OP_TIMEOUT_MS)).stdout.split("\n").map(e=>e.trim()).filter(Boolean):[],c=new Set(i.flatMap(l).filter(e=>e<o)),p=e??function(e,t,r){return"light"===e?2:"heavy"===e?Math.max(2,Math.min(t-2,r-2)):function(e,t){const r=Math.max(2,Math.floor(e/2))
|
|
37
|
+
return Math.min(r,Math.max(2,Math.ceil(t/2)))}(t,r)}(r,o,o-c.size),f=Math.max(1,Math.ceil(p))
|
|
38
|
+
return f>=o?{cpus:p}:{cpus:p,cpuset:u(o,f,i).join(",")}}catch{return{cpus:e??t}}}
|
|
39
|
+
const d=t(81618),p=e=>`${(e/1024**3).toFixed(1)} GB`,f=new Set(["experiment","rung1","deps","egress-proxy","service"])
|
|
40
|
+
exports.IDLE_GRACE_MS=3e5,exports.kz=6e4,exports.Lt=3e4,exports.ROOM_WAIT_MS=12e4
|
|
41
|
+
let m=Promise.resolve(),h=0
|
|
42
|
+
exports.FY=exports.ROOM_WAIT_MS+6*d.DOCKER_OP_TIMEOUT_MS,exports.TS=["light","standard","heavy"]},52429(e,exports,t){exports.ContainerRunner=void 0
|
|
43
|
+
const r=t(81618),n=t(83129),o=t(22604),s=t(11895),a=t(26166),i=t(2566),c=t(90695),l=t(61260),u=6e5
|
|
44
|
+
exports.ContainerRunner=class{constructor(e={}){this.image=e.image??"node:20-alpine",this.stepTimeoutMs=e.stepTimeoutMs??12e4,this.network=e.network??"none",this.resources=e.resources??{},this.memory=(0,s.memoryForBox)(this.resources.memory,this.resources.size)}async run(e){if(!e.worktreePath)return{steps:[],ok:!1,error:"worktreePath is required"}
|
|
45
|
+
const t=e.image??this.image,a={}
|
|
46
|
+
let d=Date.now()
|
|
47
|
+
const p=e=>{const t=Date.now()
|
|
48
|
+
a[e]=(a[e]??0)+(t-d),d=t},f=e.onStep??(()=>{})
|
|
49
|
+
f("getting its image",r.DOCKER_OP_TIMEOUT_MS+((0,n.localRecipeFor)(t)?n.BUILD_TIMEOUT_MS:r.PULL_TIMEOUT_MS))
|
|
50
|
+
const m=await(0,r.ensureImage)(t)
|
|
51
|
+
if(p("image"),m)return{steps:[],ok:!1,error:m}
|
|
52
|
+
if("background"===this.resources.priority){f("waiting for room to start its box",u+r.DOCKER_OP_TIMEOUT_MS)
|
|
53
|
+
const e=await(0,o.waitForRoom)(this.memory,"check of main",u)
|
|
54
|
+
if(p("room"),e)return{steps:[],ok:!1,error:e}}const h=await(0,o.withAdmission)(this.memory,"check",async()=>{const{cpus:n,cpuset:a}=await(0,o.pickCores)(this.resources.cpus,s.DEFAULT_CPUS,this.resources.size)
|
|
55
|
+
let i=await(0,r.docker)(this.createArgs(e,t,!0,a,n),r.DOCKER_OP_TIMEOUT_MS)
|
|
56
|
+
if(0!==i.exit)return{error:i.spawnError??`docker create failed: ${(i.stderr||String(i.exit)).trim()}`}
|
|
57
|
+
let l=i.stdout.trim()
|
|
58
|
+
if(p("create"),await(0,c.claimScratch)(l,t,"1000:1000")){if(await(0,r.docker)(["rm","-f","-v",l],r.DOCKER_OP_TIMEOUT_MS),i=await(0,r.docker)(this.createArgs(e,t,!1,a,n),r.DOCKER_OP_TIMEOUT_MS),0!==i.exit)return{error:i.spawnError??`docker create failed: ${(i.stderr||String(i.exit)).trim()}`}
|
|
59
|
+
l=i.stdout.trim()}return p("scratch"),{id:l}},f)
|
|
60
|
+
if("refused"in h)return{steps:[],ok:!1,error:h.refused}
|
|
61
|
+
if("error"in h.value)return{steps:[],ok:!1,error:h.value.error}
|
|
62
|
+
const w=h.value.id
|
|
63
|
+
try{f("starting its box",2*r.DOCKER_OP_TIMEOUT_MS)
|
|
64
|
+
const t=await(0,r.docker)(["start",w],r.DOCKER_OP_TIMEOUT_MS)
|
|
65
|
+
if(p("start"),0!==t.exit)return{steps:[],ok:!1,error:`docker start failed: ${(t.stderr||String(t.exit)).trim()}`}
|
|
56
66
|
const n=[]
|
|
57
|
-
let o=await(0,
|
|
58
|
-
for(const t of e.steps){const s=Date.now(),
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
await(0,r.
|
|
63
|
-
|
|
67
|
+
let o=await(0,l.readOomKills)(w)??0
|
|
68
|
+
for(const t of e.steps){const s=Date.now(),a=void 0!==e.deadlineAt?e.deadlineAt-s:1/0
|
|
69
|
+
if(a<=0){n.push({run:t.run,exit:-1,stdout:"",stderr:"",ms:0,timedOut:!0})
|
|
70
|
+
continue}const c=Math.min(t.timeoutMs??this.stepTimeoutMs,a)
|
|
71
|
+
f(`running \`${t.run.replace(/\s+/g," ").slice(0,80)}\``,c+1e4)
|
|
72
|
+
const u=await(0,r.dockerKeepingEnds)(["exec","-e",`${i.RUN_ENV_VAR}=${(0,i.withShellInit)(e.shellInit,t.run)}`,w,"/bin/sh","-c",i.RUN_FROM_ENV],c),d=Date.now()-s,p=await(0,l.readOomKills)(w),m=null!=p?Math.max(0,p-o):0
|
|
73
|
+
null!=p&&(o=p)
|
|
74
|
+
const h=m>0?`${u.stderr}${u.stderr&&!u.stderr.endsWith("\n")?"\n":""}${(0,l.oomNote)(m,this.memory)}\n`:u.stderr
|
|
75
|
+
if(n.push({run:t.run,exit:u.exit,stdout:u.stdout,stderr:h,ms:d,timedOut:u.timedOut,...m>0?{oomKills:m}:{}}),t.stopOnFail&&0!==u.exit)break}return p("commands"),{steps:n,ok:n.every(e=>0===e.exit),phaseMs:a}}finally{const e=Date.now()
|
|
76
|
+
f("removing its box",r.DOCKER_OP_TIMEOUT_MS),await(0,r.docker)(["rm","-f","-v",w],r.DOCKER_OP_TIMEOUT_MS),a.remove=Date.now()-e}}createArgs(e,t,r,n,o){const i=Object.entries(e.env??{}).flatMap(([e,t])=>["-e",`${e}=${t}`]),l=e.depsVolume?["-v",`${e.depsVolume}:/work/node_modules`]:[],u=(e.mounts??[]).flatMap(e=>["-v",`${e.volume}:${e.target}`]),d=(e.readOnlyBinds??[]).flatMap(e=>["-v",`${e.host}:${e.target}:ro`])
|
|
77
|
+
return["create","--label","alchemy.sandbox=rung1",...(0,a.hardenedCreateArgs)({network:this.network,user:"1000:1000",...r?{}:{extraTmpfs:[(0,c.scratchTmpfsArg)(512)]},shmSizeMb:this.resources.shmSizeMb,memory:this.memory,cpus:o??this.resources.cpus??s.DEFAULT_CPUS,cpuset:n,pidsLimit:this.resources.pidsLimit??512}),..."background"===this.resources.priority?["--cpu-shares",String(128)]:[],...r?c.SCRATCH_VOLUME_ARGS:[],...i,"-v",`${e.worktreePath}:/work:rw`,...l,...u,...d,"-w","/work",t,"tail","-f","/dev/null"]}}},81618(e,exports,t){function r(){return{"alchemy.owner":String(process.pid),...u.getStore()??{}}}function n(e){if("create"!==e[0]&&"run"!==e[0])return e
|
|
64
78
|
const t=new Set
|
|
65
79
|
e.forEach((r,n)=>{"--label"===e[n-1]&&t.add(r.split("=")[0])})
|
|
66
|
-
const
|
|
67
|
-
return
|
|
80
|
+
const n=Object.entries(r()).filter(([e])=>!t.has(e)).flatMap(([e,t])=>["--label",`${e}=${t.replace(/[\r\n]/g," ").slice(0,200)}`])
|
|
81
|
+
return n.length?[e[0],...n,...e.slice(1)]:e}function o(e,t){return new Promise(r=>{(0,s.execFile)("docker",n(e),{timeout:t,killSignal:"SIGKILL",maxBuffer:33554432,windowsHide:!0},(e,t,n)=>{if(!e)return void r({exit:0,stdout:t,stderr:n,timedOut:!1})
|
|
68
82
|
const o=e
|
|
69
|
-
if("ENOENT"===o.code)return void
|
|
83
|
+
if("ENOENT"===o.code)return void r({exit:-1,stdout:t??"",stderr:n??"",timedOut:!1,spawnError:"docker CLI not found on PATH"})
|
|
70
84
|
const s=!0===o.killed||"SIGKILL"===o.signal,a="number"==typeof o.code?o.code:-1
|
|
71
|
-
|
|
72
|
-
let
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
if(t)return(0,
|
|
78
|
-
const r=await
|
|
85
|
+
r({exit:a,stdout:t??"",stderr:n??"",timedOut:s})})})}exports.PULL_TIMEOUT_MS=exports.DOCKER_OP_TIMEOUT_MS=void 0,exports.containerLabels=r,exports.dockerKeepingEnds=function(e,t,r=524288){return new Promise(o=>{const a=new c.EndsKeeper(r),i=new c.EndsKeeper(r)
|
|
86
|
+
let u=!1,d=!1
|
|
87
|
+
const p=(0,s.spawn)("docker",n(e),{windowsHide:!0}),f=(0,l.awakeTimeout)(()=>{u=!0,p.kill("SIGKILL")},t)
|
|
88
|
+
p.stdout.setEncoding("utf8").on("data",e=>a.push(e)),p.stderr.setEncoding("utf8").on("data",e=>i.push(e))
|
|
89
|
+
const m=e=>{d||(d=!0,f.clear(),o(e))}
|
|
90
|
+
p.on("error",e=>m({exit:-1,stdout:a.text(),stderr:i.text(),timedOut:!1,..."ENOENT"===e.code?{spawnError:"docker CLI not found on PATH"}:{spawnError:e.message}})),p.on("close",e=>m({exit:u?-1:e??-1,stdout:a.text(),stderr:i.text(),timedOut:u}))})},exports.docker=o,exports.ensureImage=async function(e){const t=(0,i.localRecipeFor)(e)
|
|
91
|
+
if(t)return(0,i.ensureLocalImage)(t)
|
|
92
|
+
const r=await o(["image","inspect",e],exports.DOCKER_OP_TIMEOUT_MS)
|
|
79
93
|
if(r.spawnError)return r.spawnError
|
|
80
94
|
if(0===r.exit)return
|
|
81
|
-
const
|
|
82
|
-
return 0!==
|
|
83
|
-
const
|
|
84
|
-
exports.DOCKER_OP_TIMEOUT_MS=6e4,exports.
|
|
95
|
+
const n=await o(["pull",e],exports.PULL_TIMEOUT_MS)
|
|
96
|
+
return 0!==n.exit?`docker pull ${e} failed: ${(n.stderr||String(n.exit)).trim()}`:void 0}
|
|
97
|
+
const s=t(31421),a=t(16698),i=t(83129),c=t(88196),l=t(4334),u=new a.AsyncLocalStorage
|
|
98
|
+
exports.DOCKER_OP_TIMEOUT_MS=6e4,exports.PULL_TIMEOUT_MS=3e5},26166(e,exports){exports.hardenedCreateArgs=function(e){return["--network",e.network,"--user",e.user,"--cap-drop","ALL",...(e.capAdds??[]).flatMap(e=>["--cap-add",e]),...Object.entries(e.sysctls??{}).flatMap(([e,t])=>["--sysctl",`${e}=${t}`]),"--security-opt","no-new-privileges","--read-only","--tmpfs","/tmp:rw,nosuid,nodev,exec,size=256m",...(e.extraTmpfs??[]).flatMap(e=>["--tmpfs",e]),"--ipc","none","--tmpfs",`/dev/shm:rw,nosuid,nodev,size=${e.shmSizeMb??64}m`,"--memory",e.memory,"--memory-swap",e.memory,"--cpus",String(e.cpus),...e.cpuset?["--cpuset-cpus",e.cpuset]:[],"--pids-limit",String(e.pidsLimit),"-e","HOME=/tmp","-e","XDG_CACHE_HOME=/tmp/.cache","-e","MYPY_CACHE_DIR=/tmp/.mypy_cache","-e","RUFF_CACHE_DIR=/tmp/.ruff_cache","-e","PYTHONPYCACHEPREFIX=/tmp/.pycache","-e","npm_config_cache=/tmp/.npm",..."none"===e.network?["-e","UV_OFFLINE=1","-e","PIP_NO_INDEX=1","-e","npm_config_offline=true"]:[]]}},83129(e,exports,t){function r(e){const t=m.get(e.image)
|
|
85
99
|
if(t)return t.work
|
|
86
100
|
const r=(async()=>{const t=await(0,u.docker)(["image","inspect","--format",`{{ index .Config.Labels "${p}" }}`,e.image],u.DOCKER_OP_TIMEOUT_MS)
|
|
87
101
|
if(t.spawnError)return t.spawnError
|
|
@@ -114,9 +128,9 @@ if(0===t.exit){const e=/^oom_kill (\d+)/m.exec(t.stdout)
|
|
|
114
128
|
if(e)return Number(e[1])}const o=await(0,r.docker)(["exec",e,"cat","/sys/fs/cgroup/memory/memory.oom_control"],n)
|
|
115
129
|
if(0===o.exit){const e=/^oom_kill (\d+)/m.exec(o.stdout)
|
|
116
130
|
if(e)return Number(e[1])}return null},exports.probeBox=async function(e){const t=`cat /sys/fs/cgroup/memory.events 2>/dev/null || cat /sys/fs/cgroup/memory/memory.oom_control 2>/dev/null; if [ -s ${exports.H} ]; then echo __ALCHEMY_LIVE_FRAME__; fi`,o=await(0,r.docker)(["exec",e,"/bin/sh","-c",t],n),s=/^oom_kill (\d+)/m.exec(o.stdout)
|
|
117
|
-
return{oomKills:s?Number(s[1]):null,liveFrame:o.stdout.includes("__ALCHEMY_LIVE_FRAME__")}},exports.oomNote=function(e,t){return`[AlchemyLab] Out of memory: the kernel killed ${1===e?"a process":`${e} processes`} in this box during this command (the box's memory cap is ${t}). Exit code 137 means killed. Make the case smaller, or raise the environment's memory (resources.memory)
|
|
131
|
+
return{oomKills:s?Number(s[1]):null,liveFrame:o.stdout.includes("__ALCHEMY_LIVE_FRAME__")}},exports.oomNote=function(e,t,r=!1){return`[AlchemyLab] Out of memory: the kernel killed ${1===e?"a process":`${e} processes`} in this box during this command (the box's memory cap is ${t}). Exit code 137 means killed. `+(r?'A heavy box has 6 GB: experiment_start with size "heavy", then run in it. Or make the case smaller.':"Make the case smaller, or raise the environment's memory (resources.memory).")}
|
|
118
132
|
const r=t(81618),n=5e3
|
|
119
|
-
exports.H="/tmp/.alchemy_live.png"},11895(e,exports,t){exports.DEFAULT_CPUS=void 0,t(81618),t(22604),t(26166),t(2566),t(90695),t(61260),exports.DEFAULT_CPUS=4},90695(e,exports,t){exports.SCRATCH_VOLUME_ARGS=void 0,exports.scratchTmpfsArg=function(e){return`/scratch:rw,nosuid,nodev,exec,size=${e}m`},exports.claimScratch=async function(e,t,n){const o=await(0,r.docker)(["run","--rm","--network","none","--user","0:0","--volumes-from",e,"--entrypoint","chown",t,n,"/scratch"],r.DOCKER_OP_TIMEOUT_MS)
|
|
133
|
+
exports.H="/tmp/.alchemy_live.png"},11895(e,exports,t){exports.DEFAULT_CPUS=exports.HEAVY_MEMORY=void 0,exports.memoryForBox=function(e,t){return e??("heavy"===t?exports.HEAVY_MEMORY:"2g")},t(81618),t(22604),t(26166),t(2566),t(90695),t(61260),exports.HEAVY_MEMORY="6g",exports.DEFAULT_CPUS=4},90695(e,exports,t){exports.SCRATCH_VOLUME_ARGS=void 0,exports.scratchTmpfsArg=function(e){return`/scratch:rw,nosuid,nodev,exec,size=${e}m`},exports.claimScratch=async function(e,t,n){const o=await(0,r.docker)(["run","--rm","--network","none","--user","0:0","--volumes-from",e,"--entrypoint","chown",t,n,"/scratch"],r.DOCKER_OP_TIMEOUT_MS)
|
|
120
134
|
return 0===o.exit?null:o.spawnError??((o.stderr||"").trim()||`chown exited ${o.exit}`)}
|
|
121
135
|
const r=t(81618)
|
|
122
136
|
exports.SCRATCH_VOLUME_ARGS=["--mount","type=volume,dst=/scratch"]},2566(e,exports,t){exports.RUN_ENV_VAR=exports.RUN_FROM_ENV=void 0,exports.withShellInit=function(e,t){const r=(e??"").trim()
|
|
@@ -129,41 +143,46 @@ const r=t(76982)
|
|
|
129
143
|
exports.m4=1,exports.OFFICE_BOX_IMAGE=`alchemylab-local/office-box:v${exports.m4}`,exports.OT="/scratch/render",exports.dw="local NBH = utf8.char(0x2011)\nfunction Str(el)\n local t = el.text\n for _ = 1, 2 do t = t:gsub('(%d)%-(%d)', '%1' .. NBH .. '%2') end\n if t ~= el.text then el.text = t end\n return el\nend\n"
|
|
130
144
|
const n="/usr/local/share/render-pdf/nobreak.lua",o=`#!/bin/sh\n# render-pdf FILE... : convert Word, Excel, PowerPoint, OpenDocument, Markdown or HTML to PDF.\n# Writes each PDF under \${RENDER_OUT:-${exports.OT}} and prints its path, one per line.\nset -e\nout="\${RENDER_OUT:-${exports.OT}}"\nmkdir -p "$out" /scratch/.render-work\nexport HOME="\${HOME:-/scratch}"\nif [ "$1" = "--self-test" ]; then\n cd /scratch/.render-work\n python3 -c "import docx; d = docx.Document(); d.add_heading('render-pdf self-test', 1); d.add_paragraph('ok'); d.save('self-test.docx')"\n set -- /scratch/.render-work/self-test.docx\nfi\n[ "$#" -gt 0 ] || { echo "usage: render-pdf FILE..." >&2; exit 2; }\nfor f in "$@"; do\n [ -f "$f" ] || { echo "render-pdf: no such file: $f" >&2; exit 1; }\n name=$(basename "$f"); stem="\${name%.*}"\n case "$name" in\n *.md|*.markdown) pandoc --lua-filter ${n} "$f" -o "/scratch/.render-work/$stem.docx"; src="/scratch/.render-work/$stem.docx" ;;\n *) src="$f" ;;\n esac\n soffice --headless --norestore -env:UserInstallation=file:///scratch/.render-profile --convert-to pdf --outdir "$out" "$src" >/scratch/.render-work/soffice.log 2>&1 \\\n || { echo "render-pdf: LibreOffice could not convert $f" >&2; tail -5 /scratch/.render-work/soffice.log >&2; exit 1; }\n [ -f "$out/$stem.pdf" ] || { echo "render-pdf: no PDF produced for $f" >&2; exit 1; }\n echo "$out/$stem.pdf"\ndone\n`
|
|
131
145
|
exports.OFFICE_BOX_DOCKERFILE=function(){const e=Buffer.from(o).toString("base64"),t=Buffer.from(exports.dw).toString("base64")
|
|
132
|
-
return["FROM python:3.12-slim","ENV DEBIAN_FRONTEND=noninteractive PIP_NO_CACHE_DIR=1 PYTHONDONTWRITEBYTECODE=1","RUN apt-get update \\"," && apt-get install -y --no-install-recommends \\"," libreoffice-writer-nogui libreoffice-calc-nogui libreoffice-impress-nogui \\"," pandoc fonts-liberation fonts-dejavu-core fonts-crosextra-carlito fonts-crosextra-caladea \\"," zbar-tools poppler-utils \\"," && rm -rf /var/lib/apt/lists/*","RUN pip install python-docx openpyxl python-pptx pypdf segno",`RUN echo ${e} | base64 -d > /usr/local/bin/render-pdf && chmod 755 /usr/local/bin/render-pdf`,`RUN mkdir -p ${n.replace(/\/[^/]+$/,"")} && echo ${t} | base64 -d > ${n}`,""].join("\n")}(),exports.OFFICE_BOX_RECIPE_HASH=(0,r.createHash)("sha256").update(exports.OFFICE_BOX_DOCKERFILE).digest("hex").slice(0,16),exports.VP={name:"Office",description:'Make and render office files: python-docx, openpyxl, python-pptx, pandoc and LibreOffice in a sealed box. `render-pdf FILE` writes a PDF under /scratch/render. QR codes: `segno "URL" -o qr.png --scale 10`, read back with `zbarimg`; `pdftoppm -png` turns PDF pages into images. Word styling from Markdown: `pandoc --reference-doc`. The worktree is read-only here: make files under /scratch, record them (results record, box), then view_asset({ result }) to look at a PDF and write_file({ path, fromResult }) to put a file in the repository. Scripts you write to make a file stay in /scratch: the repository gets the finished files, and a note in the source saying how it was rendered.',smoke:"render-pdf --self-test",config:{image:exports.OFFICE_BOX_IMAGE,shellInit:"export HOME=/scratch",resources:{memory:"3g",scratchMb:1024,shmMb:256}}},exports.ENVIRONMENT_PRESETS={office:exports.VP}},3517(e,exports,t){function r(e,t){const r=
|
|
133
|
-
return
|
|
134
|
-
return"pdf"===t?`RENDER_OUT=/work/out render-pdf ${r(n)}`:"docx"===t&&/\.(md|markdown|html?)$/i.test(e)?`pandoc ${r(n)} -o ${r(`/work/out/${o}.docx`)}`:`soffice --headless --norestore -env:UserInstallation=file:///scratch/.render-profile --convert-to ${t} --outdir /work/out ${r(n)} >/dev/null`}
|
|
146
|
+
return["FROM python:3.12-slim","ENV DEBIAN_FRONTEND=noninteractive PIP_NO_CACHE_DIR=1 PYTHONDONTWRITEBYTECODE=1","RUN apt-get update \\"," && apt-get install -y --no-install-recommends \\"," libreoffice-writer-nogui libreoffice-calc-nogui libreoffice-impress-nogui \\"," pandoc fonts-liberation fonts-dejavu-core fonts-crosextra-carlito fonts-crosextra-caladea \\"," zbar-tools poppler-utils \\"," && rm -rf /var/lib/apt/lists/*","RUN pip install python-docx openpyxl python-pptx pypdf segno",`RUN echo ${e} | base64 -d > /usr/local/bin/render-pdf && chmod 755 /usr/local/bin/render-pdf`,`RUN mkdir -p ${n.replace(/\/[^/]+$/,"")} && echo ${t} | base64 -d > ${n}`,""].join("\n")}(),exports.OFFICE_BOX_RECIPE_HASH=(0,r.createHash)("sha256").update(exports.OFFICE_BOX_DOCKERFILE).digest("hex").slice(0,16),exports.VP={name:"Office",description:'Make and render office files: python-docx, openpyxl, python-pptx, pandoc and LibreOffice in a sealed box. `render-pdf FILE` writes a PDF under /scratch/render. QR codes: `segno "URL" -o qr.png --scale 10`, read back with `zbarimg`; `pdftoppm -png` turns PDF pages into images. Word styling from Markdown: `pandoc --reference-doc`. The worktree is read-only here: make files under /scratch, record them (results record, box), then view_asset({ result }) to look at a PDF and write_file({ path, fromResult }) to put a file in the repository. Scripts you write to make a file stay in /scratch: the repository gets the finished files, and a note in the source saying how it was rendered.',smoke:"render-pdf --self-test",config:{image:exports.OFFICE_BOX_IMAGE,shellInit:"export HOME=/scratch",resources:{memory:"3g",scratchMb:1024,shmMb:256}}},exports.ENVIRONMENT_PRESETS={office:exports.VP}},3517(e,exports,t){function r(e,t){const r=p.extname(e).slice(1).toLowerCase()
|
|
147
|
+
return w[t].includes(r)}function n(e,t){const r=e=>`'${e.replace(/'/g,"'\\''")}'`,n=`/work/in/${e}`,o=e.replace(/\.[^.]+$/,"")
|
|
148
|
+
return"pdf"===t?`RENDER_OUT=/work/out render-pdf ${r(n)}`:"docx"===t&&/\.(md|markdown|html?)$/i.test(e)?`pandoc ${r(n)} -o ${r(`/work/out/${o}.docx`)}`:`soffice --headless --norestore -env:UserInstallation=file:///scratch/.render-profile --convert-to ${t} --outdir /work/out ${r(n)} >/dev/null`}async function o(e,t,r,o){const s=await u.promises.mkdtemp(p.join(d.tmpdir(),"alchemylab-render-"))
|
|
149
|
+
try{await u.promises.mkdir(p.join(s,"in")),await u.promises.mkdir(p.join(s,"out")),await u.promises.chmod(s,493),await u.promises.chmod(p.join(s,"in"),493),await u.promises.chmod(p.join(s,"out"),511),await u.promises.writeFile(p.join(s,"in",e),t.bytes,{mode:420})
|
|
150
|
+
const a=new f.ContainerRunner({image:h.OFFICE_BOX_IMAGE,stepTimeoutMs:18e4,resources:{memory:"3g",shmSizeMb:256}}),i=await a.run({worktreePath:s,image:h.OFFICE_BOX_IMAGE,env:{HOME:"/scratch"},steps:[{run:n(e,t.to)}]})
|
|
151
|
+
if(!i.ok){const e=i.steps[0]
|
|
152
|
+
return{ok:!1,error:(i.error??`${(e?.stderr||e?.stdout||"").trim().split("\n").slice(-4).join(" ")}`)||"rendering failed",unavailable:!!i.error&&/docker|daemon|not found on PATH|Cannot connect/i.test(i.error)}}const c=(await u.promises.readdir(p.join(s,"out"))).find(e=>e.toLowerCase().endsWith(`.${t.to}`))
|
|
153
|
+
if(!c)return{ok:!1,error:`no ${t.to.toUpperCase()} was produced`}
|
|
154
|
+
const l=await u.promises.readFile(p.join(s,"out",c))
|
|
155
|
+
return await u.promises.mkdir(o,{recursive:!0}),await u.promises.writeFile(r,l),{ok:!0,bytes:l,cached:!1}}finally{await u.promises.rm(s,{recursive:!0,force:!0})}}var s,a=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
|
|
135
156
|
var o=Object.getOwnPropertyDescriptor(t,r)
|
|
136
|
-
o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,o)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),
|
|
157
|
+
o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,o)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),c=this&&this.__importStar||(s=function(e){return s=Object.getOwnPropertyNames||function(e){var t=[]
|
|
137
158
|
for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[t.length]=r)
|
|
138
|
-
return t},
|
|
159
|
+
return t},s(e)},function(e){if(e&&e.__esModule)return e
|
|
139
160
|
var t={}
|
|
140
|
-
if(null!=e)for(var r=
|
|
141
|
-
return
|
|
142
|
-
Object.defineProperty(exports,"__esModule",{value:!0}),exports.RENDER_MIME=exports.MAX_RENDER_INPUT_BYTES=void 0,exports.canRender=r,exports.renderDocument=async function(e,t){const
|
|
161
|
+
if(null!=e)for(var r=s(e),n=0;n<r.length;n++)"default"!==r[n]&&a(t,e,r[n])
|
|
162
|
+
return i(t,e),t})
|
|
163
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.RENDER_MIME=exports.MAX_RENDER_INPUT_BYTES=void 0,exports.canRender=r,exports.rendersInFlight=function(){return g.size},exports.renderDocument=async function(e,t){const n=(s=e.filename,p.basename(s).replace(/[^A-Za-z0-9._-]+/g,"_").replace(/^\.+/,"")||"document")
|
|
143
164
|
var s
|
|
144
|
-
if(!r(
|
|
165
|
+
if(!r(n,e.to))return{ok:!1,error:`${p.extname(n)||"this file"} cannot be turned into ${e.to.toUpperCase()}`}
|
|
145
166
|
if(e.bytes.length>exports.MAX_RENDER_INPUT_BYTES)return{ok:!1,error:`file is over ${exports.MAX_RENDER_INPUT_BYTES/1048576} MB`}
|
|
146
|
-
const a=(0,
|
|
147
|
-
try{return{ok:!0,bytes:await
|
|
148
|
-
if("wait"!==
|
|
167
|
+
const a=(0,l.createHash)("sha256").update(h.OFFICE_BOX_RECIPE_HASH).update("\0").update(e.to).update("\0").update(p.extname(n).toLowerCase()).update("\0").update(e.bytes).digest("hex"),i=p.join(t.cacheDir,`${a}.${e.to}`)
|
|
168
|
+
try{return{ok:!0,bytes:await u.promises.readFile(i),cached:!0}}catch{}const c=t.image??"wait"
|
|
169
|
+
if("wait"!==c){const e=(0,m.localRecipeFor)(h.OFFICE_BOX_IMAGE),t=await(0,m.localImageState)(e)
|
|
149
170
|
if("no-docker"===t.state)return{ok:!1,error:t.error,unavailable:!0}
|
|
150
|
-
if("building"===t.state)return{ok:!1,error:
|
|
171
|
+
if("building"===t.state)return{ok:!1,error:b,preparing:!0,since:t.since}
|
|
151
172
|
if("failed"===t.state&&Date.now()-t.at<12e4)return{ok:!1,error:`building the office renderer failed: ${t.error.split("\n").slice(-3).join(" ")}`}
|
|
152
|
-
if("ready"!==t.state){if("present-only"===
|
|
153
|
-
const{since:t}=(0,
|
|
154
|
-
return{ok:!1,error:
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
return await l.promises.mkdir(t.cacheDir,{recursive:!0}),await l.promises.writeFile(i,c),{ok:!0,bytes:c,cached:!1}}finally{await l.promises.rm(b,{recursive:!0,force:!0})}}
|
|
162
|
-
const c=t(76982),l=t(79896),u=i(t(70857)),d=i(t(16928)),p=t(52429),f=t(83129),m=t(44853)
|
|
173
|
+
if("ready"!==t.state){if("present-only"===c)return{ok:!1,error:"the office renderer is not built on this machine yet",unavailable:!0}
|
|
174
|
+
const{since:t}=(0,m.startLocalImageBuild)(e)
|
|
175
|
+
return{ok:!1,error:b,preparing:!0,since:t}}}let d=g.get(a)
|
|
176
|
+
if(d||(d={since:Date.now(),done:(t.run??o)(n,e,i,t.cacheDir).catch(e=>({ok:!1,error:e instanceof Error?e.message:String(e)})).finally(()=>{g.delete(a)})},g.set(a,d)),!t.answerWithin||t.answerWithin<=0)return d.done
|
|
177
|
+
const{since:f,done:w}=d
|
|
178
|
+
let x
|
|
179
|
+
const _=new Promise(e=>{x=setTimeout(()=>e({ok:!1,rendering:!0,since:f,error:"the exact copy is still rendering"}),t.answerWithin)})
|
|
180
|
+
try{return await Promise.race([w,_])}finally{x&&clearTimeout(x)}}
|
|
181
|
+
const l=t(76982),u=t(79896),d=c(t(70857)),p=c(t(16928)),f=t(52429),m=t(83129),h=t(44853)
|
|
163
182
|
exports.MAX_RENDER_INPUT_BYTES=52428800
|
|
164
|
-
const
|
|
183
|
+
const w={pdf:["docx","doc","odt","rtf","xlsx","xlsm","xls","ods","csv","pptx","ppt","odp","md","markdown","html","htm"],docx:["md","markdown","html","htm","odt","rtf","doc"],xlsx:["xls","ods"],pptx:["ppt","odp"]}
|
|
165
184
|
exports.RENDER_MIME={pdf:"application/pdf",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation"}
|
|
166
|
-
const
|
|
185
|
+
const b="the office renderer is being built on this machine (first use only, usually a few minutes)",g=new Map},43701(e,exports){function t(e){return e<128?String.fromCharCode(e):"\u20ac\x81\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\x8d\u017d\x8f\x90\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\x9d\u017e\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"[e-128]??""}exports.rtfToText=function(e){const o="string"==typeof e?e:Buffer.from(e).toString("latin1")
|
|
167
186
|
if(!/^\s*\{\s*\\rtf/i.test(o))throw new Error("not an RTF file (it does not start with {\\rtf)")
|
|
168
187
|
const s=[],a=[{skip:!1,skipChars:0}],i=()=>a[a.length-1],c=e=>{i().skip||s.push(e)}
|
|
169
188
|
for(let e=0;e<o.length;e++){const s=o[e]
|
|
@@ -303,7 +322,7 @@ const c=new Map
|
|
|
303
322
|
for(const e of Object.keys(s.files)){const t=/^(.+)\/content\.xml$/.exec(e)?.[1]
|
|
304
323
|
if(!t)continue
|
|
305
324
|
const r=await n(s,e)
|
|
306
|
-
r&&/<chart:chart\b/.test(r)&&c.set(t
|
|
325
|
+
r&&/<chart:chart\b/.test(r)&&c.set(t,O(r))}return{xml:i.split(/<office:body\b/)[1]??i,objects:c}}function y(e,t){return e.object?t.get((e.href??"").replace(/^\.\//,""))??`[embedded object: ${(e.desc||e.title||e.name||"unnamed").trim()}]`:e.image?l(e.desc||e.title,e.name):null}function O(e){const t=/chart:class="chart:(\w+)"/.exec(e)?.[1]??"chart",r=[...(/<chart:title\b[^>]*>([\s\S]*?)<\/chart:title>/.exec(e)?.[1]??"").matchAll(/<text:p\b[^>]*>([\s\S]*?)<\/text:p>/g)].map(e=>o(e[1].replace(/<[^>]+>/g,""))).join(" ").trim(),n=[],a=/<table:table\b[^>]*table:name="local-table"[^>]*>([\s\S]*?)<\/table:table>/.exec(e)?.[1]
|
|
307
326
|
if(a)for(const e of a.matchAll(/<table:table-row\b[^>]*>([\s\S]*?)<\/table:table-row>/g)){const t=[]
|
|
308
327
|
for(const r of e[1].matchAll(/<table:(?:table-cell|covered-table-cell)\b([^>]*?)(?:\/>|>([\s\S]*?)<\/table:(?:table-cell|covered-table-cell)>)/g)){const e=o([...(r[2]??"").matchAll(/<text:p\b[^>]*>([\s\S]*?)<\/text:p>/g)].map(e=>e[1].replace(/<[^>]+>/g,"")).join(" ")).trim()||s(r[1],"office:value")||"",n=Math.min(Math.max(1,Number(s(r[1],"table:number-columns-repeated")??1)||1),256)
|
|
309
328
|
for(let r=0;r<n;r++)t.push(e)}n.push(t)}const i=e=>{const t=/^\$?([A-Z]+)\$?(\d+)$/.exec(e)
|
|
@@ -316,10 +335,10 @@ for(let t=e.row;t<=r.row;t++)for(let s=e.col;s<=r.col;s++)o.push(n[t]?.[s]??"")
|
|
|
316
335
|
return`${o.slice(0,8).join(", ")}${o.length>8?`, ... (${o.length})`:""}`}const r=t.map(e=>e.ref.replace(/\$/g,""))
|
|
317
336
|
return`${t[0].table?`${t[0].table}!`:""}${2===r.length&&r[0]===r[1]?r[0]:r.join(":")}`},l=c(/<chart:categories\b[^>]*table:cell-range-address="([^"]+)"/.exec(e)?.[1]),u=[...e.matchAll(/<chart:series\b([^>]*)>/g)].map(e=>{const t=c(s(e[1],"chart:values-cell-range-address"))
|
|
318
337
|
return`${c(s(e[1],"chart:label-cell-address"))||"series"}${t?`: ${t}`:""}${l?` by ${l}`:""}`})
|
|
319
|
-
return`[chart: ${
|
|
338
|
+
return`[chart: ${R[t]??t}${r?` "${r}"`:""}${u.length?`; ${u.join("; ")}`:""}]`}function E(e,t,r){switch(e){case"text:tab":return r.push("\t"),!0
|
|
320
339
|
case"text:line-break":return r.push("\n"),!0
|
|
321
340
|
case"text:s":return r.push(" ".repeat(Math.min(100,Number(s(t,"text:c")??1)||1))),!0
|
|
322
|
-
default:return!1}}function
|
|
341
|
+
default:return!1}}function v(e,t=new Map){const r=[],n=[],a=new I
|
|
323
342
|
let i=0,c=0,l=null,u=null
|
|
324
343
|
for(const d of e.matchAll(T)){const[,e,p,f,m,h]=d
|
|
325
344
|
if(void 0!==h){if(c)continue
|
|
@@ -329,7 +348,7 @@ continue}if(c)continue
|
|
|
329
348
|
const w=n[n.length-1]
|
|
330
349
|
if(e)switch(p){case"svg:title":case"svg:desc":u=null
|
|
331
350
|
break
|
|
332
|
-
case"draw:frame":{const e=l?
|
|
351
|
+
case"draw:frame":{const e=l?y(l,t):null
|
|
333
352
|
if(l=null,!e)break
|
|
334
353
|
a.current?a.pushSpaced(e):w?.cell?w.cell.push(e):r.push(e)
|
|
335
354
|
break}case"text:p":case"text:h":{const e=a.close()
|
|
@@ -347,7 +366,7 @@ case"table:table":{const e=n.pop()
|
|
|
347
366
|
if(!e)break
|
|
348
367
|
const t=e.rows.map(e=>`| ${e.map(e=>e.replace(/\|/g,"\\|")).join(" | ")} |`),o=n[n.length-1]
|
|
349
368
|
o?.cell?o.cell.push(t.join(" ")):r.push(...t,"")
|
|
350
|
-
break}}else{if(
|
|
369
|
+
break}}else{if(E(p,f,a))continue
|
|
351
370
|
switch(p){case"text:p":case"text:h":m?!w?.cell&&r.length&&""!==r[r.length-1]&&r.push(""):a.open("text:h"===p?Number(s(f,"text:outline-level")??1)||1:0,i>0)
|
|
352
371
|
break
|
|
353
372
|
case"text:list-item":m||i++
|
|
@@ -364,9 +383,9 @@ case"draw:image":l&&(l.image=!0)
|
|
|
364
383
|
break
|
|
365
384
|
case"draw:object":case"draw:object-ole":l&&(l.object=!0,l.href=s(f,"xlink:href"))
|
|
366
385
|
break
|
|
367
|
-
case"svg:title":case"svg:desc":!m&&l&&(u="svg:title"===p?"title":"desc")}}}return r.join("\n").replace(/\n{3,}/g,"\n\n").trim()}exports.bi=void 0,exports.documentKindFor=function(e){const t=(0
|
|
386
|
+
case"svg:title":case"svg:desc":!m&&l&&(u="svg:title"===p?"title":"desc")}}}return r.join("\n").replace(/\n{3,}/g,"\n\n").trim()}exports.bi=void 0,exports.documentKindFor=function(e){const t=(0,$.formatFor)(e)
|
|
368
387
|
return t?.text?t.kind:void 0},exports.extractDocumentText=async function e(i,c,l={}){if(i.byteLength>exports.bi)throw new Error(`file is ${(i.byteLength/1048576).toFixed(1)} MB; text extraction stops at ${exports.bi/1048576} MB`)
|
|
369
|
-
const d=(0
|
|
388
|
+
const d=(0,$.formatOfKind)(c).textVia
|
|
370
389
|
if(d){if(!l.convert)throw new Error(`.${c} files are read by converting them in the office box, which is not reachable from here`)
|
|
371
390
|
const t=await e(await l.convert(i,c,d),d)
|
|
372
391
|
return{...t,kind:c,note:`Converted from .${c} to .${d} in the office box first. ${t.note??""}`.trim()}}switch(c){case"pdf":return async function(e){const r=await Promise.resolve().then(()=>t.t(88891,23)),{getDocumentProxy:n,extractText:o}=r?.default??r,s=await n(new Uint8Array(e),{isEvalSupported:!1})
|
|
@@ -402,7 +421,7 @@ const f=[...p.values()].find(e=>/notesSlide\d*\.xml$/.test(e)),m=f?await n(t,f):
|
|
|
402
421
|
let w=`## Slide ${e+1}\n${s.join("\n")||"(no text)"}`
|
|
403
422
|
h.length&&(w+=`\n\nNotes:\n${h.join("\n")}`),l.push(w)}return{kind:"pptx",text:l.join("\n\n"),units:c.length,note:"Slide text and speaker notes; pictures show as [image: alt text] and charts as a one-line summary; layout is dropped. To see a slide, view_asset this path."}}(i)
|
|
404
423
|
case"odt":return async function(e){const{xml:t,objects:r}=await k(e,"application/vnd.oasis.opendocument.text","text document")
|
|
405
|
-
return{kind:"odt",text:
|
|
424
|
+
return{kind:"odt",text:v(t,r),note:"Text, headings, lists and tables; pictures show as [image: alt text] and charts as a one-line summary; notes, comments and formatting are dropped. To see the pages, view_asset this path."}}(i)
|
|
406
425
|
case"ods":return async function(e){const{xml:t,objects:r}=await k(e,"application/vnd.oasis.opendocument.spreadsheet","spreadsheet"),{sheets:n,truncated:a}=function(e,t=new Map){const r=[]
|
|
407
426
|
let n=!1,a=null,i=null,c=null,l=null,u=null,d=0,p=!1
|
|
408
427
|
for(const f of e.matchAll(T)){const[,e,m,h,w,b]=f
|
|
@@ -418,7 +437,7 @@ var t
|
|
|
418
437
|
i.col+=c.repeat,c=null}
|
|
419
438
|
if(e)switch(m){case"svg:title":case"svg:desc":u=null
|
|
420
439
|
break
|
|
421
|
-
case"draw:frame":{const e=l?
|
|
440
|
+
case"draw:frame":{const e=l?y(l,t):null
|
|
422
441
|
l=null,e&&a&&a.figures.push(e)
|
|
423
442
|
break}case"text:p":p=!1
|
|
424
443
|
break
|
|
@@ -450,7 +469,7 @@ case"svg:title":case"svg:desc":!w&&l&&(u="svg:title"===m?"title":"desc")}}return
|
|
|
450
469
|
return{kind:"ods",text:n.map(e=>`## Sheet: ${e.name}\n${e.text||"(empty)"}${e.figures.length?`\n\n${e.figures.join("\n")}`:""}`).join("\n\n"),units:n.length,note:"Cell values as tab-separated rows (column letters in the header); a formula shows as its value followed by (=formula). Charts and pictures are listed under their sheet."+(a?" Sheets over 5000 rows are cut off.":"")}}(i)
|
|
451
470
|
case"odp":return async function(e){const{xml:t,objects:r}=await k(e,"application/vnd.oasis.opendocument.presentation","presentation"),n=function(e,t=new Map){const r=[]
|
|
452
471
|
let n=null
|
|
453
|
-
const a=new
|
|
472
|
+
const a=new I
|
|
454
473
|
let i=0,c=0,l=null,u=null
|
|
455
474
|
for(const d of e.matchAll(T)){const[,e,p,f,m,h]=d
|
|
456
475
|
if(void 0===h){if(A.has(p))m||(c+=e?-1:1)
|
|
@@ -458,14 +477,14 @@ else if(!c)if(e)switch(p){case"svg:title":case"svg:desc":u=null
|
|
|
458
477
|
break
|
|
459
478
|
case"text:p":case"text:h":{const e=a.close()
|
|
460
479
|
!e?.plain||!n||i&&/^<number>$/.test(e.plain)||(i?n.notes:n.lines).push(e.plain)
|
|
461
|
-
break}case"draw:frame":{const e=l?
|
|
480
|
+
break}case"draw:frame":{const e=l?y(l,t):null
|
|
462
481
|
l=null,e&&n&&n.lines.push(e)
|
|
463
482
|
break}case"presentation:notes":i=Math.max(0,i-1)
|
|
464
483
|
break
|
|
465
484
|
case"draw:page":{if(!n)break
|
|
466
485
|
let e=`## Slide ${r.length+1}\n${n.lines.join("\n")||"(no text)"}`
|
|
467
486
|
n.notes.length&&(e+=`\n\nNotes:\n${n.notes.join("\n")}`),r.push(e),n=null
|
|
468
|
-
break}}else{if(
|
|
487
|
+
break}}else{if(E(p,f,a))continue
|
|
469
488
|
switch(p){case"draw:page":m||(n={lines:[],notes:[]})
|
|
470
489
|
break
|
|
471
490
|
case"presentation:notes":m||i++
|
|
@@ -483,10 +502,10 @@ u&&l?l[u]=(l[u]??"")+o(h):a.push(o(h))}}return r}(t,r)
|
|
|
483
502
|
return{kind:"odp",text:n.join("\n\n"),units:n.length,note:"Slide text and speaker notes; pictures show as [image: alt text] and charts as a one-line summary; layout is dropped. To see a slide, view_asset this path."}}(i)
|
|
484
503
|
case"rtf":return{kind:"rtf",text:(0,M.rtfToText)(i),note:"Text, paragraphs and table rows; styling, pictures and layout are dropped. To see the pages, view_asset this path."}
|
|
485
504
|
default:throw new Error(`no text form for .${c}`)}}
|
|
486
|
-
const
|
|
505
|
+
const $=t(12661),M=t(43701)
|
|
487
506
|
exports.bi=52428800
|
|
488
|
-
const S=5e3,C={barChart:"bar",bar3DChart:"bar",lineChart:"line",line3DChart:"line",pieChart:"pie",pie3DChart:"pie",ofPieChart:"pie",doughnutChart:"doughnut",areaChart:"area",area3DChart:"area",scatterChart:"scatter",radarChart:"radar",bubbleChart:"bubble",stockChart:"stock",surfaceChart:"surface",surface3DChart:"surface"},T=/<(\/?)([A-Za-z][\w.-]*:[\w.-]+)\b([^>]*?)(\/?)>|([^<]+)/g,A=new Set(["text:note","office:annotation","text:tracked-changes","office:forms","text:sequence-decls"]),
|
|
489
|
-
class
|
|
507
|
+
const S=5e3,C={barChart:"bar",bar3DChart:"bar",lineChart:"line",line3DChart:"line",pieChart:"pie",pie3DChart:"pie",ofPieChart:"pie",doughnutChart:"doughnut",areaChart:"area",area3DChart:"area",scatterChart:"scatter",radarChart:"radar",bubbleChart:"bubble",stockChart:"stock",surfaceChart:"surface",surface3DChart:"surface"},T=/<(\/?)([A-Za-z][\w.-]*:[\w.-]+)\b([^>]*?)(\/?)>|([^<]+)/g,A=new Set(["text:note","office:annotation","text:tracked-changes","office:forms","text:sequence-decls"]),R={circle:"pie",ring:"doughnut"}
|
|
508
|
+
class I{constructor(){this.stack=[]}open(e,t){this.stack.push({parts:[],heading:e,listed:t})}get current(){return this.stack[this.stack.length-1]}push(e){this.current?.parts.push(e)}pushSpaced(e){const t=this.current?.parts
|
|
490
509
|
if(!t)return
|
|
491
510
|
const r=t[t.length-1]??""
|
|
492
511
|
t.push(`${!r||/\s$/.test(r)?"":" "}${e} `)}close(){const e=this.stack.pop()
|
|
@@ -509,22 +528,62 @@ return s(t,e),t})
|
|
|
509
528
|
Object.defineProperty(exports,"__esModule",{value:!0}),exports.textconv=r
|
|
510
529
|
const i=e(91943),c=a(e(70857)),l=a(e(16928)),u=e(36018),d=e(3517)
|
|
511
530
|
if(e.c[e.s]===module){const e=process.argv[2]
|
|
512
|
-
e||(process.stderr.write("usage: textconv <file>\n"),process.exit(2)),r(e).then(e=>process.stdout.write(e),()=>process.stdout.write("(AlchemyLab: text conversion failed)\n"))}},
|
|
531
|
+
e||(process.stderr.write("usage: textconv <file>\n"),process.exit(2)),r(e).then(e=>process.stdout.write(e),()=>process.stdout.write("(AlchemyLab: text conversion failed)\n"))}},4334(e,exports,t){function r(e=Date.now()){const t=Number(process.hrtime.bigint()/1000000n)
|
|
532
|
+
if(!w)return m=e,h=t,function(e){if(x)try{const t=JSON.parse(d.readFileSync(x,"utf8"))
|
|
533
|
+
if(!Array.isArray(t))return
|
|
534
|
+
for(const r of t)r&&"number"==typeof r.from&&"number"==typeof r.to&&r.to>r.from&&(r.to<e-6048e5||b.some(e=>e.from===r.from&&e.to===r.to)||b.push({from:r.from,to:r.to}))
|
|
535
|
+
b.sort((e,t)=>e.from-t.from)}catch{}}(e),w=setInterval(()=>r(),5e3),void w.unref?.()
|
|
536
|
+
if(e-m>2e4){const r={from:m,to:e}
|
|
537
|
+
if(!1!==g(r,t-h)){for(b.push(r);b.length&&b[0].to<e-6048e5;)b.shift()
|
|
538
|
+
!function(){if(x)try{d.mkdirSync(f.dirname(x),{recursive:!0})
|
|
539
|
+
const e=`${x}.${process.pid}.tmp`
|
|
540
|
+
d.writeFileSync(e,JSON.stringify(b)),d.renameSync(e,x)}catch{}}()}}e>m&&(m=e),h=t}function n(e,t=Date.now()){r()
|
|
541
|
+
let n=0
|
|
542
|
+
for(const r of b){const o=Math.max(r.from,e),s=Math.min(r.to,t)
|
|
543
|
+
s>o&&(n+=s-o)}return n}function o(e,t=Date.now()){return Math.max(0,t-e-n(e,t))}function s(e){const t=Math.max(1,Math.round(e/6e4))
|
|
544
|
+
if(t<60)return`${t} min`
|
|
545
|
+
const r=Math.floor(t/60),n=t%60
|
|
546
|
+
return n?`${r} h ${n} min`:`${r} h`}var a,i=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
|
|
547
|
+
var o=Object.getOwnPropertyDescriptor(t,r)
|
|
548
|
+
o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,o)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),c=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),l=this&&this.__importStar||(a=function(e){return a=Object.getOwnPropertyNames||function(e){var t=[]
|
|
549
|
+
for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[t.length]=r)
|
|
550
|
+
return t},a(e)},function(e){if(e&&e.__esModule)return e
|
|
551
|
+
var t={}
|
|
552
|
+
if(null!=e)for(var r=a(e),n=0;n<r.length;n++)"default"!==r[n]&&i(t,e,r[n])
|
|
553
|
+
return c(t,e),t})
|
|
554
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.systemSleepCheck=void 0,exports.sampleAwakeClock=r,exports.sleptBetween=n,exports.awakeSince=o,exports.sleepWords=s,exports.awakeTimeout=function(e,t){const s=Date.now()
|
|
555
|
+
r(s)
|
|
556
|
+
let a=null
|
|
557
|
+
const i=e=>{a=setTimeout(c,Math.max(0,e))},c=()=>{a=null
|
|
558
|
+
const r=t-o(s)
|
|
559
|
+
r>0?i(r):e()}
|
|
560
|
+
return i(t),{clear:()=>{a&&clearTimeout(a),a=null},slept:()=>n(s)}},exports.sleptDuringRunNote=function(e){return`[AlchemyLab] The computer slept for ${s(e)} while this command ran. Nothing ran during that time (the box sleeps with the computer), and that time did not count toward the command's time limit.`},exports.sleptBetweenRunsNote=function(e){return`[AlchemyLab] The computer slept for ${s(e)} since the last command in this box ended. Nothing in the box ran during that time, background processes included; they went on when it woke.`},exports.resetAwakeClockForTests=function(e={}){w&&clearInterval(w),w=null,m=0,h=0,b.length=0,g=e.check??(()=>!0),x=e.store??null}
|
|
561
|
+
const u=t(35317),d=l(t(79896)),p=l(t(70857)),f=l(t(16928))
|
|
562
|
+
exports.systemSleepCheck=(e,t)=>{if("linux"===process.platform)return e.to-e.from-t>1e4
|
|
563
|
+
if("darwin"!==process.platform)return null
|
|
564
|
+
try{const t=(0,u.execFileSync)("sysctl",["-n","kern.waketime"],{encoding:"utf8",timeout:2e3}).match(/sec\s*=\s*(\d+)\s*,\s*usec\s*=\s*(\d+)/)
|
|
565
|
+
if(!t)return null
|
|
566
|
+
const r=1e3*Number(t[1])+Math.floor(Number(t[2])/1e3)
|
|
567
|
+
return r>e.from-1e3&&r<=e.to+1e3}catch{return null}}
|
|
568
|
+
let m=0,h=0,w=null
|
|
569
|
+
const b=[]
|
|
570
|
+
let g=exports.systemSleepCheck,x=f.join(p.homedir(),".alchemy_lab","sleep-gaps.json")
|
|
571
|
+
r()},88196(e,exports){exports.EndsKeeper=void 0,exports.EndsKeeper=class{constructor(e){this.half=e,this.head="",this.tail="",this.cut=0}push(e){if(this.head.length<this.half){const t=this.half-this.head.length
|
|
513
572
|
if(this.head+=e.slice(0,t),!(e=e.slice(t)))return}this.tail+=e,this.tail.length>this.half&&(this.cut+=this.tail.length-this.half,this.tail=this.tail.slice(-this.half))}text(){return this.cut>0?`${this.head}\n[AlchemyLab] ${this.cut} characters of output cut here; the start and the end are kept.\n${this.tail}`:this.head+this.tail}}},44600(e,exports,t){async function r(e,r={}){const{spawn:n}=await Promise.resolve().then(()=>t.t(35317,23))
|
|
514
|
-
return new Promise(t=>{const
|
|
515
|
-
let
|
|
516
|
-
const
|
|
517
|
-
let
|
|
518
|
-
r.onKillReady?.((e="SIGTERM")=>{
|
|
519
|
-
const
|
|
520
|
-
|
|
573
|
+
return new Promise(t=>{const s="win32"===process.platform,a=s?n(e,{cwd:r.cwd??process.cwd(),env:r.env,shell:"cmd.exe",stdio:["pipe","pipe","pipe"],detached:!1}):n("/bin/sh",["-c",exports.RUN_FROM_ENV],{cwd:r.cwd??process.cwd(),env:{...r.env??process.env,[exports.RUN_ENV_VAR]:e},stdio:["pipe","pipe","pipe"],detached:!0}),i=[],c=[]
|
|
574
|
+
let l=!1,u=!1
|
|
575
|
+
const d=e=>{if(a.pid)try{s?a.kill(e):process.kill(-a.pid,e)}catch{}}
|
|
576
|
+
let p,f
|
|
577
|
+
r.onKillReady?.((e="SIGTERM")=>{d(e),"SIGKILL"!==e&&setTimeout(()=>{u||d("SIGKILL")},2e3)}),r.timeoutMs&&r.timeoutMs>0&&(f=(0,o.awakeTimeout)(()=>{l=!0,d("SIGTERM"),p=setTimeout(()=>{u||d("SIGKILL")},2e3)},r.timeoutMs)),a.stdout?.on("data",e=>{i.push(e),r.onChunk?.("stdout",e)}),a.stderr?.on("data",e=>{c.push(e),r.onChunk?.("stderr",e)})
|
|
578
|
+
const m=e=>{u||(u=!0,f?.clear(),p&&clearTimeout(p),t({stdout:Buffer.concat(i).toString("utf-8"),stderr:Buffer.concat(c).toString("utf-8"),exitCode:e,timedOut:l}))}
|
|
579
|
+
a.on("close",e=>m(e??(l?124:1))),a.on("error",()=>m(1))})}Object.defineProperty(exports,"__esModule",{value:!0}),exports.RUN_ENV_VAR=exports.RUN_FROM_ENV=exports.RUN_PARSE_FAILED_EXIT=void 0,exports.exitMeansCouldNotRun=function(e){return e===exports.RUN_PARSE_FAILED_EXIT||127===e},exports.execAsync=async function(e,t={}){return new Promise((r,o)=>{const[s,...a]=e.split(" "),i=(0,n.spawn)(s,a,{cwd:t.cwd||process.cwd(),stdio:["pipe","pipe","pipe"]})
|
|
521
580
|
let c="",l=""
|
|
522
581
|
i.stdout?.on("data",e=>{c+=e.toString()}),i.stderr?.on("data",e=>{l+=e.toString()}),i.on("close",e=>{r({stdout:c,stderr:l,exitCode:e||0})}),i.on("error",t=>{o(new Error(`Command failed: ${e}\nError: ${t.message}`))}),t.timeout&&setTimeout(()=>{i.kill(),o(new Error(`Command timed out: ${e}`))},t.timeout)})},exports.runShellCommand=r,exports.runTrackedShellCommand=async function(e,n,o){const{getActionServerBaseUrl:s}=await t.e(414).then(()=>t(79414)),a=s(),i=(new Date).toISOString(),c=n.cwd??process.cwd()
|
|
523
582
|
let l
|
|
524
583
|
fetch(`${a}/api/commands/start`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:o.id,name:o.name,command:e,cwd:c,sessionId:o.sessionId,startedAt:i,logPath:o.logPath,timeoutMs:n.timeoutMs}),signal:AbortSignal.timeout(2e3)}).catch(()=>{})
|
|
525
584
|
try{l=await r(e,n)}catch(e){throw fetch(`${a}/api/commands/end`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:o.id,exitCode:1,timedOut:!1,finishedAt:(new Date).toISOString()}),signal:AbortSignal.timeout(2e3)}).catch(()=>{}),e}return fetch(`${a}/api/commands/end`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:o.id,exitCode:l.exitCode,timedOut:l.timedOut,finishedAt:(new Date).toISOString()}),signal:AbortSignal.timeout(2e3)}).catch(()=>{}),l}
|
|
526
|
-
const n=t(35317)
|
|
527
|
-
exports.RUN_PARSE_FAILED_EXIT=125,exports.RUN_FROM_ENV=["c=$ALCHEMY_RUN_CMD; unset ALCHEMY_RUN_CMD",`if
|
|
585
|
+
const n=t(35317),o=t(4334)
|
|
586
|
+
exports.RUN_PARSE_FAILED_EXIT=125,exports.RUN_FROM_ENV=["c=$ALCHEMY_RUN_CMD; unset ALCHEMY_RUN_CMD",`case "$c" in *ALCHEMY_PROJECT_ROOT*) if [ -z "\${ALCHEMY_PROJECT_ROOT:-}" ]; then echo "Not run: ALCHEMY_PROJECT_ROOT (the project's folder) is not set here." >&2; exit ${exports.RUN_PARSE_FAILED_EXIT}; fi;; esac`,`if command -v bash >/dev/null 2>&1; then ALCHEMY_RUN_CMD=$c; export ALCHEMY_RUN_CMD; exec bash -o pipefail -c 'c=$ALCHEMY_RUN_CMD; unset ALCHEMY_RUN_CMD; bash -n -c "$c" || exit ${exports.RUN_PARSE_FAILED_EXIT}; eval "$c"'`,`elif (set -o pipefail) 2>/dev/null; then set -o pipefail; sh -n -c "$c" || exit ${exports.RUN_PARSE_FAILED_EXIT}; eval "$c"`,`else sh -n -c "$c" || exit ${exports.RUN_PARSE_FAILED_EXIT}; eval "$c"; fi`].join("\n"),exports.RUN_ENV_VAR="ALCHEMY_RUN_CMD"},88194(module){module.exports=require("jszip")},9956(module){module.exports=require("undici")},88891(module){module.exports=require("unpdf")},35317(module){module.exports=require("child_process")},76982(module){module.exports=require("crypto")},79896(module){module.exports=require("fs")},91943(module){module.exports=require("fs/promises")},16698(module){module.exports=require("node:async_hooks")},31421(module){module.exports=require("node:child_process")},73024(module){module.exports=require("node:fs")},48161(module){module.exports=require("node:os")},76760(module){module.exports=require("node:path")},70857(module){module.exports=require("os")},16928(module){module.exports=require("path")},2203(module){module.exports=require("stream")}}
|
|
528
587
|
const r={}
|
|
529
588
|
e.m=t,e.c=r,(()=>{const t=Object.getPrototypeOf
|
|
530
589
|
let r
|