shennian 0.4.69 → 0.4.72

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 (106) hide show
  1. package/dist/publish-build-manifest.json +150 -90
  2. package/dist/src/agent-env.js +4 -4
  3. package/dist/src/agents/adapter.d.ts +7 -3
  4. package/dist/src/agents/auth-status.d.ts +4 -0
  5. package/dist/src/agents/auth-status.js +2 -0
  6. package/dist/src/agents/claude.js +4 -4
  7. package/dist/src/agents/codex-protocol.d.ts +103 -0
  8. package/dist/src/agents/codex-protocol.js +3 -0
  9. package/dist/src/agents/codex-runtime.d.ts +91 -0
  10. package/dist/src/agents/codex-runtime.js +14 -0
  11. package/dist/src/agents/codex.d.ts +15 -91
  12. package/dist/src/agents/codex.js +2 -17
  13. package/dist/src/agents/command-spec.js +4 -3
  14. package/dist/src/agents/detect.js +1 -1
  15. package/dist/src/agents/manager.d.ts +4 -3
  16. package/dist/src/agents/manager.js +4 -4
  17. package/dist/src/agents/model-registry/discovery.js +3 -3
  18. package/dist/src/agents/model-registry/parsers.js +4 -4
  19. package/dist/src/agents/model-registry/service.d.ts +6 -2
  20. package/dist/src/agents/model-registry/service.js +1 -1
  21. package/dist/src/agents/model-registry/types.d.ts +9 -1
  22. package/dist/src/agents/model-registry/types.js +1 -1
  23. package/dist/src/agents/opencode.d.ts +4 -0
  24. package/dist/src/agents/opencode.js +1 -1
  25. package/dist/src/commands/agent-readiness.d.ts +17 -0
  26. package/dist/src/commands/agent-readiness.js +2 -0
  27. package/dist/src/commands/agent.js +2 -2
  28. package/dist/src/commands/daemon-instance-lock.js +1 -1
  29. package/dist/src/commands/daemon-process.d.ts +1 -0
  30. package/dist/src/commands/daemon-process.js +1 -1
  31. package/dist/src/commands/daemon-service-spec.d.ts +28 -0
  32. package/dist/src/commands/daemon-service-spec.js +1 -0
  33. package/dist/src/commands/daemon-start-wait.d.ts +1 -1
  34. package/dist/src/commands/daemon-start-wait.js +1 -1
  35. package/dist/src/commands/daemon-state.d.ts +57 -0
  36. package/dist/src/commands/daemon-state.js +1 -0
  37. package/dist/src/commands/daemon-windows.d.ts +8 -0
  38. package/dist/src/commands/daemon-windows.js +10 -10
  39. package/dist/src/commands/daemon.d.ts +4 -64
  40. package/dist/src/commands/daemon.js +13 -13
  41. package/dist/src/commands/manager.js +1 -1
  42. package/dist/src/commands/upgrade.js +1 -1
  43. package/dist/src/commands/worker.d.ts +11 -0
  44. package/dist/src/commands/worker.js +2 -0
  45. package/dist/src/daemon-ipc/agent-readiness.d.ts +14 -0
  46. package/dist/src/daemon-ipc/agent-readiness.js +1 -0
  47. package/dist/src/daemon-ipc/control.d.ts +1 -1
  48. package/dist/src/daemon-ipc/control.js +1 -1
  49. package/dist/src/index.js +3 -3
  50. package/dist/src/manager/prompt.d.ts +1 -1
  51. package/dist/src/manager/prompt.js +6 -6
  52. package/dist/src/manager/registry.d.ts +48 -2
  53. package/dist/src/manager/registry.js +1 -1
  54. package/dist/src/manager/runtime.d.ts +2 -2
  55. package/dist/src/manager/runtime.js +6 -6
  56. package/dist/src/manager/worker-ipc.d.ts +7 -0
  57. package/dist/src/manager/worker-ipc.js +1 -1
  58. package/dist/src/native-fusion/local-repository.d.ts +6 -1
  59. package/dist/src/native-fusion/local-repository.js +2 -2
  60. package/dist/src/native-fusion/service.d.ts +2 -0
  61. package/dist/src/native-fusion/service.js +2 -2
  62. package/dist/src/native-fusion/source-visibility-audit.d.ts +16 -0
  63. package/dist/src/native-fusion/source-visibility-audit.js +1 -0
  64. package/dist/src/native-fusion/source-visibility.d.ts +25 -0
  65. package/dist/src/native-fusion/source-visibility.js +1 -0
  66. package/dist/src/native-fusion/state.d.ts +1 -0
  67. package/dist/src/native-fusion/state.js +2 -2
  68. package/dist/src/native-fusion/types.d.ts +5 -0
  69. package/dist/src/room/managed-room-binding.d.ts +2 -0
  70. package/dist/src/room/managed-room-binding.js +1 -1
  71. package/dist/src/room/room-binding-client.d.ts +1 -0
  72. package/dist/src/room/room-binding-client.js +1 -1
  73. package/dist/src/runtime-distribution.d.ts +13 -0
  74. package/dist/src/runtime-distribution.js +1 -0
  75. package/dist/src/security/managed-agent-policy.d.ts +7 -0
  76. package/dist/src/security/managed-agent-policy.js +1 -1
  77. package/dist/src/session/handlers/agent-workspace-validation.d.ts +1 -0
  78. package/dist/src/session/handlers/agent-workspace-validation.js +1 -1
  79. package/dist/src/session/handlers/agents.d.ts +7 -1
  80. package/dist/src/session/handlers/agents.js +1 -1
  81. package/dist/src/session/handlers/chat-context.d.ts +31 -0
  82. package/dist/src/session/handlers/chat-context.js +1 -0
  83. package/dist/src/session/handlers/chat-events.d.ts +1 -1
  84. package/dist/src/session/handlers/chat-events.js +2 -2
  85. package/dist/src/session/handlers/chat-session-lifecycle.d.ts +2 -2
  86. package/dist/src/session/handlers/chat-session-lifecycle.js +1 -1
  87. package/dist/src/session/handlers/chat.d.ts +3 -29
  88. package/dist/src/session/handlers/chat.js +1 -1
  89. package/dist/src/session/manager.js +2 -2
  90. package/dist/src/session/queue-helpers.js +2 -2
  91. package/dist/src/session/queue-message.d.ts +2 -0
  92. package/dist/src/session/queue.d.ts +7 -1
  93. package/dist/src/session/queue.js +1 -1
  94. package/dist/src/session/queued-chat-dispatch.d.ts +4 -1
  95. package/dist/src/session/queued-chat-dispatch.js +1 -1
  96. package/dist/src/session/store.d.ts +4 -2
  97. package/dist/src/session/store.js +2 -2
  98. package/dist/src/session/types.d.ts +1 -0
  99. package/dist/src/upgrade/engine.js +2 -2
  100. package/dist/src/upgrade/scheduler.js +1 -1
  101. package/dist/src/upgrade/updater-launcher.js +3 -3
  102. package/node_modules/@shennian/wire/dist/room.d.ts +2 -0
  103. package/node_modules/@shennian/wire/dist/session-sync.d.ts +2 -1
  104. package/node_modules/@shennian/wire/dist/session.d.ts +25 -1
  105. package/node_modules/@shennian/wire/dist/session.js +8 -0
  106. package/package.json +1 -1
@@ -1,3 +1,3 @@
1
- import s from"node:fs";import c from"node:path";import{execSync as F,execFile as R}from"node:child_process";import{promisify as T}from"node:util";import{fileURLToPath as J}from"node:url";import{getShennianDir as U,resolveShennianPath as m}from"../config/index.js";import{getUpgradeDistTag as O}from"./channel.js";import{fetchCliDistribution as L}from"./distribution.js";const f=T(R),y=m("upgrade-attempt.json"),P=3,I="https://registry.npmjs.org",G=10*6e4,_=[5*6e4,30*6e4,120*6e4,360*6e4];function g(){try{const r=h();if(r)return JSON.parse(s.readFileSync(r,"utf-8")).version}catch{}return"0.0.0"}function h(r=J(import.meta.url)){let e=c.dirname(r);for(let n=0;n<6;n++){const t=c.join(e,"package.json");if(s.existsSync(t)&&JSON.parse(s.readFileSync(t,"utf-8")).name==="shennian")return t;e=c.dirname(e)}return null}async function H(){let r;try{const e=await fetch(`https://registry.npmjs.org/shennian/${O()}`,{headers:{Accept:"application/json"},signal:AbortSignal.timeout(1e4)});if(!e.ok)throw new Error(`npm registry returned ${e.status}`);const n=await e.json();if(typeof n?.version!="string"||!/^\d+\.\d+\.\d+$/.test(n.version))throw new Error("npm registry returned an unsupported CLI version (expected numeric major.minor.patch)");return n.version}catch(e){r=e}try{return(await L()).version}catch(e){const n=r instanceof Error?r.message:String(r),t=e instanceof Error?e.message:String(e);throw new Error(`npm registry unavailable: ${n}; Shennian fallback failed: ${t}`)}}function B(r,e){const n=p=>p.replace(/^v/,"").split(".").map(Number),[t,a,o]=n(r),[i,u,l]=n(e);return i>t?"major":i===t&&u>a?"minor":i===t&&u===a&&l>o?"patch":"none"}function Y(){return F("npm root -g",{encoding:"utf-8",stdio:"pipe",windowsHide:!0}).trim()}function z(r,e=process.platform){const n=e==="win32"?c.win32:c.posix,t=n.dirname(r),a=n.dirname(t);if(n.basename(a)!=="node_modules")return null;const o=n.dirname(a);return n.basename(o)==="lib"?n.dirname(o):o}function $(){const r=h();return r?z(r):null}function K(){const r=h();return r?c.join(c.dirname(r),"dist","bin","shennian.js"):c.join(Y(),"shennian","dist","bin","shennian.js")}function X(){try{return JSON.parse(s.readFileSync(y,"utf-8"))}catch{return null}}function d(r){s.mkdirSync(U(),{recursive:!0}),s.writeFileSync(y,JSON.stringify(r,null,2))}function Z(){try{s.unlinkSync(y)}catch{}}function N(){return m("upgrade-failures.json")}function q(){return m("upgrade.lock")}function Q(r=q(),e={}){const n=e.now??Date.now(),t=e.pid??process.pid,a=e.isProcessAlive??(l=>{try{return process.kill(l,0),!0}catch{return!1}});s.mkdirSync(c.dirname(r),{recursive:!0});const o=()=>s.openSync(r,"wx",384);let i;try{i=o()}catch(l){if(l.code!=="EEXIST")throw l;let p=!1;try{const A=JSON.parse(s.readFileSync(r,"utf-8")),E=Number(A.pid),b=Number(A.createdAt);p=!Number.isInteger(E)||!Number.isFinite(b)||n-b>G||!a(E)}catch{p=!0}if(!p)throw new Error("Another Shennian upgrade is already running");s.rmSync(r,{force:!0}),i=o()}s.writeFileSync(i,JSON.stringify({pid:t,createdAt:n})),s.closeSync(i);let u=!1;return{release(){if(!u){u=!0;try{s.unlinkSync(r)}catch{}}}}}function w(r=N()){try{const e=JSON.parse(s.readFileSync(r,"utf-8"));return!e||typeof e!="object"||!e.versions?{versions:{}}:{versions:e.versions}}catch{return{versions:{}}}}function j(r){s.mkdirSync(U(),{recursive:!0}),s.writeFileSync(N(),JSON.stringify(r,null,2))}function W(r){return _[Math.min(Math.max(r-1,0),_.length-1)]}function ur(r,e=Date.now(),n=w()){const t=n.versions[r];return!!(t&&t.nextRetryAt>e)}function pr(r,e,n=Date.now()){const t=w(),a=t.versions[r],o=(a?.failureCount??0)+1,i={version:r,failureCount:o,firstFailedAt:a?.firstFailedAt??n,lastFailedAt:n,nextRetryAt:n+W(o),error:e};return t.versions[r]=i,j(t),i}function k(r){const e=w();e.versions[r]&&(delete e.versions[r],j(e))}async function fr(){const r=X();return r?Date.now()-r.attemptAt>600*1e3?(Z(),null):(r.attemptCount++,r.attemptCount>=P?(d(r),r):(d(r),null)):null}async function dr(r,e,n={}){let t;try{t=Q()}catch(a){return{ok:!1,error:a instanceof Error?a.message:String(a)}}try{return await V(r,e,n)}finally{t.release()}}async function V(r,e,n={}){const t=n.currentVersion??g(),a=g();if(t===r)return k(r),{ok:!1,error:`Already on version ${r}`};e({step:"checking"});try{F("npm --version",{stdio:"pipe",windowsHide:!0})}catch{return{ok:!1,error:"npm is not available in PATH"}}if(a===r){e({step:"verifying",version:r});try{await v(r)}catch(o){return{ok:!1,error:`Smoke test failed: ${o instanceof Error?o.message:String(o)}`}}return d({from:t,to:r,attemptCount:0,attemptAt:Date.now()}),k(r),e({step:"restarting",from:t,to:r}),{ok:!0,from:t,to:r}}e({step:"backing-up"}),e({step:"installing",version:r});try{await M(r)}catch(o){const i=await D(t);return{ok:!1,error:`npm install failed: ${o instanceof Error?o.message:String(o)}${i.ok?"":`; rollback failed: ${i.error}`}`,rolledBack:i.ok}}e({step:"verifying",version:r});try{await v(r)}catch(o){const i=await D(t);return{ok:!1,error:`Smoke test failed: ${o instanceof Error?o.message:String(o)}${i.ok?"":`; rollback failed: ${i.error}`}`,rolledBack:i.ok}}return d({from:t,to:r,attemptCount:0,attemptAt:Date.now()}),k(r),e({step:"restarting",from:t,to:r}),{ok:!0,from:t,to:r}}function C(r){if(!/^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(r))throw new Error(`Invalid npm version: ${r}`)}function S(){return process.platform==="win32"?"npm.cmd":"npm"}function rr(r,e){return{timeout:e,windowsHide:!0,shell:r==="win32"}}function x(r){return rr(process.platform,r)}async function M(r){C(r);const e=$(),n=["install","-g",`shennian@${r}`,...e?["--prefix",e]:[]];try{await f(S(),n,x(12e4))}catch(t){const a=t instanceof Error?t.message:String(t);try{await f(S(),[...n,"--registry",I],{...x(12e4)})}catch(o){const i=o instanceof Error?o.message:String(o);throw new Error(`${a}
1
+ import s from"node:fs";import{assertStandaloneUpgrade as F,isDesktopDistribution as T}from"../runtime-distribution.js";import c from"node:path";import{execSync as U,execFile as J}from"node:child_process";import{promisify as O}from"node:util";import{fileURLToPath as L}from"node:url";import{getShennianDir as _,resolveShennianPath as m}from"../config/index.js";import{getUpgradeDistTag as P}from"./channel.js";import{fetchCliDistribution as I}from"./distribution.js";const f=O(J),y=m("upgrade-attempt.json"),G=3,H="https://registry.npmjs.org",B=10*6e4,$=[5*6e4,30*6e4,120*6e4,360*6e4];function g(){try{const r=h();if(r)return JSON.parse(s.readFileSync(r,"utf-8")).version}catch{}return"0.0.0"}function h(r=L(import.meta.url)){let e=c.dirname(r);for(let n=0;n<6;n++){const t=c.join(e,"package.json");if(s.existsSync(t)&&JSON.parse(s.readFileSync(t,"utf-8")).name==="shennian")return t;e=c.dirname(e)}return null}async function Y(){let r;try{const e=await fetch(`https://registry.npmjs.org/shennian/${P()}`,{headers:{Accept:"application/json"},signal:AbortSignal.timeout(1e4)});if(!e.ok)throw new Error(`npm registry returned ${e.status}`);const n=await e.json();if(typeof n?.version!="string"||!/^\d+\.\d+\.\d+$/.test(n.version))throw new Error("npm registry returned an unsupported CLI version (expected numeric major.minor.patch)");return n.version}catch(e){r=e}try{return(await I()).version}catch(e){const n=r instanceof Error?r.message:String(r),t=e instanceof Error?e.message:String(e);throw new Error(`npm registry unavailable: ${n}; Shennian fallback failed: ${t}`)}}function z(r,e){const n=p=>p.replace(/^v/,"").split(".").map(Number),[t,a,o]=n(r),[i,u,l]=n(e);return i>t?"major":i===t&&u>a?"minor":i===t&&u===a&&l>o?"patch":"none"}function K(){return U("npm root -g",{encoding:"utf-8",stdio:"pipe",windowsHide:!0}).trim()}function X(r,e=process.platform){const n=e==="win32"?c.win32:c.posix,t=n.dirname(r),a=n.dirname(t);if(n.basename(a)!=="node_modules")return null;const o=n.dirname(a);return n.basename(o)==="lib"?n.dirname(o):o}function N(){const r=h();return r?X(r):null}function Z(){const r=h();return r?c.join(c.dirname(r),"dist","bin","shennian.js"):c.join(K(),"shennian","dist","bin","shennian.js")}function q(){try{return JSON.parse(s.readFileSync(y,"utf-8"))}catch{return null}}function d(r){s.mkdirSync(_(),{recursive:!0}),s.writeFileSync(y,JSON.stringify(r,null,2))}function Q(){try{s.unlinkSync(y)}catch{}}function j(){return m("upgrade-failures.json")}function W(){return m("upgrade.lock")}function V(r=W(),e={}){const n=e.now??Date.now(),t=e.pid??process.pid,a=e.isProcessAlive??(l=>{try{return process.kill(l,0),!0}catch{return!1}});s.mkdirSync(c.dirname(r),{recursive:!0});const o=()=>s.openSync(r,"wx",384);let i;try{i=o()}catch(l){if(l.code!=="EEXIST")throw l;let p=!1;try{const A=JSON.parse(s.readFileSync(r,"utf-8")),E=Number(A.pid),b=Number(A.createdAt);p=!Number.isInteger(E)||!Number.isFinite(b)||n-b>B||!a(E)}catch{p=!0}if(!p)throw new Error("Another Shennian upgrade is already running");s.rmSync(r,{force:!0}),i=o()}s.writeFileSync(i,JSON.stringify({pid:t,createdAt:n})),s.closeSync(i);let u=!1;return{release(){if(!u){u=!0;try{s.unlinkSync(r)}catch{}}}}}function w(r=j()){try{const e=JSON.parse(s.readFileSync(r,"utf-8"));return!e||typeof e!="object"||!e.versions?{versions:{}}:{versions:e.versions}}catch{return{versions:{}}}}function C(r){s.mkdirSync(_(),{recursive:!0}),s.writeFileSync(j(),JSON.stringify(r,null,2))}function rr(r){return $[Math.min(Math.max(r-1,0),$.length-1)]}function dr(r,e=Date.now(),n=w()){const t=n.versions[r];return!!(t&&t.nextRetryAt>e)}function mr(r,e,n=Date.now()){const t=w(),a=t.versions[r],o=(a?.failureCount??0)+1,i={version:r,failureCount:o,firstFailedAt:a?.firstFailedAt??n,lastFailedAt:n,nextRetryAt:n+rr(o),error:e};return t.versions[r]=i,C(t),i}function k(r){const e=w();e.versions[r]&&(delete e.versions[r],C(e))}async function yr(){if(T())return null;const r=q();return r?Date.now()-r.attemptAt>600*1e3?(Q(),null):(r.attemptCount++,r.attemptCount>=G?(d(r),r):(d(r),null)):null}async function gr(r,e,n={}){let t;try{F(),t=V()}catch(a){return{ok:!1,error:a instanceof Error?a.message:String(a)}}try{return await er(r,e,n)}finally{t.release()}}async function er(r,e,n={}){const t=n.currentVersion??g(),a=g();if(t===r)return k(r),{ok:!1,error:`Already on version ${r}`};e({step:"checking"});try{U("npm --version",{stdio:"pipe",windowsHide:!0})}catch{return{ok:!1,error:"npm is not available in PATH"}}if(a===r){e({step:"verifying",version:r});try{await v(r)}catch(o){return{ok:!1,error:`Smoke test failed: ${o instanceof Error?o.message:String(o)}`}}return d({from:t,to:r,attemptCount:0,attemptAt:Date.now()}),k(r),e({step:"restarting",from:t,to:r}),{ok:!0,from:t,to:r}}e({step:"backing-up"}),e({step:"installing",version:r});try{await M(r)}catch(o){const i=await R(t);return{ok:!1,error:`npm install failed: ${o instanceof Error?o.message:String(o)}${i.ok?"":`; rollback failed: ${i.error}`}`,rolledBack:i.ok}}e({step:"verifying",version:r});try{await v(r)}catch(o){const i=await R(t);return{ok:!1,error:`Smoke test failed: ${o instanceof Error?o.message:String(o)}${i.ok?"":`; rollback failed: ${i.error}`}`,rolledBack:i.ok}}return d({from:t,to:r,attemptCount:0,attemptAt:Date.now()}),k(r),e({step:"restarting",from:t,to:r}),{ok:!0,from:t,to:r}}function D(r){if(!/^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(r))throw new Error(`Invalid npm version: ${r}`)}function S(){return process.platform==="win32"?"npm.cmd":"npm"}function tr(r,e){return{timeout:e,windowsHide:!0,shell:r==="win32"}}function x(r){return tr(process.platform,r)}async function M(r){F(),D(r);const e=N(),n=["install","-g",`shennian@${r}`,...e?["--prefix",e]:[]];try{await f(S(),n,x(12e4))}catch(t){const a=t instanceof Error?t.message:String(t);try{await f(S(),[...n,"--registry",H],{...x(12e4)})}catch(o){const i=o instanceof Error?o.message:String(o);throw new Error(`${a}
2
2
  --- npmjs fallback ---
3
- ${i}`)}}}async function v(r){C(r);const e=K(),{stdout:n}=await f(process.execPath,[e,"--version"],{timeout:1e4,windowsHide:!0});if(n.trim()!==r)throw new Error(`Version verification failed: expected ${r}, got ${n.trim()||"empty output"}`);const t=$();await f(S(),["ls","-g",`shennian@${r}`,"--omit=dev","--depth=0",...t?["--prefix",t]:[]],{...x(3e4)})}async function er(r,e={}){await(e.install??M)(r),await(e.verify??v)(r)}async function D(r){try{return await er(r),{ok:!0}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}async function mr(r){const e=r??g(),n=await H(),t=B(e,n);return t==="none"?{hasUpdate:!1}:{hasUpdate:!0,current:e,latest:n,changeType:t}}export{Q as acquireUpgradeLock,mr as checkForUpdate,Z as clearUpgradeAttempt,k as clearUpgradeFailure,B as compareVersions,H as fetchLatestVersion,h as findPackageJson,g as getCurrentVersion,W as getUpgradeRetryDelayMs,fr as handleStartupCrashCheck,M as installShennianVersion,ur as isUpgradeVersionInCooldown,rr as npmExecOptionsForPlatform,dr as performUpgrade,X as readUpgradeAttempt,w as readUpgradeFailures,pr as recordUpgradeFailure,z as resolveNpmGlobalPrefixFromPackageJson,er as rollbackToExactVersion,v as verifyInstalledVersion,d as writeUpgradeAttempt};
3
+ ${i}`)}}}async function v(r){D(r);const e=Z(),{stdout:n}=await f(process.execPath,[e,"--version"],{timeout:1e4,windowsHide:!0});if(n.trim()!==r)throw new Error(`Version verification failed: expected ${r}, got ${n.trim()||"empty output"}`);const t=N();await f(S(),["ls","-g",`shennian@${r}`,"--omit=dev","--depth=0",...t?["--prefix",t]:[]],{...x(3e4)})}async function nr(r,e={}){await(e.install??M)(r),await(e.verify??v)(r)}async function R(r){try{return await nr(r),{ok:!0}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}async function hr(r){const e=r??g(),n=await Y(),t=z(e,n);return t==="none"?{hasUpdate:!1}:{hasUpdate:!0,current:e,latest:n,changeType:t}}export{V as acquireUpgradeLock,hr as checkForUpdate,Q as clearUpgradeAttempt,k as clearUpgradeFailure,z as compareVersions,Y as fetchLatestVersion,h as findPackageJson,g as getCurrentVersion,rr as getUpgradeRetryDelayMs,yr as handleStartupCrashCheck,M as installShennianVersion,dr as isUpgradeVersionInCooldown,tr as npmExecOptionsForPlatform,gr as performUpgrade,q as readUpgradeAttempt,w as readUpgradeFailures,mr as recordUpgradeFailure,X as resolveNpmGlobalPrefixFromPackageJson,nr as rollbackToExactVersion,v as verifyInstalledVersion,d as writeUpgradeAttempt};
@@ -1 +1 @@
1
- import{checkForUpdate as l,isUpgradeVersionInCooldown as c}from"./engine.js";const u={automaticPatchEnabled:!1,rolloutPercentage:0,pausedVersions:[],blockedVersions:[],blockedCurrentVersions:[],killSwitch:!0,releaseLevel:"normal",maxIdleWaitMs:30*6e4,requiredCapabilities:[],externalUpdaterEnabled:!1};function d(r){let i=2166136261;for(let t=0;t<r.length;t++)i^=r.charCodeAt(t),i=Math.imul(i,16777619);return(i>>>0)%100}function m(r,i,t,e){if(r.killSwitch||!r.automaticPatchEnabled||r.blockedVersions.includes(e)||r.pausedVersions.includes(e)||r.pausedVersions.includes(t))return!1;const s=Math.max(0,Math.min(100,Math.floor(r.rolloutPercentage)));return d(i)<s}async function h(r){const i=new URL("/api/releases/cli-policy",r),t=await fetch(i,{headers:{Accept:"application/json"},signal:AbortSignal.timeout(1e4)});if(!t.ok)throw new Error(`release policy returned ${t.status}`);const e=await t.json();return{automaticPatchEnabled:e.automaticPatchEnabled===!0,rolloutPercentage:typeof e.rolloutPercentage=="number"?e.rolloutPercentage:0,pausedVersions:Array.isArray(e.pausedVersions)?e.pausedVersions.filter(s=>typeof s=="string"):[],blockedVersions:Array.isArray(e.blockedVersions)?e.blockedVersions.filter(s=>typeof s=="string"):[],blockedCurrentVersions:Array.isArray(e.blockedCurrentVersions)?e.blockedCurrentVersions.filter(s=>typeof s=="string"):[],killSwitch:e.killSwitch!==!1,releaseLevel:e.releaseLevel==="required"||e.releaseLevel==="blocked"?e.releaseLevel:"normal",maxIdleWaitMs:typeof e.maxIdleWaitMs=="number"&&Number.isFinite(e.maxIdleWaitMs)?Math.max(0,Math.min(1440*6e4,Math.floor(e.maxIdleWaitMs))):30*6e4,...typeof e.minimumSessionSyncProtocolVersion=="number"?{minimumSessionSyncProtocolVersion:e.minimumSessionSyncProtocolVersion}:{},...typeof e.minimumDataEpoch=="number"?{minimumDataEpoch:e.minimumDataEpoch}:{},requiredCapabilities:Array.isArray(e.requiredCapabilities)?e.requiredCapabilities.filter(s=>typeof s=="string"):[],externalUpdaterEnabled:e.externalUpdaterEnabled===!0,...typeof e.minimumUpdaterProtocolVersion=="number"?{minimumUpdaterProtocolVersion:e.minimumUpdaterProtocolVersion}:{}}}class f{deps;policy="none";timer=null;started=!1;upgradeInFlight=!1;constructor(i){this.deps=i}start(){this.started||(this.started=!0,this.arm(this.deps.initialDelayMs??3e4))}stop(){this.started=!1,this.timer&&(this.deps.clearTimeout??clearTimeout)(this.timer),this.timer=null}setPolicy(i){this.policy=i,this.started&&(this.timer||this.arm(0))}getPolicy(){return this.policy}async runOnce(){if(this.upgradeInFlight)return;const i=await(this.deps.checkForUpdate??l)(this.deps.currentVersion);if(!i.hasUpdate||(this.deps.inCooldown??c)(i.latest))return;let t=u;try{t=await(this.deps.fetchReleasePolicy??(()=>h(this.deps.serverUrl)))()}catch{return}if(t.killSwitch||!t.externalUpdaterEnabled||t.blockedVersions.includes(i.latest)||t.pausedVersions.includes(i.latest)||t.pausedVersions.includes(i.current))return;const e=t.blockedCurrentVersions.includes(i.current)?"blocked":t.releaseLevel,s=t.minimumSessionSyncProtocolVersion!==void 0&&(this.deps.sessionSyncProtocolVersion??0)<t.minimumSessionSyncProtocolVersion||t.minimumDataEpoch!==void 0&&(this.deps.dataEpoch??0)<t.minimumDataEpoch||t.requiredCapabilities.some(o=>!(this.deps.advertisedCapabilities??[]).includes(o))||t.minimumUpdaterProtocolVersion!==void 0&&(this.deps.updaterProtocolVersion??0)<t.minimumUpdaterProtocolVersion,a=e==="required"||e==="blocked"||s;if(!a&&(this.policy!=="patch"||i.changeType!=="patch"||!m(t,this.deps.machineId,i.current,i.latest)))return;const n=this.deps.getIdleState();if(!(!a&&!n.idle)){this.upgradeInFlight=!0;try{await this.deps.startUpgrade(i.latest,a)}finally{this.upgradeInFlight=!1}}}nextIntervalMs(){return this.deps.intervalMs??5*6e4+Math.floor((this.deps.random??Math.random)()*10*6e4)}arm(i){if(!this.started||this.timer)return;const t=this.deps.setTimeout??setTimeout;this.timer=t(()=>{this.timer=null,this.runOnce().catch(()=>{}).finally(()=>{this.started&&this.arm(this.nextIntervalMs())})},i),this.timer.unref?.()}}export{f as AutoUpgradeScheduler,d as deterministicRolloutBucket,h as fetchCliReleasePolicy,m as isAutomaticPatchAllowed};
1
+ import{isDesktopDistribution as a}from"../runtime-distribution.js";import{checkForUpdate as u,isUpgradeVersionInCooldown as c}from"./engine.js";const d={automaticPatchEnabled:!1,rolloutPercentage:0,pausedVersions:[],blockedVersions:[],blockedCurrentVersions:[],killSwitch:!0,releaseLevel:"normal",maxIdleWaitMs:30*6e4,requiredCapabilities:[],externalUpdaterEnabled:!1};function m(r){let i=2166136261;for(let t=0;t<r.length;t++)i^=r.charCodeAt(t),i=Math.imul(i,16777619);return(i>>>0)%100}function h(r,i,t,e){if(r.killSwitch||!r.automaticPatchEnabled||r.blockedVersions.includes(e)||r.pausedVersions.includes(e)||r.pausedVersions.includes(t))return!1;const s=Math.max(0,Math.min(100,Math.floor(r.rolloutPercentage)));return m(i)<s}async function p(r){const i=new URL("/api/releases/cli-policy",r),t=await fetch(i,{headers:{Accept:"application/json"},signal:AbortSignal.timeout(1e4)});if(!t.ok)throw new Error(`release policy returned ${t.status}`);const e=await t.json();return{automaticPatchEnabled:e.automaticPatchEnabled===!0,rolloutPercentage:typeof e.rolloutPercentage=="number"?e.rolloutPercentage:0,pausedVersions:Array.isArray(e.pausedVersions)?e.pausedVersions.filter(s=>typeof s=="string"):[],blockedVersions:Array.isArray(e.blockedVersions)?e.blockedVersions.filter(s=>typeof s=="string"):[],blockedCurrentVersions:Array.isArray(e.blockedCurrentVersions)?e.blockedCurrentVersions.filter(s=>typeof s=="string"):[],killSwitch:e.killSwitch!==!1,releaseLevel:e.releaseLevel==="required"||e.releaseLevel==="blocked"?e.releaseLevel:"normal",maxIdleWaitMs:typeof e.maxIdleWaitMs=="number"&&Number.isFinite(e.maxIdleWaitMs)?Math.max(0,Math.min(1440*6e4,Math.floor(e.maxIdleWaitMs))):30*6e4,...typeof e.minimumSessionSyncProtocolVersion=="number"?{minimumSessionSyncProtocolVersion:e.minimumSessionSyncProtocolVersion}:{},...typeof e.minimumDataEpoch=="number"?{minimumDataEpoch:e.minimumDataEpoch}:{},requiredCapabilities:Array.isArray(e.requiredCapabilities)?e.requiredCapabilities.filter(s=>typeof s=="string"):[],externalUpdaterEnabled:e.externalUpdaterEnabled===!0,...typeof e.minimumUpdaterProtocolVersion=="number"?{minimumUpdaterProtocolVersion:e.minimumUpdaterProtocolVersion}:{}}}class b{deps;policy="none";timer=null;started=!1;upgradeInFlight=!1;constructor(i){this.deps=i}start(){a()||this.started||(this.started=!0,this.arm(this.deps.initialDelayMs??3e4))}stop(){this.started=!1,this.timer&&(this.deps.clearTimeout??clearTimeout)(this.timer),this.timer=null}setPolicy(i){this.policy=i,this.started&&(this.timer||this.arm(0))}getPolicy(){return this.policy}async runOnce(){if(a()||this.upgradeInFlight)return;const i=await(this.deps.checkForUpdate??u)(this.deps.currentVersion);if(!i.hasUpdate||(this.deps.inCooldown??c)(i.latest))return;let t=d;try{t=await(this.deps.fetchReleasePolicy??(()=>p(this.deps.serverUrl)))()}catch{return}if(t.killSwitch||!t.externalUpdaterEnabled||t.blockedVersions.includes(i.latest)||t.pausedVersions.includes(i.latest)||t.pausedVersions.includes(i.current))return;const e=t.blockedCurrentVersions.includes(i.current)?"blocked":t.releaseLevel,s=t.minimumSessionSyncProtocolVersion!==void 0&&(this.deps.sessionSyncProtocolVersion??0)<t.minimumSessionSyncProtocolVersion||t.minimumDataEpoch!==void 0&&(this.deps.dataEpoch??0)<t.minimumDataEpoch||t.requiredCapabilities.some(l=>!(this.deps.advertisedCapabilities??[]).includes(l))||t.minimumUpdaterProtocolVersion!==void 0&&(this.deps.updaterProtocolVersion??0)<t.minimumUpdaterProtocolVersion,n=e==="required"||e==="blocked"||s;if(!n&&(this.policy!=="patch"||i.changeType!=="patch"||!h(t,this.deps.machineId,i.current,i.latest)))return;const o=this.deps.getIdleState();if(!(!n&&!o.idle)){this.upgradeInFlight=!0;try{await this.deps.startUpgrade(i.latest,n)}finally{this.upgradeInFlight=!1}}}nextIntervalMs(){return this.deps.intervalMs??5*6e4+Math.floor((this.deps.random??Math.random)()*10*6e4)}arm(i){if(!this.started||this.timer)return;const t=this.deps.setTimeout??setTimeout;this.timer=t(()=>{this.timer=null,this.runOnce().catch(()=>{}).finally(()=>{this.started&&this.arm(this.nextIntervalMs())})},i),this.timer.unref?.()}}export{b as AutoUpgradeScheduler,m as deterministicRolloutBucket,p as fetchCliReleasePolicy,h as isAutomaticPatchAllowed};
@@ -1,3 +1,3 @@
1
- import r from"node:fs";import d from"node:path";import{randomUUID as y}from"node:crypto";import{spawn as I,spawnSync as j}from"node:child_process";import{resolveShennianPath as p}from"../config/index.js";import{findPackageJson as P,resolveNpmGlobalPrefixFromPackageJson as _}from"./engine.js";import{ensureUpdaterInstalled as E}from"./updater-bootstrap.js";import{UPDATER_PROTOCOL_VERSION as S}from"./updater-protocol.js";function w(e,o){r.mkdirSync(d.dirname(e),{recursive:!0,mode:448});const a=`${e}.tmp-${process.pid}-${y()}`;try{r.writeFileSync(a,`${JSON.stringify(o,null,2)}
2
- `,{mode:384,flag:"wx"});const n=r.openSync(a,process.platform==="win32"?"r+":"r");try{r.fsyncSync(n)}finally{r.closeSync(n)}if(r.renameSync(a,e),process.platform!=="win32"){const t=r.openSync(d.dirname(e),"r");try{r.fsyncSync(t)}finally{r.closeSync(t)}}}finally{try{r.unlinkSync(a)}catch{}}}function J(e){const o=e.root??p("runtime","updater"),a=P(),n=e.npmPrefix??(a?_(a):null);if(!n)throw new Error("Cannot determine the active npm prefix");const t=e.jobId??y();return{protocolVersion:S,jobId:t,fromVersion:e.fromVersion,targetVersion:e.targetVersion,npmPrefix:n,npmExecutable:e.npmExecutable??(process.platform==="win32"?"npm.cmd":"npm"),nodeExecutable:e.nodeExecutable??process.execPath,packageName:"shennian",operation:e.operation??"upgrade",oldDaemonPid:e.oldDaemonPid,platform:process.platform,createdAt:(e.now??new Date).toISOString(),daemonExitTimeoutMs:15e3,commandTimeoutMs:12e4,resultPath:d.join(o,"results",`${t}.json`),attemptPath:p("upgrade-attempt.json"),...e.requireHandoffAck?{requireHandoffAck:!0}:{},...e.rollbackJobId?{rollbackJobId:e.rollbackJobId}:{},...e.isolatedDaemonStart?{isolatedDaemonStart:!0}:{}}}function $(e,o=p("runtime","updater")){const a=d.join(o,"jobs");r.mkdirSync(a,{recursive:!0,mode:448});const n=d.join(a,`${e.jobId}.json`),t=`${n}.tmp-${process.pid}-${y()}`;try{r.writeFileSync(t,`${JSON.stringify(e,null,2)}
3
- `,{mode:384,flag:"wx"});const c=r.openSync(t,process.platform==="win32"?"r+":"r");try{r.fsyncSync(c)}finally{r.closeSync(c)}if(r.renameSync(t,n),process.platform!=="win32"){const s=r.openSync(a,"r");try{r.fsyncSync(s)}finally{r.closeSync(s)}}return n}finally{try{r.unlinkSync(t)}catch{}}}function O(e,o){return e==="linux"&&/(?:^|\/)shennian\.service(?:\n|$)/m.test(o.trim())}function H(e,o={}){const a=o.root??e.root??p("runtime","updater"),n=o.readiness??E({root:a}),t=J({...e,root:a}),c=$(t,a),s=d.join(a,"updater.lock");r.mkdirSync(a,{recursive:!0,mode:448});let l=null,f=!1;const h=()=>{if(f){try{JSON.parse(r.readFileSync(s,"utf8")).jobId===t.jobId&&r.unlinkSync(s)}catch{}f=!1}};try{try{l=r.openSync(s,"wx",384),f=!0}catch(i){if(i.code!=="EEXIST")throw i;let b=!1;try{const g=JSON.parse(r.readFileSync(s,"utf8")),k=o.isAlive??(x=>{try{return process.kill(x,0),!0}catch{return!1}});b=!!(g.pid&&k(g.pid))}catch{}if(b)throw new Error("upgrade_locked");r.rmSync(s,{force:!0}),l=r.openSync(s,"wx",384),f=!0}r.writeFileSync(l,JSON.stringify({jobId:t.jobId,phase:"handoff",pid:process.pid,createdAt:(o.now??Date.now)()})),r.closeSync(l),l=null;let u=o.serviceCgroup??"";if(process.platform==="linux"&&!o.spawn&&o.serviceCgroup===void 0)try{u=r.readFileSync("/proc/self/cgroup","utf8")}catch{}if(O(o.platform??process.platform,u)){const i=(o.systemdRun??j)("systemd-run",["--user","--quiet","--collect",`--unit=shennian-updater-${t.jobId}`,"--property=Type=exec","--property=KillMode=process",`--setenv=PATH=${process.env.PATH??"/usr/local/bin:/usr/bin:/bin"}`,"--",t.nodeExecutable,n.workerPath,c],{encoding:"utf8",stdio:"pipe",timeout:1e4});if(i.error||i.status!==0)throw new Error("updater_service_launch_failed");return{job:t,process:null}}const m=(o.spawn??I)(t.nodeExecutable,[n.workerPath,c],{detached:!0,stdio:"ignore",windowsHide:!0});return m.once?.("error",i=>{w(t.resultPath,{protocolVersion:S,jobId:t.jobId,state:"failed",fromVersion:t.fromVersion,targetVersion:t.targetVersion,errorCode:"internal_error",errorSummary:i instanceof Error?i.message.slice(0,500):"updater_spawn_failed",updatedAt:new Date().toISOString()}),h()}),m.unref(),{job:t,process:m}}catch(u){l!==null&&r.closeSync(l),h();try{r.unlinkSync(c)}catch{}throw u}}async function C(e,o=8e3){const a=Date.now()+o;for(;Date.now()<a;){let n=null;try{n=JSON.parse(r.readFileSync(e.resultPath,"utf8"))}catch{}if(n?.jobId===e.jobId&&n.state==="waiting_for_daemon")return;if(n?.jobId===e.jobId&&n.state==="failed")throw new Error(n.errorCode??"updater_not_ready");await new Promise(t=>setTimeout(t,50))}throw new Error("updater_readiness_timeout")}function R(e){w(`${e.resultPath}.handoff`,{jobId:e.jobId})}function L(e,o,a=p("runtime","updater")){if(!/^[A-Za-z0-9_-]{1,128}$/.test(e))return!1;const n=d.join(a,"results",`${e}.json`);try{const t=r.lstatSync(n);if(t.isSymbolicLink()||!t.isFile())return!1;const c=JSON.parse(r.readFileSync(n,"utf8"));return c.protocolVersion!==S||c.jobId!==e||c.state!=="starting"||c.targetVersion!==o?!1:(w(n,{...c,state:c.operation==="rollback"?"rolled_back":"healthy",effectiveVersion:o,updatedAt:new Date().toISOString()}),!0)}catch{return!1}}export{R as confirmUpdaterHandoff,J as createUpdaterJob,H as launchUpdater,L as markUpdaterHealthy,O as needsSystemdUpdater,C as waitForUpdaterReady,$ as writeUpdaterJob};
1
+ import r from"node:fs";import{assertStandaloneUpgrade as I}from"../runtime-distribution.js";import d from"node:path";import{randomUUID as y}from"node:crypto";import{spawn as j,spawnSync as P}from"node:child_process";import{resolveShennianPath as p}from"../config/index.js";import{findPackageJson as _,resolveNpmGlobalPrefixFromPackageJson as E}from"./engine.js";import{ensureUpdaterInstalled as J}from"./updater-bootstrap.js";import{UPDATER_PROTOCOL_VERSION as S}from"./updater-protocol.js";function w(e,o){r.mkdirSync(d.dirname(e),{recursive:!0,mode:448});const a=`${e}.tmp-${process.pid}-${y()}`;try{r.writeFileSync(a,`${JSON.stringify(o,null,2)}
2
+ `,{mode:384,flag:"wx"});const n=r.openSync(a,process.platform==="win32"?"r+":"r");try{r.fsyncSync(n)}finally{r.closeSync(n)}if(r.renameSync(a,e),process.platform!=="win32"){const t=r.openSync(d.dirname(e),"r");try{r.fsyncSync(t)}finally{r.closeSync(t)}}}finally{try{r.unlinkSync(a)}catch{}}}function $(e){I();const o=e.root??p("runtime","updater"),a=_(),n=e.npmPrefix??(a?E(a):null);if(!n)throw new Error("Cannot determine the active npm prefix");const t=e.jobId??y();return{protocolVersion:S,jobId:t,fromVersion:e.fromVersion,targetVersion:e.targetVersion,npmPrefix:n,npmExecutable:e.npmExecutable??(process.platform==="win32"?"npm.cmd":"npm"),nodeExecutable:e.nodeExecutable??process.execPath,packageName:"shennian",operation:e.operation??"upgrade",oldDaemonPid:e.oldDaemonPid,platform:process.platform,createdAt:(e.now??new Date).toISOString(),daemonExitTimeoutMs:15e3,commandTimeoutMs:12e4,resultPath:d.join(o,"results",`${t}.json`),attemptPath:p("upgrade-attempt.json"),...e.requireHandoffAck?{requireHandoffAck:!0}:{},...e.rollbackJobId?{rollbackJobId:e.rollbackJobId}:{},...e.isolatedDaemonStart?{isolatedDaemonStart:!0}:{}}}function O(e,o=p("runtime","updater")){const a=d.join(o,"jobs");r.mkdirSync(a,{recursive:!0,mode:448});const n=d.join(a,`${e.jobId}.json`),t=`${n}.tmp-${process.pid}-${y()}`;try{r.writeFileSync(t,`${JSON.stringify(e,null,2)}
3
+ `,{mode:384,flag:"wx"});const c=r.openSync(t,process.platform==="win32"?"r+":"r");try{r.fsyncSync(c)}finally{r.closeSync(c)}if(r.renameSync(t,n),process.platform!=="win32"){const s=r.openSync(a,"r");try{r.fsyncSync(s)}finally{r.closeSync(s)}}return n}finally{try{r.unlinkSync(t)}catch{}}}function F(e,o){return e==="linux"&&/(?:^|\/)shennian\.service(?:\n|$)/m.test(o.trim())}function R(e,o={}){const a=o.root??e.root??p("runtime","updater"),n=o.readiness??J({root:a}),t=$({...e,root:a}),c=O(t,a),s=d.join(a,"updater.lock");r.mkdirSync(a,{recursive:!0,mode:448});let l=null,f=!1;const h=()=>{if(f){try{JSON.parse(r.readFileSync(s,"utf8")).jobId===t.jobId&&r.unlinkSync(s)}catch{}f=!1}};try{try{l=r.openSync(s,"wx",384),f=!0}catch(i){if(i.code!=="EEXIST")throw i;let b=!1;try{const g=JSON.parse(r.readFileSync(s,"utf8")),k=o.isAlive??(x=>{try{return process.kill(x,0),!0}catch{return!1}});b=!!(g.pid&&k(g.pid))}catch{}if(b)throw new Error("upgrade_locked");r.rmSync(s,{force:!0}),l=r.openSync(s,"wx",384),f=!0}r.writeFileSync(l,JSON.stringify({jobId:t.jobId,phase:"handoff",pid:process.pid,createdAt:(o.now??Date.now)()})),r.closeSync(l),l=null;let u=o.serviceCgroup??"";if(process.platform==="linux"&&!o.spawn&&o.serviceCgroup===void 0)try{u=r.readFileSync("/proc/self/cgroup","utf8")}catch{}if(F(o.platform??process.platform,u)){const i=(o.systemdRun??P)("systemd-run",["--user","--quiet","--collect",`--unit=shennian-updater-${t.jobId}`,"--property=Type=exec","--property=KillMode=process",`--setenv=PATH=${process.env.PATH??"/usr/local/bin:/usr/bin:/bin"}`,"--",t.nodeExecutable,n.workerPath,c],{encoding:"utf8",stdio:"pipe",timeout:1e4});if(i.error||i.status!==0)throw new Error("updater_service_launch_failed");return{job:t,process:null}}const m=(o.spawn??j)(t.nodeExecutable,[n.workerPath,c],{detached:!0,stdio:"ignore",windowsHide:!0});return m.once?.("error",i=>{w(t.resultPath,{protocolVersion:S,jobId:t.jobId,state:"failed",fromVersion:t.fromVersion,targetVersion:t.targetVersion,errorCode:"internal_error",errorSummary:i instanceof Error?i.message.slice(0,500):"updater_spawn_failed",updatedAt:new Date().toISOString()}),h()}),m.unref(),{job:t,process:m}}catch(u){l!==null&&r.closeSync(l),h();try{r.unlinkSync(c)}catch{}throw u}}async function L(e,o=8e3){const a=Date.now()+o;for(;Date.now()<a;){let n=null;try{n=JSON.parse(r.readFileSync(e.resultPath,"utf8"))}catch{}if(n?.jobId===e.jobId&&n.state==="waiting_for_daemon")return;if(n?.jobId===e.jobId&&n.state==="failed")throw new Error(n.errorCode??"updater_not_ready");await new Promise(t=>setTimeout(t,50))}throw new Error("updater_readiness_timeout")}function q(e){w(`${e.resultPath}.handoff`,{jobId:e.jobId})}function M(e,o,a=p("runtime","updater")){if(!/^[A-Za-z0-9_-]{1,128}$/.test(e))return!1;const n=d.join(a,"results",`${e}.json`);try{const t=r.lstatSync(n);if(t.isSymbolicLink()||!t.isFile())return!1;const c=JSON.parse(r.readFileSync(n,"utf8"));return c.protocolVersion!==S||c.jobId!==e||c.state!=="starting"||c.targetVersion!==o?!1:(w(n,{...c,state:c.operation==="rollback"?"rolled_back":"healthy",effectiveVersion:o,updatedAt:new Date().toISOString()}),!0)}catch{return!1}}export{q as confirmUpdaterHandoff,$ as createUpdaterJob,R as launchUpdater,M as markUpdaterHealthy,F as needsSystemdUpdater,L as waitForUpdaterReady,O as writeUpdaterJob};
@@ -38,6 +38,8 @@ export type RoomSummary = {
38
38
  lastReadSequence?: RoomSequence;
39
39
  unreadCount?: number;
40
40
  membershipRole?: RoomMembershipRole;
41
+ /** The signed-in human's relationship to this Room. Older servers may omit it. */
42
+ membershipStatus?: 'active' | 'left' | 'removed';
41
43
  pinnedAt?: string | null;
42
44
  updatedAt: string;
43
45
  /** Optional list projection used by local-first clients to avoid per-room requests. */
@@ -1,6 +1,6 @@
1
1
  import type { Envelope } from './envelope.ts';
2
- import type { AgentType, ManagerConfig, SessionMode } from './session.ts';
3
2
  import type { ProjectFsOpaqueCapability } from './project-fs.ts';
3
+ import type { AgentType, ManagerConfig, SessionMode } from './session.ts';
4
4
  export declare const SESSION_SYNC_PROTOCOL_VERSION: 2;
5
5
  export type SessionSyncProtocolVersion = typeof SESSION_SYNC_PROTOCOL_VERSION;
6
6
  /**
@@ -320,6 +320,7 @@ export type SessionBodyReplicaErrorEvent = {
320
320
  * accepted from a daemon payload.
321
321
  */
322
322
  export type DaemonSessionIndexProjection = {
323
+ nativeSessionVisibility?: 'user' | 'internal';
323
324
  id: string;
324
325
  agentType: AgentType;
325
326
  sessionMode?: SessionMode;
@@ -117,6 +117,8 @@ export type AcpExternalSessionIdentity = {
117
117
  export type AgentInfo = {
118
118
  type: AgentType;
119
119
  models: ModelInfo[];
120
+ /** True when this runtime can back an ordinary Shennian session. */
121
+ supportsStandardSession?: boolean;
120
122
  /** User-facing grouping. Omitted by older daemons and interpreted as deep. */
121
123
  integration?: AgentIntegration;
122
124
  /** Non-secret metadata used for dynamic ACP display fallbacks. */
@@ -137,6 +139,10 @@ export type AgentInfo = {
137
139
  supportsWorker?: boolean;
138
140
  /** True only after this real provider passed Manager-mode runtime validation. */
139
141
  supportsManagerMode?: boolean;
142
+ /** True when a managed Room turn can receive explicit Room tools. */
143
+ supportsRoomTools?: boolean;
144
+ /** True when the public temporary Worker controller may target this runtime. */
145
+ supportsExternalWorkerTarget?: boolean;
140
146
  /** Per-machine Agent provider config summary (additive, non-secret). */
141
147
  config?: AgentConfigSummary;
142
148
  /** Non-secret runtime version and compatibility summary. */
@@ -279,6 +285,8 @@ export type NianSession = {
279
285
  agentType: AgentType;
280
286
  /** Missing on legacy records/clients and normalized to standard, except legacy agentType=manager. */
281
287
  sessionMode?: SessionMode;
288
+ /** Internal orchestration stays out of personal discovery; linked details remain readable. */
289
+ nativeSessionVisibility?: 'user' | 'internal';
282
290
  managerConfig?: ManagerConfig | null;
283
291
  agentSessionId: string | null;
284
292
  sourceMode?: NativeSessionSourceMode | null;
@@ -336,7 +344,7 @@ export type NianSession = {
336
344
  activity?: SessionActivitySnapshot | null;
337
345
  externalChannel?: ExternalChannelSessionStatus | null;
338
346
  };
339
- export type SessionListProjection = Pick<NianSession, 'id' | 'machineId' | 'userId' | 'agentType' | 'sessionMode' | 'managerConfig' | 'agentSessionId' | 'modelId' | 'managerDefaultWorkerAgentType' | 'managerDefaultWorkerModelId' | 'title' | 'titleSource' | 'titleRevision' | 'titleLockedByUser' | 'titleOriginEventId' | 'status' | 'workDir' | 'lastMessagePreview' | 'lastMessagePreviewMessageId' | 'lastMessagePreviewAt' | 'lastVisibleEventAt' | 'bodyStorageMode' | 'bodyRevision' | 'indexRevision' | 'dataEpoch' | 'firstAvailableSeq' | 'visibleMessageCount' | 'lastVisibleMessageId' | 'attentionCount' | 'lastAttentionId' | 'lastBodyCommittedAt' | 'deletionRevision' | 'lastActivityAt' | 'createdAt' | 'updatedAt' | 'deletedAt' | 'machineName' | 'ownerName' | 'ownerPhone' | 'ownerEmail' | 'canManage' | 'sharedMachineSession' | 'activity' | 'externalChannel'>;
347
+ export type SessionListProjection = Pick<NianSession, 'id' | 'machineId' | 'userId' | 'agentType' | 'sessionMode' | 'nativeSessionVisibility' | 'managerConfig' | 'agentSessionId' | 'modelId' | 'managerDefaultWorkerAgentType' | 'managerDefaultWorkerModelId' | 'title' | 'titleSource' | 'titleRevision' | 'titleLockedByUser' | 'titleOriginEventId' | 'status' | 'workDir' | 'lastMessagePreview' | 'lastMessagePreviewMessageId' | 'lastMessagePreviewAt' | 'lastVisibleEventAt' | 'bodyStorageMode' | 'bodyRevision' | 'indexRevision' | 'dataEpoch' | 'firstAvailableSeq' | 'visibleMessageCount' | 'lastVisibleMessageId' | 'attentionCount' | 'lastAttentionId' | 'lastBodyCommittedAt' | 'deletionRevision' | 'lastActivityAt' | 'createdAt' | 'updatedAt' | 'deletedAt' | 'machineName' | 'ownerName' | 'ownerPhone' | 'ownerEmail' | 'canManage' | 'sharedMachineSession' | 'activity' | 'externalChannel'>;
340
348
  export type ChatSendParams = PersonalSyncIdentity & {
341
349
  sessionId: string;
342
350
  text: string;
@@ -382,6 +390,12 @@ export type QueuedChatMessage = PersonalSyncIdentity & {
382
390
  replyTarget?: string | null;
383
391
  createdAt: string;
384
392
  updatedAt: string;
393
+ /** Presentation state for the shared pending-message panel. */
394
+ pendingState?: 'waiting' | 'submitting' | 'provider_queued';
395
+ /** Whether the current client may delete this item before Provider claim. */
396
+ canDelete?: boolean;
397
+ /** Whether the daemon currently has a truthful immediate-send path. */
398
+ canPromote?: boolean;
385
399
  };
386
400
  export type ChatQueueSnapshot = PersonalSyncIdentity & {
387
401
  sessionId: string;
@@ -389,6 +403,8 @@ export type ChatQueueSnapshot = PersonalSyncIdentity & {
389
403
  pending: QueuedChatMessage[];
390
404
  /** Owner-authored messages that may be deleted or promoted by the current UI. */
391
405
  controllablePending?: QueuedChatMessage[];
406
+ /** All owner-authored pending items that belong in the shared composer panel. */
407
+ visiblePending?: QueuedChatMessage[];
392
408
  };
393
409
  export type ChatEnqueueParams = ChatSendParams & {
394
410
  queueMessageId?: string;
@@ -439,3 +455,11 @@ export type FsReadParams = {
439
455
  path: string;
440
456
  rootPath?: string;
441
457
  };
458
+ /** Visibility is separate from access: an Owner can still open linked internal details. */
459
+ export declare function isInternalSession(session: {
460
+ id: string;
461
+ nativeSessionVisibility?: string | null;
462
+ agentType?: string;
463
+ sessionMode?: string | null;
464
+ agentIdentityId?: string | null;
465
+ }): boolean;
@@ -50,3 +50,11 @@ export function filterAvailableAgentInfos(agents) {
50
50
  }
51
51
  return filtered;
52
52
  }
53
+ /** Visibility is separate from access: an Owner can still open linked internal details. */
54
+ export function isInternalSession(session) {
55
+ return session.nativeSessionVisibility === 'internal'
56
+ || session.id.startsWith('sess_worker_')
57
+ || session.agentType === 'manager'
58
+ || session.sessionMode === 'manager'
59
+ || Boolean(session.agentIdentityId);
60
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.4.69",
3
+ "version": "0.4.72",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {