@reason-machines/cli-linux-arm64-musl 0.2.381 → 0.2.383

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 (111) hide show
  1. package/README.md +3 -1
  2. package/bin/ara +2 -2
  3. package/bin/vm-hands/api-credentials-xppmbg0m.js +2 -0
  4. package/bin/vm-hands/api-xmpbsm6b.js +2 -0
  5. package/bin/vm-hands/{ask-relay-fc0jc3t5.js → ask-relay-h8f5dmfh.js} +3 -3
  6. package/bin/vm-hands/connect-cli-qvfxpk5t.js +2 -0
  7. package/bin/vm-hands/{custom-endpoint-device-zhpake9f.js → custom-endpoint-device-bm94e9r0.js} +1 -1
  8. package/bin/vm-hands/desktop-account-3tnm4z5w.js +2 -0
  9. package/bin/vm-hands/{device-workspace-vbcry9d6.js → device-workspace-0xsj5ykf.js} +1 -1
  10. package/bin/vm-hands/hands-worker-source-azdrrhsz.js +2 -0
  11. package/bin/vm-hands/{index-bbk6a9sk.js → index-7f2kwwen.js} +1 -1
  12. package/bin/vm-hands/{install-receipt-7x81ek76.js → install-receipt-3xyx3rdd.js} +1 -1
  13. package/bin/vm-hands/local-automation-pvy9revm.js +2 -0
  14. package/bin/vm-hands/local-capabilities-zfzyknay.js +2 -0
  15. package/bin/vm-hands/local-desktop-users-ajb81vjm.js +2 -0
  16. package/bin/vm-hands/local-display-mac-9h6btvvq.js +2 -0
  17. package/bin/vm-hands/local-display-session-xqncvp30.js +2 -0
  18. package/bin/vm-hands/local-pty-session-cjas515w.js +2 -0
  19. package/bin/vm-hands/managed-runtime-s414h5nm.js +2 -0
  20. package/bin/vm-hands/{network-contract-zqvt1v0t.js → network-contract-dsw79qkc.js} +1 -1
  21. package/bin/vm-hands/package-smk3nqjs.js +2 -0
  22. package/bin/vm-hands/permissions-3mkk9mfw.js +2 -0
  23. package/bin/vm-hands/{reason-hands-protocol-8fxjynte.js → reason-hands-protocol-7d7xj1h3.js} +1 -1
  24. package/bin/vm-hands/serve-service-txzqn5kj.js +2 -0
  25. package/bin/vm-hands/status-23eqx9t3.js +96 -0
  26. package/bin/vm-hands/version-3gj9bqhc.js +2 -0
  27. package/bin/vm-hands/{vm-hands-entry-lite-7shpbsw8.js → vm-hands-entry-lite-1gxktkpe.js} +2 -2
  28. package/bin/vm-hands/vm-hands-entry-lite-2e18tm6w.js +245 -0
  29. package/bin/vm-hands/{vm-hands-entry-lite-g036gtem.js → vm-hands-entry-lite-2t0vcvd8.js} +1 -1
  30. package/bin/vm-hands/vm-hands-entry-lite-3dc4v5bd.js +11 -0
  31. package/bin/vm-hands/{vm-hands-entry-lite-hgkf1svv.js → vm-hands-entry-lite-41nygv3p.js} +2 -2
  32. package/bin/vm-hands/{vm-hands-entry-lite-j2q1k9vb.js → vm-hands-entry-lite-51hmj6am.js} +1 -1
  33. package/bin/vm-hands/{vm-hands-entry-lite-zfwg7ehq.js → vm-hands-entry-lite-5n4vsm6b.js} +2 -2
  34. package/bin/vm-hands/{vm-hands-entry-lite-k7wwza46.js → vm-hands-entry-lite-7xbgw4m0.js} +2 -2
  35. package/bin/vm-hands/vm-hands-entry-lite-8fj07njx.js +3 -0
  36. package/bin/vm-hands/{vm-hands-entry-lite-3hbe4em3.js → vm-hands-entry-lite-9cmfthkq.js} +1 -1
  37. package/bin/vm-hands/{vm-hands-entry-lite-4q8tsaqv.js → vm-hands-entry-lite-9r5tz2dx.js} +2 -2
  38. package/bin/vm-hands/{vm-hands-entry-lite-45j8qwsf.js → vm-hands-entry-lite-9w5vs9zv.js} +1 -1
  39. package/bin/vm-hands/vm-hands-entry-lite-a0yfp7s2.js +251 -0
  40. package/bin/vm-hands/{vm-hands-entry-lite-za55dtte.js → vm-hands-entry-lite-ammr3xbc.js} +2 -2
  41. package/bin/vm-hands/vm-hands-entry-lite-dh5gwmyf.js +3 -0
  42. package/bin/vm-hands/{vm-hands-entry-lite-5pm6bhb8.js → vm-hands-entry-lite-e0gdt6r5.js} +1 -1
  43. package/bin/vm-hands/{vm-hands-entry-lite-5kgvss4p.js → vm-hands-entry-lite-e2mjbqmr.js} +2 -2
  44. package/bin/vm-hands/vm-hands-entry-lite-ejm5er3h.js +7 -0
  45. package/bin/vm-hands/vm-hands-entry-lite-eqhsewc0.js +105 -0
  46. package/bin/vm-hands/{vm-hands-entry-lite-mh0xecf3.js → vm-hands-entry-lite-f02906k8.js} +4 -4
  47. package/bin/vm-hands/vm-hands-entry-lite-f5230h6t.js +67 -0
  48. package/bin/vm-hands/{vm-hands-entry-lite-zh8p7ndn.js → vm-hands-entry-lite-fb5dzy9x.js} +2 -2
  49. package/bin/vm-hands/{vm-hands-entry-lite-yjn6sk08.js → vm-hands-entry-lite-fcrqyxz0.js} +1 -1
  50. package/bin/vm-hands/vm-hands-entry-lite-fyvgav60.js +3 -0
  51. package/bin/vm-hands/vm-hands-entry-lite-g5grabna.js +540 -0
  52. package/bin/vm-hands/vm-hands-entry-lite-g7h6wjqy.js +3 -0
  53. package/bin/vm-hands/{vm-hands-entry-lite-34e71nbe.js → vm-hands-entry-lite-g8pj1jxa.js} +174 -16
  54. package/bin/vm-hands/vm-hands-entry-lite-h1rxv02g.js +458 -0
  55. package/bin/vm-hands/vm-hands-entry-lite-h8dbw0c7.js +4 -0
  56. package/bin/vm-hands/{vm-hands-entry-lite-nhtb458c.js → vm-hands-entry-lite-hnsm5t36.js} +1 -1
  57. package/bin/vm-hands/{vm-hands-entry-lite-0asdf4pm.js → vm-hands-entry-lite-jzcc9h71.js} +3 -3
  58. package/bin/vm-hands/{vm-hands-entry-lite-r6pap1kh.js → vm-hands-entry-lite-ma001vzh.js} +1 -1
  59. package/bin/vm-hands/{vm-hands-entry-lite-anmv8hp7.js → vm-hands-entry-lite-mn64e4pt.js} +286 -104
  60. package/bin/vm-hands/{vm-hands-entry-lite-9cgm6g8t.js → vm-hands-entry-lite-pk3q774c.js} +1 -1
  61. package/bin/vm-hands/vm-hands-entry-lite-qef2ndkd.js +6 -0
  62. package/bin/vm-hands/vm-hands-entry-lite-qnnfvm5r.js +5 -0
  63. package/bin/vm-hands/vm-hands-entry-lite-r8qg3wp1.js +3 -0
  64. package/bin/vm-hands/vm-hands-entry-lite-rd0ak4ye.js +4 -0
  65. package/bin/vm-hands/{vm-hands-entry-lite-00qsbphw.js → vm-hands-entry-lite-rpn0frzb.js} +2 -2
  66. package/bin/vm-hands/{vm-hands-entry-lite-g9rvf5qk.js → vm-hands-entry-lite-rtt2w6c6.js} +1 -1
  67. package/bin/vm-hands/vm-hands-entry-lite-sex82vb1.js +3 -0
  68. package/bin/vm-hands/vm-hands-entry-lite-vcwgh8tr.js +346 -0
  69. package/bin/vm-hands/{vm-hands-entry-lite-dgxxsdwb.js → vm-hands-entry-lite-xrthfx3q.js} +2 -2
  70. package/bin/vm-hands/{vm-hands-entry-lite-kxdw4myj.js → vm-hands-entry-lite-y2s2w174.js} +1 -1
  71. package/bin/vm-hands/{vm-hands-entry-lite-hc3p6r9p.js → vm-hands-entry-lite-zjfr0zh8.js} +2 -2
  72. package/bin/vm-hands/vm-hands-entry-lite.js +1 -1
  73. package/bin/vm-hands/{vm-hands-executor-qssgfea1.js → vm-hands-executor-9p92j0mv.js} +1 -1
  74. package/bin/vm-hands/vm-hands-op-runner-ers4cefp.js +2 -0
  75. package/bin/vm-hands/{vm-hands-runtime-5me6cpmn.js → vm-hands-runtime-en4gj0t0.js} +3 -3
  76. package/bin/vm-hands/worker-sandbox-tgqbmy6b.js +2 -0
  77. package/package.json +1 -1
  78. package/bin/vm-hands/api-af9g18n7.js +0 -2
  79. package/bin/vm-hands/api-credentials-65mrr3tn.js +0 -2
  80. package/bin/vm-hands/connect-cli-j478km3s.js +0 -2
  81. package/bin/vm-hands/desktop-account-5zvgspyw.js +0 -2
  82. package/bin/vm-hands/hands-worker-source-h0b1j53p.js +0 -2
  83. package/bin/vm-hands/local-automation-c86tjeft.js +0 -2
  84. package/bin/vm-hands/local-capabilities-1h99gkt6.js +0 -2
  85. package/bin/vm-hands/local-desktop-users-0hadyvx1.js +0 -2
  86. package/bin/vm-hands/local-display-mac-v1pc7177.js +0 -2
  87. package/bin/vm-hands/local-display-session-tzq0hne8.js +0 -2
  88. package/bin/vm-hands/local-pty-session-hs7rq03x.js +0 -2
  89. package/bin/vm-hands/managed-runtime-5dqaaw1x.js +0 -2
  90. package/bin/vm-hands/package-3cd7cfyv.js +0 -2
  91. package/bin/vm-hands/permissions-vbyqjbyb.js +0 -2
  92. package/bin/vm-hands/serve-service-be739c9s.js +0 -2
  93. package/bin/vm-hands/status-s8ny6men.js +0 -96
  94. package/bin/vm-hands/version-8s4syrp2.js +0 -2
  95. package/bin/vm-hands/vm-hands-entry-lite-1085xsma.js +0 -5
  96. package/bin/vm-hands/vm-hands-entry-lite-4m40gwkf.js +0 -3
  97. package/bin/vm-hands/vm-hands-entry-lite-62wmnm7g.js +0 -540
  98. package/bin/vm-hands/vm-hands-entry-lite-98076n5g.js +0 -62
  99. package/bin/vm-hands/vm-hands-entry-lite-bvbfcp1k.js +0 -4
  100. package/bin/vm-hands/vm-hands-entry-lite-c01eyep6.js +0 -3
  101. package/bin/vm-hands/vm-hands-entry-lite-dcynw6t2.js +0 -3
  102. package/bin/vm-hands/vm-hands-entry-lite-hh24bq0d.js +0 -3
  103. package/bin/vm-hands/vm-hands-entry-lite-jb2sr2r7.js +0 -3
  104. package/bin/vm-hands/vm-hands-entry-lite-kt5aj2ax.js +0 -11
  105. package/bin/vm-hands/vm-hands-entry-lite-n9nnb482.js +0 -459
  106. package/bin/vm-hands/vm-hands-entry-lite-sb9a1jcn.js +0 -4
  107. package/bin/vm-hands/vm-hands-entry-lite-xg3d0a2y.js +0 -340
  108. package/bin/vm-hands/vm-hands-entry-lite-zamt8xp7.js +0 -181
  109. package/bin/vm-hands/vm-hands-entry-lite-ze9msfq1.js +0 -3
  110. package/bin/vm-hands/vm-hands-op-runner-b76rjaps.js +0 -2
  111. package/bin/vm-hands/worker-sandbox-wpzkvwer.js +0 -2
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{$g as S,Gg as w,Hg as m,Ig as q,Jg as B,Kg as L,Lg as W,Mg as F,Og as Q,Qg as j,Rg as k,Sg as J,Tg as z,Ug as Z,Wg as K,Xg as $,Zg as _,_g as G,bh as M,eh as X}from"./vm-hands-entry-lite-za55dtte.js";import{Ci as h}from"./vm-hands-entry-lite-4m40gwkf.js";import{nj as y,oj as p,pj as x,qj as b}from"./vm-hands-entry-lite-9cgm6g8t.js";var s=["cgroup_membership_read_failed","cgroup_v2_membership_absent","cgroup_scope_invalid","cgroup_root_unavailable","cgroup_directory_unavailable","cgroup_limit_read_failed","cgroup_events_read_failed","cgroup_current_read_failed","cgroup_stat_read_failed","boot_id_read_failed","boot_id_invalid","guest_meminfo_read_failed","guest_vmstat_read_failed","memory_counter_invalid","memory_field_missing","memory_capacity_invalid"];var o=String.raw`(function(fs, path) {
2
+ import{Tg as H}from"./vm-hands-entry-lite-2e18tm6w.js";import{$g as Q,Vg as m,Wg as q,Xg as L,Yg as B,Zg as W,_g as F,bh as j,dh as k,eh as z,fh as Z,gh as J,hh as K,jh as $,kh as G,mh as M,nh as s,oh as X,qh as _,th as S}from"./vm-hands-entry-lite-ammr3xbc.js";import{Ri as y}from"./vm-hands-entry-lite-sex82vb1.js";import{Cj as p,Dj as x,Ej as b,Fj as w}from"./vm-hands-entry-lite-pk3q774c.js";import{Dk as Y}from"./vm-hands-entry-lite-f5230h6t.js";var o=["cgroup_membership_read_failed","cgroup_v2_membership_absent","cgroup_scope_invalid","cgroup_root_unavailable","cgroup_directory_unavailable","cgroup_limit_read_failed","cgroup_events_read_failed","cgroup_current_read_failed","cgroup_stat_read_failed","boot_id_read_failed","boot_id_invalid","guest_meminfo_read_failed","guest_vmstat_read_failed","memory_counter_invalid","memory_field_missing","memory_capacity_invalid"];var c=String.raw`(function(fs, path) {
3
3
  const fail = (message, reasonCode) => { throw Object.assign(Error(message), {reasonCode}); };
4
4
  const read = (p, reasonCode, trim=true) => { try { const text=fs.readFileSync(p, "utf8"); return trim?text.trim():text; }
5
5
  catch { fail("memory_read", reasonCode); } };
@@ -64,7 +64,7 @@ import{$g as S,Gg as w,Hg as m,Ig as q,Jg as B,Kg as L,Lg as W,Mg as F,Og as Q,Q
64
64
  if(!Number.isSafeInteger(limitBytes)||limitBytes<=0||!Number.isSafeInteger(available)||available>limitBytes) fail("memory_capacity", "memory_capacity_invalid");
65
65
  return {bootId,oomKills:field(read("/proc/vmstat", "guest_vmstat_read_failed"),"oom_kill"),currentBytes:limitBytes-available,
66
66
  limitBytes,inactiveFileBytes:0,capacitySource:"guest",memoryScope:"/proc"};
67
- })`;var c=String.raw`import os,sys,json,stat,fcntl,time,ctypes
67
+ })`;var u=String.raw`import os,sys,json,stat,fcntl,time,ctypes
68
68
  v=json.load(sys.stdin)
69
69
  root=v['root']; paths=list(dict.fromkeys([v['source'],v['snapshot']]))
70
70
  marker=('# reason-job-env-owner:'+v['runId']+'\n').encode()
@@ -309,7 +309,7 @@ function fileOperation(request) {
309
309
  });
310
310
  return { promise, cancel() {} };
311
311
  }
312
- `;var u="a3e39eb55160acfc116fa9871ccc594c68be7a642d2331b24baa707c8f601ec0";import{createHash as tt}from"crypto";var pt=Object.freeze({"api.ara.so":"api.reasonmachines.com","api.reasonmachines.ai":"api.reasonmachines.com","api-staging.ara.so":"staging-api.reasonmachines.com","staging-api.reasonmachines.ai":"staging-api.reasonmachines.com"});var a=Object.freeze({trailingSlashPattern:/\/+$/.source,keyPrefix:"http.",keySuffix:"/.extraheader",valuePrefix:"Authorization: Bearer "});var d=Object.freeze({tokenEnv:"ARA_GIT_BROKER_TOKEN",reasonTokenEnv:"REASON_GIT_BROKER_TOKEN",urlEnv:"ARA_GIT_BROKER_URL",keyPrefix:"credential.",keySuffix:"/.helper",value:'!f(){ printf "username=%s\\npassword=%s\\n" "ara-run" "${REASON_GIT_BROKER_TOKEN:-$ARA_GIT_BROKER_TOKEN}"; };f'});var r=/^[A-Za-z_][A-Za-z0-9_]*$/;var O=new Set(["ARA_INFERENCE_TOKEN","AI_GATEWAY_API_KEY","CLOUD_AGENT_AI_GATEWAY_API_KEY","INFERENCE_V2_GATEWAY_API_KEY","VERCEL_AI_GATEWAY_API_KEY","INFERENCE_V2_CONCENTRATE_API_KEY","INFERENCE_V2_OPENAI_API_KEY","INFERENCE_V2_ANTHROPIC_API_KEY","INFERENCE_V2_FINGERPRINT_SECRET","OPENAI_API_KEY","OPENROUTER_API_KEY","ANTHROPIC_API_KEY","CODEX_ACCESS_TOKEN","GITHUB_COPILOT_API_KEY","AZURE_OPENAI_API_KEY","AZURE_OPENAI_CLIENT_SECRET"]),I=new Set(["ARA_OPERATOR_KEY","BL_API_KEY","BLAXEL_API_KEY","NSC_TOKEN","NSC_TOKEN_FILE","NAMESPACE_API_KEY","NAMESPACE_ACCESS_TOKEN","NAMESPACE_TOKEN","NAMESPACE_TOKEN_JSON","NAMESPACE_SANDBOX_TOKEN_JSON","ARA_LOCAL_QA_NAMESPACE_WORKLOAD_TOKEN_FILE","NAMESPACE_SANDBOX_USE_LOCAL_USER_TOKEN","COMPUTE_SERVICE_TOKEN"]),T=["INFISICAL_","NSC_"],A=new Set(["ARA_JOB_ENV","ARA_DELIVERY_BASE_SHA","WORK_ROOT","REPO_DIR","ARA_CONTROL_DIR","ARA_PRESERVE_WORKSPACE","ARA_PINNED_CHECKOUT_REUSE","FOLLOWUP_BRANCH","REPO_URL","TOKENLESS_URL","REPOSITORY_IDENTITY_URL","DEFAULT_BRANCH","BRANCH","BRANCH_GENERATED","BASE_REF","REPO_EMPTY","REPO_WRITABLE","ARA_DELIVERY_BASE_BRANCH","ARA_SERVER_GIT_PUBLICATION","ARA_EMPTY_REPOSITORY_COMMIT","REASON_MODEL","REASON_DELIVERY_BASE_BRANCH","REASON_DELIVERY_BASE_SHA","REASON_EMPTY_REPOSITORY_COMMIT","REASON_SCRATCH_SESSION_ID","REASON_SERVER_GIT_PUBLICATION","REASON_ALLOW_INSTALL_SCRIPTS","SCM_TOKEN","SCM_TOKEN_USER","REASON_OIDC_TOKEN_URL","REASON_OIDC_REQUEST_TOKEN","AWS_CONTAINER_CREDENTIALS_FULL_URI","AWS_CONTAINER_AUTHORIZATION_TOKEN","AWS_CONTAINER_CREDENTIALS_RELATIVE_URI","AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE","BASH_ENV","ENV","BASHOPTS","SHELLOPTS","PS4","IFS","CDPATH","GLOBIGNORE","PROMPT_COMMAND","PATH","HOME","TMPDIR","TMP","TEMP","XDG_CONFIG_HOME","GIT_DIR","GIT_WORK_TREE","GIT_INDEX_FILE","GIT_OBJECT_DIRECTORY","GIT_COMMON_DIR","GIT_NAMESPACE","GIT_CEILING_DIRECTORIES","GIT_DISCOVERY_ACROSS_FILESYSTEM","GIT_SHALLOW_FILE","GIT_ALLOW_PROTOCOL","GIT_PROTOCOL_FROM_USER","GIT_REPLACE_REF_BASE","NODE_OPTIONS","NODE_PATH","NODE_REPL_EXTERNAL_MODULES","CLASSPATH","PYTHONPATH","PYTHONSTARTUP","PYTHONHOME","RUBYOPT","RUBYLIB","PERL5LIB","PERL5OPT","JAVA_TOOL_OPTIONS","_JAVA_OPTIONS","JDK_JAVA_OPTIONS","GEM_PATH","GEM_HOME","GIT_SSH","GIT_SSH_COMMAND","GIT_EXEC_PATH","GIT_TEMPLATE_DIR","GIT_ALTERNATE_OBJECT_DIRECTORIES","GIT_PROXY_COMMAND","GIT_EXTERNAL_DIFF","GIT_PAGER","GIT_EDITOR","GIT_ASKPASS","SSH_ASKPASS","PAGER","EDITOR","TAR_OPTIONS","CURL_HOME","WGETRC","APT_CONFIG","PERLLIB","GIT_GRAFT_FILE","POSIXLY_CORRECT"]),D=["GIT_TRACE","CONTEXT_REPO_","ARA_CHECKPOINT_BOOTSTRAP_","_","ARA_HANDS_","ARA_DEVICE_","ARA_GIT_BROKER_","REASON_HANDS_","REASON_DEVICE_","REASON_GIT_BROKER_","LD_","DYLD_","GIT_CONFIG","BASH_FUNC_"];var n="^(?!(?:"+[...O,...I,...A].join("|")+")$)(?!(?:"+[...T,...D].join("|")+"))"+r.source.slice(1),mt=new RegExp(n);var v=["HOME","PWD","OLDPWD","TMPDIR","TMP","TEMP","SHELL","USER","LOGNAME","SCM_TOKEN","SCM_TOKEN_USER","GH_TOKEN","GITHUB_TOKEN","GH_ENTERPRISE_TOKEN","GITHUB_ENTERPRISE_TOKEN","GITLAB_TOKEN"],N=["ARA_HANDS_","ARA_DEVICE_","ARA_GIT_BROKER_","REASON_HANDS_","REASON_DEVICE_","REASON_GIT_BROKER_","BUN_"],U="^(?!(?:"+v.join("|")+")$)(?!(?:"+N.join("|")+"))"+n.slice(1),E="ARA_DELIVERY_BASE_SHA|WORK_ROOT|FOLLOWUP_BRANCH|ARA_PRESERVE_WORKSPACE|ARA_PINNED_CHECKOUT_REUSE|CONTEXT_REPO_[A-Z0-9_]+|REPO_URL|TOKENLESS_URL|REPOSITORY_IDENTITY_URL|DEFAULT_BRANCH|BRANCH|BRANCH_GENERATED|BASE_REF|REPO_EMPTY|REPO_WRITABLE|ARA_DELIVERY_BASE_BRANCH|ARA_SERVER_GIT_PUBLICATION|ARA_EMPTY_REPOSITORY_COMMIT|REASON_MODEL|REASON_DELIVERY_BASE_BRANCH|REASON_DELIVERY_BASE_SHA|REASON_EMPTY_REPOSITORY_COMMIT|REASON_SCRATCH_SESSION_ID|REASON_SERVER_GIT_PUBLICATION|REASON_ALLOW_INSTALL_SCRIPTS",i="^(?:"+E+"|"+U.slice(1,-1)+")$",R=new RegExp(i);function Wt(t){return R.test(t)}var f=Object.freeze({tokenPath:"/identity/token",awsPath:"/identity/aws",tokenPattern:/^[A-Za-z0-9_.~-]+$/.source}),l=Object.freeze({variables:256,valueBytes:130816,snapshotBytes:1048576}),Ft=Object.freeze({valueChars:16384,snapshotBytes:65536});var g=["set -g history-limit 50000","set -g status off","set -g window-size smallest","set -gq fill-character ' '","set -g escape-time 10","set -g prefix None","set -g prefix2 None","set -g terminal-overrides ',*:smcup@:rmcup@'"];var et=2,rt="ara-hands-worker.cjs",Y=["/usr/local/go/bin","/opt/node/bin","/usr/local/bin","/usr/sbin","/usr/bin","/sbin","/bin","/usr/local/cargo/bin"],nt=Y.join(":"),it=["/opt/homebrew/bin",...Y].join(":"),st='(platform, linuxPath, macosPath) => platform === "darwin" ? macosPath : linuxPath';function Ht(t,H,P){return t==="darwin"?P:H}var ot=String.raw`(function(anchor, pid, native) {
312
+ `;var a="a3e39eb55160acfc116fa9871ccc594c68be7a642d2331b24baa707c8f601ec0";import{createHash as rt}from"crypto";var bt=Object.freeze({"api.ara.so":"api.reasonmachines.com","api.reasonmachines.ai":"api.reasonmachines.com","api-staging.ara.so":"staging-api.reasonmachines.com","staging-api.reasonmachines.ai":"staging-api.reasonmachines.com"});var d=Object.freeze({trailingSlashPattern:/\/+$/.source,keyPrefix:"http.",keySuffix:"/.extraheader",valuePrefix:"Authorization: Bearer "});var f=Object.freeze({tokenEnv:"ARA_GIT_BROKER_TOKEN",reasonTokenEnv:"REASON_GIT_BROKER_TOKEN",urlEnv:"ARA_GIT_BROKER_URL",keyPrefix:"credential.",keySuffix:"/.helper",value:'!f(){ printf "username=%s\\npassword=%s\\n" "ara-run" "${REASON_GIT_BROKER_TOKEN:-$ARA_GIT_BROKER_TOKEN}"; };f'});var r=/^[A-Za-z_][A-Za-z0-9_]*$/;var T=new Set(["ARA_INFERENCE_TOKEN","AI_GATEWAY_API_KEY","CLOUD_AGENT_AI_GATEWAY_API_KEY","INFERENCE_V2_GATEWAY_API_KEY","VERCEL_AI_GATEWAY_API_KEY","INFERENCE_V2_CONCENTRATE_API_KEY","INFERENCE_V2_OPENAI_API_KEY","INFERENCE_V2_ANTHROPIC_API_KEY","INFERENCE_V2_FINGERPRINT_SECRET","OPENAI_API_KEY","OPENROUTER_API_KEY","ANTHROPIC_API_KEY","CODEX_ACCESS_TOKEN","GITHUB_COPILOT_API_KEY","AZURE_OPENAI_API_KEY","AZURE_OPENAI_CLIENT_SECRET"]),A=new Set(["ARA_OPERATOR_KEY","BL_API_KEY","BLAXEL_API_KEY","NSC_TOKEN","NSC_TOKEN_FILE","NAMESPACE_API_KEY","NAMESPACE_ACCESS_TOKEN","NAMESPACE_TOKEN","NAMESPACE_TOKEN_JSON","NAMESPACE_SANDBOX_TOKEN_JSON","ARA_LOCAL_QA_NAMESPACE_WORKLOAD_TOKEN_FILE","NAMESPACE_SANDBOX_USE_LOCAL_USER_TOKEN","COMPUTE_SERVICE_TOKEN"]),D=["INFISICAL_","NSC_"],v=new Set(["ARA_JOB_ENV","ARA_DELIVERY_BASE_SHA","WORK_ROOT","REPO_DIR","ARA_CONTROL_DIR","ARA_PRESERVE_WORKSPACE","ARA_PINNED_CHECKOUT_REUSE","FOLLOWUP_BRANCH","REPO_URL","TOKENLESS_URL","REPOSITORY_IDENTITY_URL","DEFAULT_BRANCH","BRANCH","BRANCH_GENERATED","BASE_REF","REPO_EMPTY","REPO_WRITABLE","ARA_DELIVERY_BASE_BRANCH","ARA_SERVER_GIT_PUBLICATION","ARA_EMPTY_REPOSITORY_COMMIT","REASON_MODEL","REASON_DELIVERY_BASE_BRANCH","REASON_DELIVERY_BASE_SHA","REASON_EMPTY_REPOSITORY_COMMIT","REASON_SCRATCH_SESSION_ID","REASON_SERVER_GIT_PUBLICATION","REASON_ALLOW_INSTALL_SCRIPTS","SCM_TOKEN","SCM_TOKEN_USER","REASON_OIDC_TOKEN_URL","REASON_OIDC_REQUEST_TOKEN","AWS_CONTAINER_CREDENTIALS_FULL_URI","AWS_CONTAINER_AUTHORIZATION_TOKEN","AWS_CONTAINER_CREDENTIALS_RELATIVE_URI","AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE","BASH_ENV","ENV","BASHOPTS","SHELLOPTS","PS4","IFS","CDPATH","GLOBIGNORE","PROMPT_COMMAND","PATH","HOME","TMPDIR","TMP","TEMP","XDG_CONFIG_HOME","GIT_DIR","GIT_WORK_TREE","GIT_INDEX_FILE","GIT_OBJECT_DIRECTORY","GIT_COMMON_DIR","GIT_NAMESPACE","GIT_CEILING_DIRECTORIES","GIT_DISCOVERY_ACROSS_FILESYSTEM","GIT_SHALLOW_FILE","GIT_ALLOW_PROTOCOL","GIT_PROTOCOL_FROM_USER","GIT_REPLACE_REF_BASE","NODE_OPTIONS","NODE_PATH","NODE_REPL_EXTERNAL_MODULES","CLASSPATH","PYTHONPATH","PYTHONSTARTUP","PYTHONHOME","RUBYOPT","RUBYLIB","PERL5LIB","PERL5OPT","JAVA_TOOL_OPTIONS","_JAVA_OPTIONS","JDK_JAVA_OPTIONS","GEM_PATH","GEM_HOME","GIT_SSH","GIT_SSH_COMMAND","GIT_EXEC_PATH","GIT_TEMPLATE_DIR","GIT_ALTERNATE_OBJECT_DIRECTORIES","GIT_PROXY_COMMAND","GIT_EXTERNAL_DIFF","GIT_PAGER","GIT_EDITOR","GIT_ASKPASS","SSH_ASKPASS","PAGER","EDITOR","TAR_OPTIONS","CURL_HOME","WGETRC","APT_CONFIG","PERLLIB","GIT_GRAFT_FILE","POSIXLY_CORRECT"]),N=["GIT_TRACE","CONTEXT_REPO_","ARA_CHECKPOINT_BOOTSTRAP_","_","ARA_HANDS_","ARA_DEVICE_","ARA_GIT_BROKER_","REASON_HANDS_","REASON_DEVICE_","REASON_GIT_BROKER_","LD_","DYLD_","GIT_CONFIG","BASH_FUNC_"];var n="^(?!(?:"+[...T,...A,...v].join("|")+")$)(?!(?:"+[...D,...N].join("|")+"))"+r.source.slice(1),Lt=new RegExp(n);var U=["HOME","PWD","OLDPWD","TMPDIR","TMP","TEMP","SHELL","USER","LOGNAME","SCM_TOKEN","SCM_TOKEN_USER","GH_TOKEN","GITHUB_TOKEN","GH_ENTERPRISE_TOKEN","GITHUB_ENTERPRISE_TOKEN","GITLAB_TOKEN"],R=["ARA_HANDS_","ARA_DEVICE_","ARA_GIT_BROKER_","REASON_HANDS_","REASON_DEVICE_","REASON_GIT_BROKER_","BUN_"],E="^(?!(?:"+U.join("|")+")$)(?!(?:"+R.join("|")+"))"+n.slice(1),tt="ARA_DELIVERY_BASE_SHA|WORK_ROOT|FOLLOWUP_BRANCH|ARA_PRESERVE_WORKSPACE|ARA_PINNED_CHECKOUT_REUSE|CONTEXT_REPO_[A-Z0-9_]+|REPO_URL|TOKENLESS_URL|REPOSITORY_IDENTITY_URL|DEFAULT_BRANCH|BRANCH|BRANCH_GENERATED|BASE_REF|REPO_EMPTY|REPO_WRITABLE|ARA_DELIVERY_BASE_BRANCH|ARA_SERVER_GIT_PUBLICATION|ARA_EMPTY_REPOSITORY_COMMIT|REASON_MODEL|REASON_DELIVERY_BASE_BRANCH|REASON_DELIVERY_BASE_SHA|REASON_EMPTY_REPOSITORY_COMMIT|REASON_SCRATCH_SESSION_ID|REASON_SERVER_GIT_PUBLICATION|REASON_ALLOW_INSTALL_SCRIPTS",i="^(?:"+tt+"|"+E.slice(1,-1)+")$",et=new RegExp(i);function Qt(t){return et.test(t)}var l=Object.freeze({tokenPath:"/identity/token",awsPath:"/identity/aws",tokenPattern:/^[A-Za-z0-9_.~-]+$/.source}),g=Object.freeze({variables:256,valueBytes:130816,snapshotBytes:1048576}),jt=Object.freeze({valueChars:16384,snapshotBytes:65536});var h=["set -g history-limit 50000","set -g status off","set -g window-size smallest","set -gq fill-character ' '","set -g escape-time 10","set -g prefix None","set -g prefix2 None","set -g terminal-overrides ',*:smcup@:rmcup@'"];var nt=2,it="ara-hands-worker.cjs",P=["/usr/local/go/bin","/opt/node/bin","/usr/local/bin","/usr/sbin","/usr/bin","/sbin","/bin","/usr/local/cargo/bin"],st=P.join(":"),ot=["/opt/homebrew/bin",...P].join(":"),ct='(platform, linuxPath, macosPath) => platform === "darwin" ? macosPath : linuxPath';function It(t,V,C){return t==="darwin"?C:V}var ut=String.raw`(function(anchor, pid, native) {
313
313
  const token = native.identity(pid);
314
314
  const session = native.session(pid);
315
315
  if (!native.same(anchor)) throw new Error("pty_session_identity_lost");
@@ -317,7 +317,7 @@ function fileOperation(request) {
317
317
  if (session.id !== anchor[5]) throw new Error("pty_member_session_changed");
318
318
  if (!token) return { retry: true, token: null };
319
319
  return { retry: false, token };
320
- })`,ct=String.raw`(function(native) {
320
+ })`,at=String.raw`(function(native) {
321
321
  let probe;
322
322
  try {
323
323
  try {
@@ -327,7 +327,7 @@ function fileOperation(request) {
327
327
  native.signal(probe);
328
328
  } finally { if (probe) native.release(probe); }
329
329
  } catch (error) { native.close(); throw error; }
330
- })`,ut=String.raw`(function(bootstrap) {
330
+ })`,dt=String.raw`(function(bootstrap) {
331
331
  const { dlopen, ptr } = require("bun:ffi");
332
332
  const api = dlopen("libc.so.6", {
333
333
  prctl: { args: ["i32", "u64", "u64", "u64", "u64"], returns: "i32" },
@@ -348,7 +348,7 @@ function fileOperation(request) {
348
348
  require("node:fs").writeSync(3, "subreaper\n");
349
349
  api.execve(ptr(args[0]), ptr(argv), ptr(envp));
350
350
  throw new Error("pty_exec_failed");
351
- })`,at=String.raw`
351
+ })`,ft=String.raw`
352
352
  "use strict";
353
353
  const crypto = require("node:crypto");
354
354
  const fs = require("node:fs");
@@ -356,43 +356,110 @@ const net = require("node:net");
356
356
  const path = require("node:path");
357
357
  const { spawn, spawnSync } = require("node:child_process");
358
358
  const { StringDecoder } = require("node:string_decoder");
359
- const GIT_BROKER_HTTP_HEADER_POLICY = ${JSON.stringify(a)};
360
- const GIT_BROKER_CREDENTIAL_HELPER_POLICY = ${JSON.stringify(d)};
359
+ const GIT_BROKER_HTTP_HEADER_POLICY = ${JSON.stringify(d)};
360
+ const GIT_BROKER_CREDENTIAL_HELPER_POLICY = ${JSON.stringify(f)};
361
361
  const DEVICE_ENVIRONMENT_NAME_RE = new RegExp(${JSON.stringify(i)});
362
- const DEVICE_CLOUD_ACCESS_POLICY = ${JSON.stringify(f)};
363
- const DEVICE_ENVIRONMENT_LIMITS = ${JSON.stringify(l)};
362
+ const DEVICE_CLOUD_ACCESS_POLICY = ${JSON.stringify(l)};
363
+ const DEVICE_ENVIRONMENT_LIMITS = ${JSON.stringify(g)};
364
364
 
365
- const VERSION = ${q};
366
- const WORKER_VERSION = ${et};
367
- const WORKER_ENTRYPOINT = ${JSON.stringify(rt)};
368
- const GUEST_MEMORY_UNAVAILABLE_REASONS = ${JSON.stringify(s)};
369
- const sampleGuestMemory = ${o};
370
- const inspectMacPtyMember = ${ot};
371
- const probeLinuxPtyLibrary = ${ct};
372
- const LINUX_PTY_EXEC_SOURCE = ${JSON.stringify(ut)};
373
- const CLOSE_CODES = ${JSON.stringify(M)};
365
+ const VERSION = ${L};
366
+ const WORKER_VERSION = ${nt};
367
+ const WORKER_ENTRYPOINT = ${JSON.stringify(it)};
368
+ const GUEST_MEMORY_UNAVAILABLE_REASONS = ${JSON.stringify(o)};
369
+ const sampleGuestMemory = ${c};
370
+ const inspectMacPtyMember = ${ut};
371
+ const probeLinuxPtyLibrary = ${at};
372
+ const windowsPtyApi = ${H};
373
+ const LINUX_PTY_EXEC_SOURCE = ${JSON.stringify(dt)};
374
+ const CLOSE_CODES = ${JSON.stringify(_)};
374
375
  const SHA256_RE = /^[0-9a-f]{64}$/;
375
376
  const MAX_FRAME_BYTES = ${B};
376
- const MAX_INPUT_CHARS = ${L};
377
- const MAX_STRUCTURED_INPUT_CHARS = ${W};
378
- const MAX_OUTPUT_CHARS = ${F};
379
- const WORKSPACE_BEFORE_MAX_OUTPUT_CHARS = ${X};
380
- const MAX_ERROR_CHARS = ${Q};
377
+ const MAX_INPUT_CHARS = ${W};
378
+ const MAX_STRUCTURED_INPUT_CHARS = ${F};
379
+ const MAX_OUTPUT_CHARS = ${Q};
380
+ const WORKSPACE_BEFORE_MAX_OUTPUT_CHARS = ${S};
381
+ const MAX_ERROR_CHARS = ${j};
381
382
  const MAX_LEDGER_IDS = 16384;
382
383
  const MAX_CACHED_RESULTS = 256;
383
- const MAX_JOB_INPUT_CHARS = ${j};
384
- const MAX_JOB_OUTPUT_CHARS = ${k};
385
- const MAX_JOB_OUTPUT_CHUNKS = ${J};
386
- const MAX_JOBS = ${z};
384
+ const MAX_JOB_INPUT_CHARS = ${k};
385
+ const MAX_JOB_OUTPUT_CHARS = ${z};
386
+ const MAX_JOB_OUTPUT_CHUNKS = ${Z};
387
+ const MAX_JOBS = ${J};
387
388
  const MAX_JOB_RECORD_BYTES = 262144;
388
389
  const MAX_JOB_JOURNAL_BYTES = MAX_JOBS * MAX_JOB_RECORD_BYTES;
389
- const MAX_JOB_CONTROL_FRAME_BYTES = ${Z};
390
- const MAX_PTY_INPUT_BYTES = ${K};
391
- const MAX_PTY_OUTPUT_BYTES = ${$};
392
- const MAX_PTY_DIMENSION = ${_};
390
+ const MAX_JOB_CONTROL_FRAME_BYTES = ${K};
391
+ const MAX_PTY_INPUT_BYTES = ${$};
392
+ const MAX_PTY_OUTPUT_BYTES = ${G};
393
+ const MAX_PTY_DIMENSION = ${M};
393
394
  const ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,199}$/;
394
395
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
395
- const FIXED_BASH = "/bin/bash";
396
+ const WINDOWS = process.platform === "win32";
397
+ // Each Bash leader's tree on Windows, children that outlive it included (shared/windows-job-object.ts).
398
+ const windowsJobs = WINDOWS ? ${Y}(require) : null;
399
+ /** Windows has no POSIX owner or mode bits: the user's own profile folders are
400
+ * private by their ACLs, and the worker runs as that ordinary user. */
401
+ function ownedPrivately(stat, mask = 0o077) {
402
+ return WINDOWS || (stat.uid === process.getuid() && (stat.mode & mask) === 0);
403
+ }
404
+ /** Windows cannot open (or fsync) a directory; its renames are durable by NTFS journaling. */
405
+ function syncDirectory(directory) {
406
+ if (WINDOWS) return;
407
+ const directoryFd = fs.openSync(directory, fs.constants.O_RDONLY);
408
+ try { fs.fsyncSync(directoryFd); } finally { fs.closeSync(directoryFd); }
409
+ }
410
+ /** Path containment; Windows paths compare case-insensitively. */
411
+ function pathWithin(candidate, root) {
412
+ const [child, parent] = WINDOWS ? [candidate.toLowerCase(), root.toLowerCase()] : [candidate, root];
413
+ return child === parent || child.startsWith(parent + path.sep);
414
+ }
415
+ /** Git Bash's form of a Windows path (C:\Users\me is /c/Users/me): every path
416
+ * this worker sends or sets as a shell coordinate, since the server and its
417
+ * scripts speak POSIX. Unchanged off Windows. */
418
+ function posixPath(value) {
419
+ if (!WINDOWS) return value;
420
+ const drive = /^([A-Za-z]):(?:[\\/](.*))?$/.exec(value);
421
+ if (!drive) return value.replace(/\\/g, "/");
422
+ return "/" + drive[1].toLowerCase() + (drive[2] ? "/" + drive[2].replace(/\\/g, "/") : "");
423
+ }
424
+ /** A path from the server or the model as Node opens it on Windows: /c/Users/me,
425
+ * C:/Users/me and C:\Users\me name the same file, and /tmp is the shell's
426
+ * TEMP (Git Bash mounts it there). Relative paths are unchanged. */
427
+ function nativePath(value) {
428
+ if (!WINDOWS || typeof value !== "string") return value;
429
+ const temporary = /^\/tmp(?:\/(.*))?$/.exec(value);
430
+ if (temporary) return nativePath(path.join(config.executionEnvironment?.temporaryDirectory ?? config.workRoot, temporary[1] || ""));
431
+ const drive = /^\/([A-Za-z])(?:\/(.*))?$/.exec(value);
432
+ if (drive) return drive[1].toUpperCase() + ":\\" + (drive[2] || "").replace(/\//g, "\\");
433
+ return /^[A-Za-z]:\//.test(value) ? value.replace(/\//g, "\\") : value;
434
+ }
435
+ /** The request with its file path as nativePath gives it (Windows only); the
436
+ * journal and every result keep the request as the server sent it. */
437
+ function nativePathRequest(request) {
438
+ const input = request.input;
439
+ if (!WINDOWS) return request;
440
+ if (["read", "edit", "write"].includes(request.tool) && typeof input.path === "string") {
441
+ return { ...request, input: { ...input, path: nativePath(input.path) } };
442
+ }
443
+ if (request.tool === "pi_tool" && input.tool !== "bash" && typeof input.args.path === "string") {
444
+ return { ...request, input: { ...input, args: { ...input.args, path: nativePath(input.args.path) } } };
445
+ }
446
+ return request;
447
+ }
448
+ const filesystemRoot = (value) => path.parse(value).root === value;
449
+ // A Windows managed job's control endpoint is a named pipe of its own.
450
+ const validWindowsPipe = (value) => WINDOWS && typeof value === "string" && /^\\\\\.\\pipe\\reason-[A-Za-z0-9._-]{1,200}$/.test(value);
451
+ // Windows programs need these system coordinates (Winsock, crypto, profile
452
+ // folders); a composed environment carries them from the worker's own.
453
+ const WINDOWS_SYSTEM_VARIABLES = ["SystemRoot", "SystemDrive", "windir", "ComSpec", "PATHEXT", "USERPROFILE", "USERNAME",
454
+ "USERDOMAIN", "COMPUTERNAME", "APPDATA", "LOCALAPPDATA", "ProgramData", "ProgramFiles", "ProgramFiles(x86)", "ProgramW6432",
455
+ "CommonProgramFiles", "CommonProgramFiles(x86)", "CommonProgramW6432", "NUMBER_OF_PROCESSORS", "PROCESSOR_ARCHITECTURE", "OS", "PSModulePath"];
456
+ function windowsSystemVariables() {
457
+ if (!WINDOWS) return {};
458
+ return Object.fromEntries(WINDOWS_SYSTEM_VARIABLES.flatMap((name) => {
459
+ const value = process.env[name];
460
+ return typeof value === "string" && value.length <= 32768 && !value.includes("\0") ? [[name, value]] : [];
461
+ }));
462
+ }
396
463
  /** A Reason cloud machine's memory ceiling, which guestd records on every
397
464
  * start (/run/sc/memory-max-mib), or 0 elsewhere. Read per command: a resize
398
465
  * changes it. */
@@ -425,10 +492,11 @@ function jobsUserPrefix(model) {
425
492
  return user ? ["/usr/bin/setpriv", "--reuid=" + user.uid, "--regid=" + gid, "--clear-groups", "--no-new-privs", "--",
426
493
  "/usr/bin/env", "HOME=" + user.home, "USER=" + user.username, "LOGNAME=" + user.username] : [];
427
494
  }
428
- const FIXED_CLOUD_CHILD_PATH = ${JSON.stringify(nt)};
429
- const FIXED_MACOS_CLOUD_CHILD_PATH = ${JSON.stringify(it)};
430
- const selectCloudChildPath = ${st};
495
+ const FIXED_CLOUD_CHILD_PATH = ${JSON.stringify(st)};
496
+ const FIXED_MACOS_CLOUD_CHILD_PATH = ${JSON.stringify(ot)};
497
+ const selectCloudChildPath = ${ct};
431
498
  const config = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
499
+ const FIXED_BASH = WINDOWS ? config.bashExecutable : "/bin/bash";
432
500
  const allowedTools = config.allowedTools === undefined
433
501
  ? ["bash", "repl", "read", "edit", "write"]
434
502
  : config.allowedTools;
@@ -455,7 +523,7 @@ function validEnvironmentConfiguration() {
455
523
  || (baseline.variables !== undefined && !validHostVariables(baseline.variables))
456
524
  || ![baseline.home, baseline.temporaryDirectory].every(value => validPath(value) && value.length <= 32768 && !/[\r\n]/.test(value))
457
525
  || typeof baseline.path !== "string" || baseline.path.length > 32768
458
- || !baseline.path.split(":").every(value => validPath(value) && !/[\r\n]/.test(value)))) return false;
526
+ || !baseline.path.split(path.delimiter).every(value => validPath(value) && !/[\r\n]/.test(value)))) return false;
459
527
  if (config.environmentSnapshotPath === undefined) return config.environmentExpectedBinding === undefined;
460
528
  const authority = config.environmentExpectedBinding;
461
529
  if (!validPath(config.environmentSnapshotPath) || path.basename(config.environmentSnapshotPath) !== "environment.json"
@@ -492,7 +560,7 @@ const validPrivateJob = config.transport === "local_job_ipc" && config.url === "
492
560
  && config.workRoot === config.workspaceAliasPath && config.environmentSnapshotPath === undefined
493
561
  && config.jobEnvSourcePath === undefined && config.spawnPolicy === undefined && config.managedPty === undefined
494
562
  && hasOnlyKeys(config.directShell, ["mode", "executable", "jobId"]) && UUID_RE.test(config.directShell.jobId)
495
- && validPath(config.directShell.executable) && ["bash", "zsh"].includes(path.basename(config.directShell.executable))
563
+ && validPath(config.directShell.executable) && ["bash", "zsh"].includes(path.basename(config.directShell.executable, WINDOWS ? ".exe" : undefined))
496
564
  && (config.directShell.mode === "host" ? config.bashCommandPrefix === undefined
497
565
  : config.directShell.mode === "confined" && process.platform === "darwin"
498
566
  && config.bashCommandPrefix?.length === 3 && config.bashCommandPrefix[0] === "/usr/bin/sandbox-exec"
@@ -509,12 +577,12 @@ function validJobEnvSourcePath() {
509
577
  if (config.jobEnvSourcePath === undefined || config.jobEnvSourcePath === path.join(config.workRoot, "job.env")) return true;
510
578
  // A cloud workspace's job.env is in its Session's root-only control
511
579
  // directory (shared/device-workspace.ts), derived from the root alone.
512
- const cloud = new RegExp(${JSON.stringify(b.source)}).exec(config.workRoot);
580
+ const cloud = new RegExp(${JSON.stringify(w.source)}).exec(config.workRoot);
513
581
  if (process.platform === "linux" && cloud) {
514
582
  const workspaceId = cloud[3];
515
- const owner = (new RegExp(${JSON.stringify(p.source)}).exec(workspaceId) || [])[1]
516
- ?? (new RegExp(${JSON.stringify(x.source)}).exec(workspaceId) || [])[1] ?? workspaceId;
517
- return config.jobEnvSourcePath === ${JSON.stringify(y)} + "/" + owner + "/job.env";
583
+ const owner = (new RegExp(${JSON.stringify(x.source)}).exec(workspaceId) || [])[1]
584
+ ?? (new RegExp(${JSON.stringify(b.source)}).exec(workspaceId) || [])[1] ?? workspaceId;
585
+ return config.jobEnvSourcePath === ${JSON.stringify(p)} + "/" + owner + "/job.env";
518
586
  }
519
587
  // Personal Cloud controls are root-owned and outside the writable grant.
520
588
  // Admit only the same canonical session, never a caller-selected private path.
@@ -544,11 +612,13 @@ if (
544
612
  (config.terminalCleanupRunId !== undefined && (!UUID_RE.test(config.terminalCleanupRunId) || config.terminalCleanupRunId !== config.browserRunId)) ||
545
613
  (config.terminalDaemonNonce !== undefined && (!UUID_RE.test(config.terminalDaemonNonce) || !config.terminalCleanupRunId)) ||
546
614
  (config.browserRunId !== undefined && (typeof config.browserRunId !== "string" || !UUID_RE.test(config.browserRunId))) ||
547
- config.workRoot === "/" || config.workspaceAliasPath === "/" ||
615
+ filesystemRoot(config.workRoot) || filesystemRoot(config.workspaceAliasPath) ||
548
616
  (config.workRoot !== config.workspaceAliasPath && (
549
- config.workRoot.startsWith(config.workspaceAliasPath + "/") ||
550
- config.workspaceAliasPath.startsWith(config.workRoot + "/")
617
+ pathWithin(config.workRoot, config.workspaceAliasPath) ||
618
+ pathWithin(config.workspaceAliasPath, config.workRoot)
551
619
  )) ||
620
+ (WINDOWS ? !validPath(config.bashExecutable) || path.basename(config.bashExecutable).toLowerCase() !== "bash.exe"
621
+ : config.bashExecutable !== undefined) ||
552
622
  typeof config.launchId !== "string" || !/^[a-f0-9-]{36}$/.test(config.launchId) ||
553
623
  !Number.isSafeInteger(config.expiresAtMs) || config.expiresAtMs <= Date.now() ||
554
624
  !validTimeout(config.bashTimeoutMs) || !validTimeout(config.replTimeoutMs) ||
@@ -580,8 +650,8 @@ if (
580
650
  config.bashCommandPrefix !== undefined || config.jobEnvSourcePath !== undefined
581
651
  )) ||
582
652
  (config.jobControlSocketPath !== undefined && (
583
- !config.managedJobs || !validPath(config.jobControlSocketPath) ||
584
- path.basename(config.jobControlSocketPath) !== "control.sock" || Buffer.byteLength(config.jobControlSocketPath) > 100
653
+ !config.managedJobs || (WINDOWS ? !validWindowsPipe(config.jobControlSocketPath) : !validPath(config.jobControlSocketPath) ||
654
+ path.basename(config.jobControlSocketPath) !== "control.sock" || Buffer.byteLength(config.jobControlSocketPath) > 100)
585
655
  )) ||
586
656
  !Array.isArray(allowedTools) || allowedTools.length < 1 || allowedTools.length > 5 ||
587
657
  new Set(allowedTools).size !== allowedTools.length ||
@@ -752,7 +822,7 @@ function failure(id, exitCode, error, stdout, stderr, responseGeneration = targe
752
822
  exitCode: Number.isSafeInteger(exitCode) && exitCode > 0 && exitCode <= 255 ? exitCode : 1,
753
823
  stdout: clip(stdout || "", MAX_OUTPUT_CHARS),
754
824
  stderr: clip(stderr || "", MAX_OUTPUT_CHARS),
755
- cwd: config.repoPath,
825
+ cwd: posixPath(config.repoPath),
756
826
  error: clip(error, MAX_ERROR_CHARS),
757
827
  };
758
828
  }
@@ -765,7 +835,7 @@ function success(id, stdout, stderr, responseGeneration = targetGeneration) {
765
835
  exitCode: 0,
766
836
  stdout: clip(stdout || "", MAX_OUTPUT_CHARS),
767
837
  stderr: clip(stderr || "", MAX_OUTPUT_CHARS),
768
- cwd: config.repoPath,
838
+ cwd: posixPath(config.repoPath),
769
839
  };
770
840
  }
771
841
  // The code alone names the reason: Bun's WebSocket client drops close text.
@@ -906,7 +976,7 @@ function privateJournalRead(name, maxBytes = MAX_JOB_RECORD_BYTES) {
906
976
  const fd = fs.openSync(path.join(journalDirectory, name), fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
907
977
  try {
908
978
  const stat = fs.fstatSync(fd);
909
- if (!stat.isFile() || stat.uid !== process.getuid() || (stat.mode & 0o077) !== 0 || stat.size > maxBytes) {
979
+ if (!stat.isFile() || !ownedPrivately(stat) || stat.size > maxBytes) {
910
980
  throw new Error("invalid_job_journal");
911
981
  }
912
982
  return { value: JSON.parse(fs.readFileSync(fd, "utf8")), bytes: stat.size };
@@ -927,8 +997,7 @@ function privateJournalWrite(name, encoded, maxBytes = MAX_JOB_RECORD_BYTES, dur
927
997
  try { fs.writeFileSync(fd, encoded); if (durable) fs.fsyncSync(fd); } finally { fs.closeSync(fd); }
928
998
  fs.renameSync(temp, target);
929
999
  if (!durable) return bytes;
930
- const directoryFd = fs.openSync(path.dirname(target), fs.constants.O_RDONLY);
931
- try { fs.fsyncSync(directoryFd); } finally { fs.closeSync(directoryFd); }
1000
+ syncDirectory(path.dirname(target));
932
1001
  return bytes;
933
1002
  }
934
1003
  function journalScope(generation, fenceId) {
@@ -958,10 +1027,10 @@ function initializeJobs() {
958
1027
  // (shared/local-protected-paths.ts) that the file tools and every confinement
959
1028
  // refuse. A home-folder worker keeps it in ~/.config/reason, so its Session may
960
1029
  // work in the home folder itself, as a Mac's home grant does.
961
- const PROTECTED_STATE_DIRECTORIES = ${JSON.stringify(h)};
1030
+ const PROTECTED_STATE_DIRECTORIES = ${JSON.stringify(y)};
962
1031
  function stateOverlapsWorkspace(state, root) {
963
- if (state === root || root.startsWith(state + path.sep)) return true;
964
- if (!state.startsWith(root + path.sep)) return false;
1032
+ if (pathWithin(root, state)) return true;
1033
+ if (!pathWithin(state, root)) return false;
965
1034
  const segments = state.slice(root.length + 1).toLowerCase().split(path.sep);
966
1035
  return !PROTECTED_STATE_DIRECTORIES.some((sequence) => segments.some((_, start) =>
967
1036
  sequence.every((part, offset) => segments[start + offset] === part)));
@@ -971,7 +1040,7 @@ function prepareJournalDirectory() {
971
1040
  const candidate = config.managedJobs.journalDirectory;
972
1041
  try { initializeJobs(); } catch (error) { if (error.code !== "EEXIST") throw error; }
973
1042
  const stat = fs.lstatSync(candidate);
974
- if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid() || (stat.mode & 0o077) !== 0) throw new Error("invalid_job_journal");
1043
+ if (!stat.isDirectory() || stat.isSymbolicLink() || !ownedPrivately(stat)) throw new Error("invalid_job_journal");
975
1044
  journalDirectory = fs.realpathSync(candidate);
976
1045
  for (const root of [config.repoPath, config.workRoot]) {
977
1046
  const canonical = fs.realpathSync(root);
@@ -991,8 +1060,7 @@ function acquireJournalOwnership() {
991
1060
  executorLaunchId: config.launchId, workerArtifactSha256: config.workerArtifactSha256,
992
1061
  pid: process.pid, createdAtMs: Date.now() }));
993
1062
  fs.fsyncSync(fd);
994
- const directoryFd = fs.openSync(journalDirectory, fs.constants.O_RDONLY);
995
- try { fs.fsyncSync(directoryFd); } finally { fs.closeSync(directoryFd); }
1063
+ syncDirectory(journalDirectory);
996
1064
  }
997
1065
  function releaseJournalOwnership() {
998
1066
  if (!journalOwnership) return;
@@ -1002,8 +1070,7 @@ function releaseJournalOwnership() {
1002
1070
  fs.unlinkSync(owned.path);
1003
1071
  fs.closeSync(owned.fd);
1004
1072
  journalOwnership = null;
1005
- const directoryFd = fs.openSync(journalDirectory, fs.constants.O_RDONLY);
1006
- try { fs.fsyncSync(directoryFd); } finally { fs.closeSync(directoryFd); }
1073
+ syncDirectory(journalDirectory);
1007
1074
  }
1008
1075
  function loadJobs() {
1009
1076
  if (!config.managedJobs) return;
@@ -1084,7 +1151,7 @@ function loadJobs() {
1084
1151
  for (const name of fs.readdirSync(journalDirectory)) {
1085
1152
  if (!/^[0-9a-f]{64}\.job\.json\.tmp$/.test(name)) continue;
1086
1153
  const stat = fs.lstatSync(path.join(journalDirectory, name));
1087
- if (!stat.isFile() || stat.uid !== process.getuid() || (stat.mode & 0o077) !== 0 || stat.size > MAX_JOB_RECORD_BYTES) throw new Error("invalid_job_journal");
1154
+ if (!stat.isFile() || !ownedPrivately(stat) || stat.size > MAX_JOB_RECORD_BYTES) throw new Error("invalid_job_journal");
1088
1155
  journalDebrisBytes += stat.size;
1089
1156
  reservedBytes += stat.size;
1090
1157
  if (reservedBytes > MAX_JOB_JOURNAL_BYTES) throw new Error("job_journal_full");
@@ -1305,7 +1372,7 @@ async function handleTerminalCleanup(target, claim, raw) {
1305
1372
  let child, timer, killTimer;
1306
1373
  const finish = ok => { clearTimeout(timer); clearTimeout(killTimer); if (!ok) cleanupUnconfirmed = true; resolve(ok); };
1307
1374
  try {
1308
- child = spawn("/usr/bin/python3", ["-I", "-c", ${JSON.stringify(c)}],
1375
+ child = spawn("/usr/bin/python3", ["-I", "-c", ${JSON.stringify(u)}],
1309
1376
  { stdio: ["pipe", "ignore", "ignore"], env: { PATH: "/usr/bin:/bin" }, detached: true });
1310
1377
  let timedOut = false;
1311
1378
  timer = setTimeout(() => { timedOut = true; try { process.kill(-child.pid, "SIGTERM"); } catch { cleanupUnconfirmed = true; }
@@ -1468,21 +1535,24 @@ async function handleJob(claim, raw, sendReply, isCurrent, fromControl = false)
1468
1535
  function startJobControl() {
1469
1536
  if (!config.jobControlSocketPath) return Promise.resolve();
1470
1537
  return new Promise((resolve, reject) => {
1471
- const directory = path.dirname(config.jobControlSocketPath);
1472
- const stat = fs.lstatSync(directory);
1473
- if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid()
1474
- || (stat.mode & 0o777) !== 0o700 || fs.realpathSync(directory) !== directory
1475
- || path.join(directory, "control.sock") !== config.jobControlSocketPath) throw new Error("invalid_job_control_directory");
1476
- for (const root of [config.repoPath, config.workRoot]) {
1477
- const canonical = fs.realpathSync(root);
1478
- if (directory === canonical || directory.startsWith(canonical + path.sep) || canonical.startsWith(directory + path.sep)) {
1479
- throw new Error("job_control_overlaps_workspace");
1538
+ // A Windows named pipe has no directory; a second server on the same name fails to listen.
1539
+ if (!WINDOWS) {
1540
+ const directory = path.dirname(config.jobControlSocketPath);
1541
+ const stat = fs.lstatSync(directory);
1542
+ if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid()
1543
+ || (stat.mode & 0o777) !== 0o700 || fs.realpathSync(directory) !== directory
1544
+ || path.join(directory, "control.sock") !== config.jobControlSocketPath) throw new Error("invalid_job_control_directory");
1545
+ for (const root of [config.repoPath, config.workRoot]) {
1546
+ const canonical = fs.realpathSync(root);
1547
+ if (pathWithin(directory, canonical) || pathWithin(canonical, directory)) {
1548
+ throw new Error("job_control_overlaps_workspace");
1549
+ }
1480
1550
  }
1551
+ // lstat also rejects dangling symlinks; never unlink or adopt an existing
1552
+ // endpoint. An exclusive per-launch directory is composition-owned.
1553
+ try { fs.lstatSync(config.jobControlSocketPath); throw new Error("job_control_path_exists"); }
1554
+ catch (error) { if (error.code !== "ENOENT") throw error; }
1481
1555
  }
1482
- // lstat also rejects dangling symlinks; never unlink or adopt an existing
1483
- // endpoint. An exclusive per-launch directory is composition-owned.
1484
- try { fs.lstatSync(config.jobControlSocketPath); throw new Error("job_control_path_exists"); }
1485
- catch (error) { if (error.code !== "ENOENT") throw error; }
1486
1556
  // Bind before connecting the relay so a duplicate/stale socket cannot leave
1487
1557
  // a second serving worker. Single framed request per connection, bounded
1488
1558
  // clients/body/time; the existing job handler owns all mutations.
@@ -1517,7 +1587,7 @@ function startJobControl() {
1517
1587
  server.maxConnections = 16;
1518
1588
  server.once("error", reject);
1519
1589
  server.listen(config.jobControlSocketPath, () => {
1520
- try { fs.chmodSync(config.jobControlSocketPath, 0o600); }
1590
+ try { if (!WINDOWS) fs.chmodSync(config.jobControlSocketPath, 0o600); }
1521
1591
  catch (error) { server.close(); reject(error); return; }
1522
1592
  jobControlServer = server;
1523
1593
  resolve();
@@ -1556,9 +1626,17 @@ async function handleRequestCancel(target, claim, raw) {
1556
1626
  id: request.id, targetId: request.targetId, status });
1557
1627
  }
1558
1628
  }
1629
+ // Windows has no process groups: a command's tree is its leader's Job Object,
1630
+ // gone once the job has no process left. Without one, it is the leader and what
1631
+ // taskkill /T finds under it, and the tree counts as gone with its leader.
1559
1632
  function processGroupAbsent(pgid) {
1633
+ const active = windowsJobs ? windowsJobs.active(pgid) : null;
1634
+ if (active !== null) {
1635
+ if (active === 0) windowsJobs.release(pgid);
1636
+ return active === 0;
1637
+ }
1560
1638
  try {
1561
- process.kill(-pgid, 0);
1639
+ process.kill(WINDOWS ? pgid : -pgid, 0);
1562
1640
  if (process.platform === "linux") {
1563
1641
  try {
1564
1642
  const entries = fs.readdirSync("/proc");
@@ -1612,6 +1690,14 @@ async function killGroup(child) {
1612
1690
  if (!child || !Number.isSafeInteger(child.pid)) return;
1613
1691
  const pgid = child.pid;
1614
1692
  if (processGroupAbsent(pgid)) return;
1693
+ if (WINDOWS) {
1694
+ if (!(windowsJobs && windowsJobs.terminate(pgid))) try {
1695
+ spawnSync(path.join(process.env.SystemRoot || "C:\\Windows", "System32", "taskkill.exe"), ["/PID", String(pgid), "/T", "/F"],
1696
+ { stdio: "ignore", timeout: 10_000, windowsHide: true });
1697
+ } catch (error) { void error; }
1698
+ if (await waitForProcessGroupAbsent(pgid, 2_000)) return;
1699
+ throw new Error("process_group_cleanup_unconfirmed");
1700
+ }
1615
1701
  try { process.kill(-pgid, "SIGTERM"); } catch (error) {
1616
1702
  if (error && error.code !== "ESRCH") throw error;
1617
1703
  }
@@ -1956,7 +2042,7 @@ function readPrivateEnvironment() {
1956
2042
  const parent = path.dirname(candidate);
1957
2043
  if (fs.realpathSync(parent) !== parent) throw new Error("environment_unavailable");
1958
2044
  const directory = fs.lstatSync(parent);
1959
- if (!directory.isDirectory() || directory.uid !== process.getuid() || (directory.mode & 0o7777) !== 0o700) throw new Error("environment_unavailable");
2045
+ if (!directory.isDirectory() || !(WINDOWS || (directory.uid === process.getuid() && (directory.mode & 0o7777) === 0o700))) throw new Error("environment_unavailable");
1960
2046
  for (const root of [config.workRoot, config.repoPath]) {
1961
2047
  const canonical = fs.realpathSync(root);
1962
2048
  if (stateOverlapsWorkspace(parent, canonical)) throw new Error("environment_unavailable");
@@ -1969,8 +2055,8 @@ function readPrivateEnvironment() {
1969
2055
  catch (error) { if (error && error.code === "ENOENT") throw new Error("environment_unavailable"); throw error; }
1970
2056
  try {
1971
2057
  const before = fs.fstatSync(fd);
1972
- if (!before.isFile() || before.uid !== process.getuid() || before.nlink !== 1
1973
- || ![0o600, 0o400].includes(before.mode & 0o7777) || before.size < 1 || before.size > DEVICE_ENVIRONMENT_LIMITS.snapshotBytes) throw new Error("environment_unavailable");
2058
+ if (!before.isFile() || before.nlink !== 1
2059
+ || !(WINDOWS || (before.uid === process.getuid() && [0o600, 0o400].includes(before.mode & 0o7777))) || before.size < 1 || before.size > DEVICE_ENVIRONMENT_LIMITS.snapshotBytes) throw new Error("environment_unavailable");
1974
2060
  const bytes = Buffer.alloc(before.size + 1);
1975
2061
  let length = 0;
1976
2062
  while (length < bytes.length) {
@@ -2002,7 +2088,7 @@ function validateEnvironmentSnapshot(snapshot) {
2002
2088
  if (name.length > 128 || !DEVICE_ENVIRONMENT_NAME_RE.test(name) || typeof value !== "string" || Buffer.byteLength(value, "utf8") > DEVICE_ENVIRONMENT_LIMITS.valueBytes || value.includes("\0")) throw new Error("environment_unavailable");
2003
2089
  }
2004
2090
  if (snapshot.github_auth !== undefined && (snapshot.github_auth !== "local_gh" || snapshot.git !== null
2005
- || !["darwin", "linux"].includes(process.platform) || !config.executionEnvironment || config.environmentExpectedBinding.binding.kind !== "workspace_source")) {
2091
+ || !["darwin", "linux", "win32"].includes(process.platform) || !config.executionEnvironment || config.environmentExpectedBinding.binding.kind !== "workspace_source")) {
2006
2092
  throw new Error("environment_unavailable");
2007
2093
  }
2008
2094
  if (snapshot.git !== null) {
@@ -2075,7 +2161,7 @@ function environmentForSpawn(piShell = false, confined = false) {
2075
2161
  const deviceRoot = fs.realpathSync(config.deviceRootPath || config.workRoot);
2076
2162
  const workspace = fs.realpathSync(config.workRoot);
2077
2163
  const repo = fs.realpathSync(config.repoPath);
2078
- const within = (candidate, root) => candidate === root || candidate.startsWith(root + path.sep);
2164
+ const within = pathWithin;
2079
2165
  if (!within(workspace, deviceRoot) || !within(repo, workspace)) throw new Error("environment_unavailable");
2080
2166
  let pool;
2081
2167
  if (config.workspacePoolPath !== undefined) {
@@ -2090,14 +2176,16 @@ function environmentForSpawn(piShell = false, confined = false) {
2090
2176
  const baseline = config.executionEnvironment;
2091
2177
  const temporaryDirectory = baseline?.temporaryDirectory ?? config.workRoot;
2092
2178
  const hostVariables = piShell ? baseline?.variables : undefined;
2093
- const env = { ...hostVariables, ...snapshot.variables, PATH: baseline?.path ?? "/opt/homebrew/bin:" + FIXED_CLOUD_CHILD_PATH,
2094
- HOME: baseline?.home ?? config.workRoot, PWD: config.repoPath, TMPDIR: temporaryDirectory, TMP: temporaryDirectory, TEMP: temporaryDirectory,
2179
+ const env = { ...hostVariables, ...snapshot.variables, ...windowsSystemVariables(),
2180
+ PATH: baseline?.path ?? (WINDOWS ? process.env.PATH : "/opt/homebrew/bin:" + FIXED_CLOUD_CHILD_PATH),
2181
+ HOME: baseline?.home ?? config.workRoot, PWD: posixPath(config.repoPath), TMPDIR: temporaryDirectory, TMP: temporaryDirectory, TEMP: temporaryDirectory,
2095
2182
  SHELL: FIXED_BASH, BASH_ENV: "/dev/null", ENV: "/dev/null",
2096
2183
  // Each coordinate under its Reason name and the Ara name every server
2097
- // script and Session shell before the rename reads.
2098
- REASON_DEVICE_ROOT: deviceRoot, REASON_HANDS_WORKSPACE: workspace, REASON_HANDS_REPO: repo,
2099
- ARA_DEVICE_ROOT: deviceRoot, ARA_HANDS_WORKSPACE: workspace, ARA_HANDS_REPO: repo,
2100
- ...(pool === undefined ? {} : { REASON_HANDS_WORKSPACE_POOL: pool, ARA_HANDS_WORKSPACE_POOL: pool }),
2184
+ // script and Session shell before the rename reads; in Git Bash's form on
2185
+ // Windows, where those scripts compare them with $PWD and pwd -P.
2186
+ REASON_DEVICE_ROOT: posixPath(deviceRoot), REASON_HANDS_WORKSPACE: posixPath(workspace), REASON_HANDS_REPO: posixPath(repo),
2187
+ ARA_DEVICE_ROOT: posixPath(deviceRoot), ARA_HANDS_WORKSPACE: posixPath(workspace), ARA_HANDS_REPO: posixPath(repo),
2188
+ ...(pool === undefined ? {} : { REASON_HANDS_WORKSPACE_POOL: posixPath(pool), ARA_HANDS_WORKSPACE_POOL: posixPath(pool) }),
2101
2189
  GIT_CONFIG_NOSYSTEM: "1", GIT_CONFIG_SYSTEM: "/dev/null", GIT_CONFIG_GLOBAL: "/dev/null", GIT_TERMINAL_PROMPT: "0",
2102
2190
  };
2103
2191
  const pairs = [["credential.helper", ""], ["http.extraheader", ""]];
@@ -2226,11 +2314,95 @@ function prepareBashSpawn(argv, extraFileDescriptors, expiresAtMs, signal, onLos
2226
2314
  let nativePtyOwner = null;
2227
2315
  function ptySupported() {
2228
2316
  if (!config.managedPty || config.environmentSnapshotPath === undefined || config.spawnPolicy || config.bashCommandPrefix
2229
- || !["darwin", "linux"].includes(process.platform) || typeof Bun === "undefined" || typeof Bun.Terminal !== "function") return false;
2317
+ || typeof Bun === "undefined") return false;
2318
+ if (process.platform === "win32") return windowsPty().available();
2319
+ if (!["darwin", "linux"].includes(process.platform) || typeof Bun.Terminal !== "function") return false;
2230
2320
  if (process.platform === "linux" && !["x64", "arm64"].includes(process.arch)) return false;
2231
2321
  try { platformPtyOwner(); return true; } catch { return false; }
2232
2322
  }
2233
2323
  function platformPtyOwner() { return process.platform === "linux" ? linuxPtyOwner() : macPtyOwner(); }
2324
+ let windowsPtyOwner = null;
2325
+ function windowsPty() { return windowsPtyOwner ||= windowsPtyApi(() => require("bun:ffi"), fs.existsSync); }
2326
+ /** Windows: a ConPTY whose shell and everything it starts share one job
2327
+ * object (windows-pty-source.ts). The open process handle pins the shell's
2328
+ * PID; teardown terminates the job and confirms it has no live process, the
2329
+ * counterpart of the POSIX session sweep. */
2330
+ function windowsPtyOperation(request, managed) {
2331
+ let pty = null, childEnvironment = null;
2332
+ let done = false, cancelled = false, timedOut = false, cleanup = null, exitCode = null, timer = null;
2333
+ const spawnGeneration = targetGeneration, spawnFence = targetFenceId;
2334
+ let resolveResult, acknowledgeSpawn;
2335
+ const promise = new Promise((resolve) => { resolveResult = resolve; });
2336
+ const started = new Promise((resolve) => { acknowledgeSpawn = resolve; });
2337
+ const finish = (error, code) => {
2338
+ if (done) return;
2339
+ done = true; acknowledgeSpawn(false);
2340
+ clearTimeout(timer);
2341
+ resolveResult(error ? failure(request.id, code, error, "", "") : success(request.id, "", ""));
2342
+ };
2343
+ function stopSession() {
2344
+ if (cleanup) return cleanup;
2345
+ cleanup = Promise.resolve().then(async () => {
2346
+ if (!pty) { finish(timedOut ? "timeout" : "cancelled", timedOut ? 124 : 130); return; }
2347
+ try {
2348
+ if (pty.activeProcesses() > 0) pty.terminate();
2349
+ for (const startedAt = Date.now(); pty.activeProcesses() > 0;) {
2350
+ if (Date.now() - startedAt > ${s}) throw new Error("pty_cleanup_timeout");
2351
+ await new Promise((resolve) => setTimeout(resolve, 20));
2352
+ }
2353
+ pty.close();
2354
+ if (timedOut) finish("timeout", 124);
2355
+ else if (cancelled) finish("cancelled", 130);
2356
+ else finish(exitCode === 0 ? null : "command_failed", exitCode ?? 1);
2357
+ } catch {
2358
+ // Closing the job handle still ends its processes (KILL_ON_JOB_CLOSE), unconfirmed.
2359
+ try { pty.close(); } catch { /* already closed */ }
2360
+ finish("process_group_cleanup_unconfirmed", 1);
2361
+ }
2362
+ });
2363
+ return cleanup;
2364
+ }
2365
+ function arm(deadline) {
2366
+ clearTimeout(timer);
2367
+ timer = setTimeout(() => { timedOut = true; void stopSession(); }, Math.max(1, deadline - Date.now()));
2368
+ }
2369
+ const canInput = () => done || cleanup || !pty ? "job_not_running" : null;
2370
+ try {
2371
+ childEnvironment = environmentForSpawn();
2372
+ if (stopped || spawnGeneration !== targetGeneration || spawnFence !== targetFenceId
2373
+ || !validJobLease(managed.leaseExpiresAtMs)) throw new Error("pty_spawn_expired");
2374
+ const env = { ...childEnvironment.env, TERM: "xterm-256color" };
2375
+ const shell = windowsPty().defaultShell(process.env);
2376
+ pty = windowsPty().spawn({ file: shell, args: windowsPty().shellArgs(shell), cwd: config.repoPath, env,
2377
+ cols: request.input.cols, rows: request.input.rows, onData: (bytes) => { if (!done) managed.onBytes(bytes); } });
2378
+ consumedEnvironment = { revision: childEnvironment.snapshot.revision, hash: childEnvironment.hash };
2379
+ managed.onEnvironment(childEnvironment.snapshot);
2380
+ arm(managed.leaseExpiresAtMs);
2381
+ void pty.exited.then((code) => { if (!done && !cleanup) { exitCode = code; void stopSession(); } });
2382
+ acknowledgeSpawn(true);
2383
+ } catch {
2384
+ if (pty) { cancelled = true; void stopSession(); }
2385
+ else finish("spawn_failed", 1);
2386
+ }
2387
+ return { promise, started, supportsCancellation: true, canInput,
2388
+ settle: stopSession,
2389
+ processIdentity() {
2390
+ return pty && !done && !cleanup ? { pid: pty.pid, processGroupId: pty.pid, executorLaunchId: config.launchId } : null;
2391
+ },
2392
+ input(data) {
2393
+ const error = canInput(); if (error) return error;
2394
+ try { pty.write(data); return null; }
2395
+ catch { cancelled = true; void stopSession(); return "job_not_running"; }
2396
+ },
2397
+ resize(cols, rows) {
2398
+ const error = canInput(); if (error) return error;
2399
+ try { pty.resize(cols, rows); return null; }
2400
+ catch { cancelled = true; void stopSession(); return "job_not_running"; }
2401
+ },
2402
+ renew(deadline) { if (done || cleanup) return false; arm(deadline); return true; },
2403
+ cancel() { cancelled = true; return stopSession(); },
2404
+ };
2405
+ }
2234
2406
  /** Only live native process identities, never recovered PIDs. Darwin's audit
2235
2407
  * token includes the kernel PID version; stale versions cannot signal a reused
2236
2408
  * PID. Keep the trusted session leader alive until its interactive groups are
@@ -2479,7 +2651,7 @@ function linuxPtyOwner() {
2479
2651
  // user detaches from the shell (nohup, setsid, disown, or jobs left at exit)
2480
2652
  // are not swept. At most TERMINAL_HOST_LIMIT shells per scope.
2481
2653
  const TERMINAL_SHELL = "/bin/bash --noprofile --norc -i";
2482
- const TERMINAL_TMUX_CONFIG = ${JSON.stringify([...g,"new-session -d -s main /bin/bash --noprofile --norc -i","set -g exit-empty on","run-shell -b -d 43200 -C kill-server",""].join(`
2654
+ const TERMINAL_TMUX_CONFIG = ${JSON.stringify([...h,"new-session -d -s main /bin/bash --noprofile --norc -i","set -g exit-empty on","run-shell -b -d 43200 -C kill-server",""].join(`
2483
2655
  `))};
2484
2656
  const TERMINAL_HOST_LIMIT = 4;
2485
2657
  const terminalViewers = new Map();
@@ -2587,6 +2759,7 @@ async function chooseTerminalProgram() {
2587
2759
  return oneShot;
2588
2760
  }
2589
2761
  function ptyOperation(request, managed, program = TERMINAL_SHELL) {
2762
+ if (process.platform === "win32") return windowsPtyOperation(request, managed);
2590
2763
  const native = platformPtyOwner();
2591
2764
  let child = null, anchor = null, terminal = null, childEnvironment = null, device = null;
2592
2765
  let done = false, cancelled = false, timedOut = false, cleanup = null, exitCode = null;
@@ -2622,7 +2795,7 @@ function ptyOperation(request, managed, program = TERMINAL_SHELL) {
2622
2795
  const { members, empty } = native.session(anchor, device);
2623
2796
  try {
2624
2797
  if (empty && exitCode !== null && subreaper) break;
2625
- if (Date.now() - startedAt > ${G}) throw new Error("pty_cleanup_timeout");
2798
+ if (Date.now() - startedAt > ${s}) throw new Error("pty_cleanup_timeout");
2626
2799
  for (const token of members) {
2627
2800
  if (!native.same(anchor)) throw new Error("pty_session_identity_lost");
2628
2801
  const id = native.identityKey(token);
@@ -2638,7 +2811,7 @@ function ptyOperation(request, managed, program = TERMINAL_SHELL) {
2638
2811
  controlReleased = true;
2639
2812
  let exitTimer;
2640
2813
  try { await Promise.race([child.exited, new Promise((_, reject) => {
2641
- exitTimer = setTimeout(() => reject(new Error("pty_anchor_exit_unconfirmed")), ${S});
2814
+ exitTimer = setTimeout(() => reject(new Error("pty_anchor_exit_unconfirmed")), ${X});
2642
2815
  })]); } finally { clearTimeout(exitTimer); }
2643
2816
  if (timedOut) finish("timeout", 124);
2644
2817
  else if (cancelled) finish("cancelled", 130);
@@ -2899,7 +3072,9 @@ function bashOperation(request, onProgress, managed, piShell) {
2899
3072
  command[0], command.slice(1),
2900
3073
  {
2901
3074
  cwd: config.repoPath,
2902
- detached: true,
3075
+ // Windows: no process group (taskkill /T stops the tree) and no console window.
3076
+ detached: !WINDOWS,
3077
+ windowsHide: true,
2903
3078
  env: validPrivateJob ? process.env : childEnvironment ? childEnvironment.env : {
2904
3079
  ...process.env,
2905
3080
  // A physical Device keeps the CLI-resolved host PATH (including
@@ -2923,6 +3098,7 @@ function bashOperation(request, onProgress, managed, piShell) {
2923
3098
  );
2924
3099
  // A new leader with this PID proves the retained group of that ID ended.
2925
3100
  if (Number.isSafeInteger(child.pid)) backgroundGroups.delete(child.pid);
3101
+ if (windowsJobs && Number.isSafeInteger(child.pid)) windowsJobs.track(child.pid);
2926
3102
  } catch (error) {
2927
3103
  // The protocol error stays spawn_failed; a coded refusal such as
2928
3104
  // local_device_gh_confinement_unavailable or environment_unavailable is
@@ -3153,15 +3329,19 @@ function replOperation(request) {
3153
3329
  // timeout and the lease, and background processes retained until the worker
3154
3330
  // stops. One departure from stock: a command idle on a watcher's banner is
3155
3331
  // stopped (PI_WATCH_BANNER). PI_* variables are not set here.
3156
- const PI_TOOLS_SHA256 = "${u}";
3332
+ const PI_TOOLS_SHA256 = "${a}";
3157
3333
  const piToolsSource = typeof araHandsPiToolsSource === "function" ? araHandsPiToolsSource : null;
3158
3334
  let piTools = null;
3159
3335
  function loadPiTools() {
3160
3336
  if (piTools) return piTools;
3161
3337
  const source = piToolsSource();
3162
3338
  if (digest(source) !== PI_TOOLS_SHA256) throw new Error("pi_tools_digest_mismatch");
3339
+ // The bundle names itself file:///ara-hands-pi-tools.cjs, which Windows
3340
+ // cannot turn into a path (no drive letter), so loading it would throw.
3341
+ const body = process.platform === "win32"
3342
+ ? source.replaceAll("file:///ara-hands-pi-tools.cjs", "file:///C:/ara-hands-pi-tools.cjs") : source;
3163
3343
  const module = { exports: {} };
3164
- new Function("module", "exports", "require", '"use strict";\n' + source)(module, module.exports, require);
3344
+ new Function("module", "exports", "require", '"use strict";\n' + body)(module, module.exports, require);
3165
3345
  piTools = module.exports;
3166
3346
  return piTools;
3167
3347
  }
@@ -3182,10 +3362,10 @@ const PI_EXIT_STDIO_GRACE_MS = 100;
3182
3362
  // the token once under quoteDepth layers of single quoting, so the confined
3183
3363
  // script is byte-identical to what the Brain's confineBashPayload gives the
3184
3364
  // bash tool: srt/bwrap, the payload uid, the network allowlist and allowWrite.
3185
- const PI_TOOL_CONFINEMENT_TOKEN = "${w}";
3365
+ const PI_TOOL_CONFINEMENT_TOKEN = "${m}";
3186
3366
  function validPiToolConfinement(value) {
3187
3367
  return hasOnlyKeys(value, ["template", "quoteDepth"]) && typeof value.template === "string"
3188
- && value.template.length <= ${m} && !value.template.includes("\0")
3368
+ && value.template.length <= ${q} && !value.template.includes("\0")
3189
3369
  && value.template.split(PI_TOOL_CONFINEMENT_TOKEN).length === 2 && [1, 2, 3].includes(value.quoteDepth);
3190
3370
  }
3191
3371
  // The script T when this command is exactly this policy's confineBashPayload(T)
@@ -3423,8 +3603,7 @@ function prepareRequestJournal() {
3423
3603
  try { fs.mkdirSync(directory, { mode: 0o700 }); }
3424
3604
  catch (error) { if (error.code !== "EEXIST") throw error; }
3425
3605
  const stat = fs.lstatSync(directory);
3426
- if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid()
3427
- || (stat.mode & 0o077) !== 0) throw new Error("invalid_request_journal");
3606
+ if (!stat.isDirectory() || stat.isSymbolicLink() || !ownedPrivately(stat)) throw new Error("invalid_request_journal");
3428
3607
  // Stream the private directory: receipt count is not a lifetime call cap.
3429
3608
  // A crash may leave the fixed temp sibling; only the renamed final record
3430
3609
  // is authoritative, so it cannot authorize replay or a completed result.
@@ -3674,12 +3853,12 @@ async function handleRequest(target, connectionGeneration, claim, raw) {
3674
3853
  const startOperation = () => request.tool === "bash"
3675
3854
  ? bashOperation(request, progress)
3676
3855
  : request.tool === "pi_tool"
3677
- ? piToolOperation(request, request.input.tool === "bash" ? progress : null, claim.piToolsConfinement)
3856
+ ? piToolOperation(nativePathRequest(request), request.input.tool === "bash" ? progress : null, claim.piToolsConfinement)
3678
3857
  : request.tool === "repl"
3679
3858
  ? replOperation(request)
3680
3859
  : (config.spawnPolicy || config.bashCommandPrefix) && request.tool !== "read"
3681
- ? payloadFileOperation(request)
3682
- : fileOperation(request);
3860
+ ? payloadFileOperation(nativePathRequest(request))
3861
+ : fileOperation(nativePathRequest(request));
3683
3862
  const operation = request.workspaceBefore !== undefined
3684
3863
  ? workspaceBeforeOperation(request, startOperation) : startOperation();
3685
3864
  // Every waiter observes the durable completion, never the raw child result.
@@ -3986,6 +4165,9 @@ function stop(reason) {
3986
4165
  return stoppingPromise;
3987
4166
  }
3988
4167
  process.once("SIGTERM", () => { void stop("SIGTERM"); });
4168
+ // Windows delivers no catchable SIGTERM to a child: its parent ends this
4169
+ // worker's stdin pipe instead (cli/local-hands-relay.ts signalHandsWorker).
4170
+ if (WINDOWS) { process.stdin.once("end", () => { void stop("SIGTERM"); }); process.stdin.once("error", () => { void stop("SIGTERM"); }); process.stdin.resume(); }
3989
4171
  process.once("SIGINT", () => { void stop("SIGINT"); });
3990
4172
  process.once("SIGHUP", () => { void stop("SIGHUP"); });
3991
4173
  setTimeout(() => { void stop("expired"); }, Math.max(1, config.expiresAtMs - Date.now())).unref();
@@ -3994,5 +4176,5 @@ void startJobControl().then(() => {
3994
4176
  try { loadJobs(); prepareRequestJournal(); } catch { process.exit(44); }
3995
4177
  if (validPrivateJob) markReady(); else connect();
3996
4178
  }, () => process.exit(45));
3997
- `.trimStart(),Pt=tt("sha256").update(at,"utf8").digest("hex");
3998
- export{r as Fc,Wt as Gc,f as Hc,l as Ic,et as Jc,rt as Kc,nt as Lc,it as Mc,Ht as Nc,ot as Oc,ct as Pc,at as Qc,Pt as Rc};
4179
+ `.trimStart(),Ot=rt("sha256").update(ft,"utf8").digest("hex");
4180
+ export{r as Nc,Qt as Oc,l as Pc,g as Qc,nt as Rc,it as Sc,st as Tc,ot as Uc,It as Vc,ut as Wc,at as Xc,ft as Yc,Ot as Zc};