@messenger-agent/client 0.38.0-alpha.2 → 0.38.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +4 -4
- package/dist/maintenance.d.ts +1 -1
- package/dist/maintenance.js +1 -1
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.js +3 -3
- package/dist/supervisor.js +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{parseCliArgs as
|
|
3
|
-
`)}function
|
|
4
|
-
`):"No maintenance task has been scheduled"}function
|
|
2
|
+
import{parseCliArgs as y,UsageError as A,usage as f}from"./args.js";import{activateMigratedService as N,completeMigrationHandoff as T,installClient as W}from"./install.js";import{currentPackageVersion as p,installRuntime as b,normalizeUpgradeVersion as G,pruneRuntimeReleases as O,rollbackRuntime as _}from"./runtime.js";import{serviceCommandsForConfig as h,serviceName as w,uninstallLegacyService as R,uninstallService as D,verifyServiceHealth as E}from"./service.js";import{runSupervisor as H}from"./supervisor.js";import{runCommand as M}from"./exec.js";import{defaultConfigPath as i,preferredClientPaths as l}from"./paths.js";import{readAgentServer as F,readClientPath as I,writeClientPath as $,writeUpgradeChannel as v}from"./config-file.js";import{requestAgentRestart as U,requestClientActivity as k,requestMaintenanceCancel as q,requestMaintenanceStatus as L,requestScheduleMaintenance as j}from"./control.js";import{cliName as x,productName as z}from"./identity.js";import{migrateLegacyClient as B}from"./migration.js";import{assertPlatformNativeDependencies as J}from"./native-dependencies.js";async function V(){const e=y(process.argv.slice(2));if(e.command==="version"){console.log(`${x} ${await p()}`);return}if(e.command==="self-check"){await p(),J(),console.log(`${z} runtime is healthy`);return}if(e.command==="complete-migration"){await T(e.handoffPath);return}if(e.command==="run-service"){await H(e.configPath??process.env.AGENT_CONFIG_PATH??i);return}if(e.command==="install"){const t=await W(e);console.log(`Installed ${w}`),console.log(`Config: ${t.configPath}`),console.log(`Data: ${t.dataDir}`),console.log(`Runtime: ${t.runtime.currentLink}`),console.log(`Command: ${t.runtime.cliWrapperPath}`),console.log(`Service file: ${t.service.servicePath}`),console.log(`Upgrade: ${t.runtime.cliWrapperPath} upgrade`),console.log(`Restart: ${t.runtime.cliWrapperPath} restart`),console.log(`Status: ${t.runtime.cliWrapperPath} status`),console.log(`Logs: ${t.service.commands.logs}`);for(const n of t.service.warnings)console.warn(`Warning: ${n}`);return}if(e.command==="upgrade"){const{version:t,channel:n}=G(e.version,e.channel),a=process.env.PATH,o=e.configPath===i?l().configPath:e.configPath;if(a&&await $(o,a),n&&(await v(o,n),console.log(`Auto-upgrade channel: ${n}`)),e.delaySeconds!==void 0){await m(o,{type:"upgrade",version:t,path:a},e.delaySeconds,e.allowWaiting);return}const s=await B(),r=o===s.legacyPaths.configPath?s.paths.configPath:o;a&&r!==o&&await $(r,a),n&&r!==o&&await v(r,n);const c=await b({version:t,configPath:r,server:await F(r),runtimeDir:s.paths.runtimeDir,binDir:s.paths.binDir,path:a??await I(r)});if(!await N(s,c,r,a)){const d=h(r);try{await g(d.restart),await E()}catch(u){throw await _(c),await g(d.restart).catch(()=>{}),u}await O(s.paths.runtimeDir).catch(u=>{console.error(`Warning: failed to remove old runtime releases: ${String(u)}`)})}console.log(`Upgraded runtime to ${c.version}`),console.log(`Runtime: ${c.currentLink}`),console.log(`Command: ${c.cliWrapperPath}`),console.log(`Status: ${c.cliWrapperPath} status`);return}if(e.command==="sessions"){const t=await k(P(e.configPath));console.log(e.json?JSON.stringify(t):K(t));return}if(e.command==="maintenance"){const t=P(e.configPath),n=e.action==="cancel"?await q(t):await L(t);console.log(e.json?JSON.stringify(n??null):Q(n));return}if(e.command==="restart"&&e.agent){if(e.delaySeconds!==void 0){await m(process.env.AGENT_CONFIG_PATH??i,{type:"restart",agent:e.agent},e.delaySeconds,e.allowWaiting);return}await U(process.env.AGENT_CONFIG_PATH??i,e.agent),console.log(`Restarted ${e.agent} agent`);return}if(e.command==="status"||e.command==="start"||e.command==="restart"||e.command==="stop"){if((e.command==="restart"||e.command==="stop")&&e.delaySeconds!==void 0){await m(process.env.AGENT_CONFIG_PATH??i,{type:e.command},e.delaySeconds,e.allowWaiting);return}const t=l().configPath,n=h(t),a=e.command==="status"?n.status:e.command==="start"?n.start:e.command==="restart"?n.restart:n.stop;await g(a);return}if(e.command==="uninstall"){if(e.delaySeconds!==void 0){await m(process.env.AGENT_CONFIG_PATH??i,{type:"uninstall"},e.delaySeconds,e.allowWaiting);return}l().configPath===i?await D():await R(),console.log(`Uninstalled ${w}`);return}}function P(e){return e===i?l().configPath:e}async function m(e,t,n,a){const o=await j(e,{operation:t,delaySeconds:n,allowWaiting:a});console.log(`Scheduled maintenance task ${o.id}`),console.log(`Operation: ${C(o.operation)}`),console.log(`Not before: ${o.notBefore}`)}function K(e){const t=[`Active sessions: ${e.active}`,`Waiting sessions: ${e.waiting}`];for(const n of["codex","claude"]){const a=e.agents[n];t.push(a.available?`${S(n)}: active=${a.active}, waiting=${a.waiting}`:`${S(n)}: unavailable (${a.error})`)}return t.join(`
|
|
3
|
+
`)}function Q(e){return e?[`Task: ${e.id}`,`Operation: ${C(e.operation)}`,`Status: ${e.status}`,`Not before: ${e.notBefore}`,...e.message?[`Message: ${e.message}`]:[]].join(`
|
|
4
|
+
`):"No maintenance task has been scheduled"}function C(e){return e.type==="upgrade"?`upgrade to ${e.version}`:e.type==="restart"?e.agent?`restart ${e.agent}`:"restart client":e.type}function S(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}async function g(e){const t=await M("/bin/sh",["-lc",e],{allowFailure:!0});if(t.stdout&&process.stdout.write(t.stdout),t.stderr&&process.stderr.write(t.stderr),t.status!==0)throw new Error(t.stderr||t.stdout||`Command failed: ${e}`)}V().catch(e=>{if(e instanceof A){const n=e.message===f()?e.message:`${e.message}
|
|
5
5
|
|
|
6
|
-
${
|
|
6
|
+
${f()}`;console.error(n),process.exit(2)}const t=e instanceof Error?e.message:String(e);console.error(t),process.exit(1)});
|
package/dist/maintenance.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export declare class MaintenanceScheduler {
|
|
|
48
48
|
private readonly maxWaitMs;
|
|
49
49
|
private readonly now;
|
|
50
50
|
constructor(options: MaintenanceSchedulerOptions);
|
|
51
|
-
start(): Promise<
|
|
51
|
+
start(): Promise<MaintenanceTask | undefined>;
|
|
52
52
|
schedule(options: ScheduleMaintenanceOptions): Promise<MaintenanceTask>;
|
|
53
53
|
getTask(): MaintenanceTask | undefined;
|
|
54
54
|
cancel(): Promise<MaintenanceTask>;
|
package/dist/maintenance.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{randomUUID as o}from"node:crypto";import{mkdir as h,readFile as c,rename as u,writeFile as d}from"node:fs/promises";import{dirname as l}from"node:path";const w=new Set(["scheduled","waiting","running","restarting","stopping"]);class p{options;task;timer;pollIntervalMs;maxWaitMs;now;constructor(t){this.options=t,this.pollIntervalMs=t.pollIntervalMs??1e3,this.maxWaitMs=t.maxWaitMs??3600*1e3,this.now=t.now??Date.now}async start(){if(this.task=await this.readState(),!!this.task){if(this.task.status==="restarting"||this.task.status==="stopping"){const t=this.isoNow();this.task={...this.task,status:"completed",updatedAt:
|
|
1
|
+
import{randomUUID as o}from"node:crypto";import{mkdir as h,readFile as c,rename as u,writeFile as d}from"node:fs/promises";import{dirname as l}from"node:path";const w=new Set(["scheduled","waiting","running","restarting","stopping"]);class p{options;task;timer;pollIntervalMs;maxWaitMs;now;constructor(t){this.options=t,this.pollIntervalMs=t.pollIntervalMs??1e3,this.maxWaitMs=t.maxWaitMs??3600*1e3,this.now=t.now??Date.now}async start(){if(this.task=await this.readState(),!!this.task){if(this.task.status==="restarting"||this.task.status==="stopping"){const t=structuredClone(this.task),i=this.isoNow();return this.task={...this.task,status:"completed",updatedAt:i,completedAt:i,message:"Client service completed the maintenance operation"},await this.writeState(),t}if(this.task.status==="running"){await this.finish("failed","Client service exited before the maintenance operation completed");return}(this.task.status==="scheduled"||this.task.status==="waiting")&&this.arm()}}async schedule(t){if(!Number.isInteger(t.delaySeconds)||t.delaySeconds<1||t.delaySeconds>86400)throw new Error("--delay must be an integer between 1 and 86400 seconds");if(this.task&&w.has(this.task.status)&&!(t.source!=="automatic"&&this.task.source==="automatic"&&m(this.task)))throw new Error(`Maintenance task ${this.task.id} is already ${this.task.status}`);const i=this.now(),s=new Date(i).toISOString();return this.task={id:o(),operation:t.operation,status:"scheduled",allowWaiting:t.allowWaiting,createdAt:s,notBefore:new Date(i+t.delaySeconds*1e3).toISOString(),updatedAt:s,source:t.source??"manual"},await this.writeState(),this.arm(),this.task}getTask(){return this.task?structuredClone(this.task):void 0}async cancel(){if(!this.task||this.task.status!=="scheduled"&&this.task.status!=="waiting")throw new Error("No cancellable maintenance task");this.timer&&clearTimeout(this.timer);const t=this.isoNow();return this.task={...this.task,status:"cancelled",updatedAt:t,completedAt:t,message:"Cancelled by user"},await this.writeState(),this.task}stop(){this.timer&&clearTimeout(this.timer),this.timer=void 0}async checkNow(){this.timer&&clearTimeout(this.timer),this.timer=void 0,await this.tick()}arm(t){if(!this.task||this.task.status!=="scheduled"&&this.task.status!=="waiting")return;this.timer&&clearTimeout(this.timer);const i=Math.max(0,Date.parse(this.task.notBefore)-this.now());this.timer=setTimeout(()=>this.tick(),t??i),this.timer.unref()}async tick(){this.timer=void 0;const t=this.task;if(!(!t||t.status!=="scheduled"&&t.status!=="waiting")){if(this.now()<Date.parse(t.notBefore)){this.arm();return}try{const i=await this.options.getActivity(),s=Object.entries(i.agents).filter(([,a])=>!a.available).map(([a])=>a),e=[];if(s.length>0&&e.push(`unavailable agents: ${s.join(", ")}`),i.active>0&&e.push(`${i.active} active session(s)`),!t.allowWaiting&&i.waiting>0&&e.push(`${i.waiting} waiting session(s)`),e.length>0){if(t.source!=="automatic"&&this.now()-Date.parse(t.notBefore)>=this.maxWaitMs){await this.finish("failed",`Timed out waiting for an idle client: ${e.join("; ")}`);return}await this.updateWaiting(`Waiting for an idle client: ${e.join("; ")}`),this.arm(this.pollIntervalMs);return}const r=this.isoNow();this.task={...t,status:"running",updatedAt:r,message:"Maintenance operation is running"},await this.writeState(),await this.options.execute(t.operation,a=>this.markServiceExit(a)),await this.finish("completed","Maintenance operation completed")}catch(i){await this.finish("failed",i instanceof Error?i.message:String(i))}}}async updateWaiting(t){this.task&&(this.task={...this.task,status:"waiting",updatedAt:this.isoNow(),message:t},await this.writeState())}async markServiceExit(t){!this.task||this.task.status!=="running"||(this.task={...this.task,status:t,updatedAt:this.isoNow(),message:`Maintenance operation is ${t==="restarting"?"restarting":"stopping"} the client service`},await this.writeState())}async finish(t,i){if(!this.task)return;const s=this.isoNow();this.task={...this.task,status:t,updatedAt:s,completedAt:s,message:i},await this.writeState()}isoNow(){return new Date(this.now()).toISOString()}async readState(){try{return JSON.parse(await c(this.options.statePath,"utf8"))}catch(t){if(t.code==="ENOENT")return;throw t}}async writeState(){if(!this.task)return;await h(l(this.options.statePath),{recursive:!0,mode:448});const t=`${this.options.statePath}.tmp`;await d(t,`${JSON.stringify(this.task,null,2)}
|
|
2
2
|
`,{mode:384}),await u(t,this.options.statePath)}}function m(n){return n.status==="scheduled"||n.status==="waiting"}export{p as MaintenanceScheduler};
|
package/dist/runtime.d.ts
CHANGED
|
@@ -77,6 +77,8 @@ export declare function defaultAgentHomes(): [string, string];
|
|
|
77
77
|
export declare function installRuntime(options: RuntimeInstallOptions): Promise<RuntimeInstallResult>;
|
|
78
78
|
export declare function prepareRuntime(options: RuntimeInstallOptions): Promise<RuntimePreparation>;
|
|
79
79
|
export declare function activateRuntime(preparation: RuntimePreparation): Promise<RuntimeInstallResult>;
|
|
80
|
+
export declare function runtimeDirectoryForConfig(configPath: string): string;
|
|
81
|
+
export declare function pruneRuntimeReleases(runtimeDir: string): Promise<void>;
|
|
80
82
|
export declare function rollbackRuntime(result: RuntimeInstallResult): Promise<void>;
|
|
81
83
|
export declare function nodeHostPackageName(platform: "linux" | "darwin", arch: "x64" | "arm64"): string;
|
|
82
84
|
export declare function nodeHostMirrorTarballUrl(platform: "linux" | "darwin", arch: "x64" | "arm64", version: string, mirrorUrl?: string): string;
|
package/dist/runtime.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createHash as
|
|
2
|
-
`),
|
|
3
|
-
`);await
|
|
1
|
+
import{createHash as fe}from"node:crypto";import{createReadStream as de,createWriteStream as me}from"node:fs";import{access as pe,cp as V,lstat as te,mkdir as R,readFile as T,readdir as we,readlink as he,rename as b,rm as v,symlink as ge,writeFile as D}from"node:fs/promises";import{homedir as ae}from"node:os";import{basename as ye,delimiter as $e,dirname as A,isAbsolute as z,join as o,relative as ve,resolve as h}from"node:path";import{Readable as Ee}from"node:stream";import{pipeline as ke}from"node:stream/promises";import{fileURLToPath as ne}from"node:url";import{normalizeOptional as Pe,resolveAgentBridgeUrls as Ne}from"@messenger-agent/shared/agent-config";import{runCommand as C}from"./exec.js";import{cliName as xe,legacyCliName as Re,runtimePackageScope as be}from"./identity.js";import{defaultBinDir as De,defaultRuntimeDir as oe,legacyCodingAgentPaths as Ce,messengerAgentPaths as Se}from"./paths.js";const F="https://registry.npmjs.org",J="@messenger-agent/client",cr=["latest","beta","alpha"];function lr(e){if(!(e==null||e==="")){if(e==="stable")return"latest";if(e==="latest"||e==="beta"||e==="alpha")return e;throw new Error(`Unknown release channel: ${String(e)} (expected latest, beta, or alpha)`)}}function B(e){return e==="stable"?"latest":e==="latest"||e==="beta"||e==="alpha"?e:void 0}function ur(e,r){const t=B(e),n=r??t;return{version:t?n??t:e,channel:n}}function fr(e){return/^\d+\.\d+\.\d+-/.test(e)}function dr(e,r){const[t]=e.split("+",1),[n]=r.split("+",1),a=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(t??""),i=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(n??"");if(!a||!i)throw new Error(`Automatic upgrades require semantic versions, received: ${e} and ${r}`);for(let c=1;c<=3;c+=1){const s=Number(a[c])-Number(i[c]);if(s!==0)return Math.sign(s)}return He(a[4],i[4])}function He(e,r){if(!e&&!r)return 0;if(!e)return 1;if(!r)return-1;const t=e.split("."),n=r.split(".");for(let a=0;a<Math.max(t.length,n.length);a+=1){const i=t[a],c=n[a];if(i===void 0)return-1;if(c===void 0)return 1;const s=/^\d+$/.test(i),l=/^\d+$/.test(c);if(s&&l){const m=Number(i)-Number(c);if(m!==0)return Math.sign(m);continue}if(s)return-1;if(l)return 1;if(i!==c)return i<c?-1:1}return 0}async function Ae(){const e=o(A(ne(import.meta.url)),"..","package.json");return JSON.parse(await T(e,"utf8")).version??"latest"}function mr(e=import.meta.url){const r=A(ne(e));return ye(r)==="src"?o(r,"..","assets","skills"):o(r,"assets","skills")}function _e(){return[process.env.CODEX_HOME??o(ae(),".codex"),process.env.CLAUDE_CONFIG_DIR??o(ae(),".claude")]}async function w(e){await v(e,{recursive:!0,force:!0})}async function Y(e,r){const t=`${r}.tmp-${process.pid}`;await w(t),await ge(e,t,"dir"),await b(t,r)}async function Z(e){try{return(await te(e)).isSymbolicLink()}catch{return!1}}async function pr(e){return Ue(await Me(e))}async function Me(e){const r=ie(e.configPath),t=e.runtimeDir??r?.runtimeDir??oe,n=e.binDir??r?.binDir??De,a=Je(e.platform??process.platform),i=Be(e.arch??process.arch),c=B(e.version),s=e.version==="current"?await Ae():c?await Ge(c,e.registryUrl):e.version,l=await We({runtimeDir:t,platform:a,arch:i,registryUrl:e.registryUrl,mirrorUrl:le(e.server,e.nodeHostMirrorUrl),artifactDirectory:e.hostArtifactDirectory}),m=s.replaceAll("/","_").replaceAll(":","_"),p=o(t,"releases"),u=o(p,m),N=o(t,"current"),x=o(u,"node_modules","@messenger-agent","client","dist","index.js"),f=o(u,"node_modules","@messenger-agent","client","package.json"),y=e.skillsSourceDir??o(u,"node_modules","@messenger-agent","client","dist","assets","skills"),g=o(n,"messenger-agent-service"),G=o(n,"coding-agent-client-service"),W=o(n,xe),I=o(n,Re);if(await R(p,{recursive:!0,mode:448}),await R(n,{recursive:!0,mode:448}),!(await O(f,s)&&(await q(l.nodeExecutable,x)).status===0)){const d=`${u}.tmp-${process.pid}`,U=o(d,"node_modules","@messenger-agent","client","dist","index.js");await w(d),await R(d,{recursive:!0,mode:448});try{if(e.clientDirectory&&await O(o(e.clientDirectory,"node_modules","@messenger-agent","client","package.json"),s))await V(e.clientDirectory,d,{recursive:!0});else{const H=o(d,".npmrc");await D(H,""),await C(l.nodeExecutable,[l.npmCli,"install","--prefix",d,"--omit=dev","--include=optional","--ignore-scripts","--no-audit","--no-fund","--registry",e.registryUrl??process.env.MESSENGER_AGENT_NPM_REGISTRY??F,"--userconfig",H,`${J}@${s}`],{env:{PATH:Le(l.nodeExecutable,e.path)},cwd:d})}if(!await O(o(d,"node_modules","@messenger-agent","client","package.json"),s))throw new Error(`Installed Messenger Agent Client does not match ${s}`);const $=await q(l.nodeExecutable,U);if($.status!==0)throw new Error(`Messenger Agent Client self-check failed: ${$.stderr||$.stdout}`);await w(u),await b(d,u)}catch($){throw await w(d),$}}const[M,L]=_e();return{releaseDir:u,currentLink:N,wrapperPath:g,legacyServiceWrapperPath:G,cliWrapperPath:W,legacyCliWrapperPath:I,version:s,configPath:e.configPath,...e.path?{path:e.path}:{},skillsSourceDir:y,agentHomes:[e.codexHome??M,e.claudeHome??L],platform:a,arch:i,hostVersion:l.manifest.version,hostReleaseDir:l.releaseDir,hostCurrentLink:l.currentLink}}async function Ue(e){const{releaseDir:r,currentLink:t,wrapperPath:n,legacyServiceWrapperPath:a,cliWrapperPath:i,legacyCliWrapperPath:c,version:s,configPath:l,path:m,skillsSourceDir:p,agentHomes:u,platform:N,arch:x,hostVersion:f,hostReleaseDir:y,hostCurrentLink:g}=e,G=[n,a,i,c],W=o(r,"node_modules","@messenger-agent","client","dist","index.js"),I=o(r,"node_modules","@messenger-agent","client","package.json");if(!await O(I,s))throw new Error(`Prepared Messenger Agent Client does not match ${s}`);const _=await Q(o(y,"manifest.json"),{version:f,platform:N,arch:x}),M=P(y,_.node),L=P(y,_.npm);if(!await S(M)||!await S(L))throw new Error(`Prepared Node Host ${f} is incomplete`);const d=await q(M,W);if(d.status!==0)throw new Error(`Prepared Messenger Agent Client self-check failed: ${d.stderr||d.stdout}`);await Ye(p,u);const U=await X(t),$=await X(g),H=await Promise.all(G.map(async k=>({path:k,content:await Te(k)})));await Z(t)||await w(t),await Z(g)||await w(g);try{await Y(y,g),await Y(r,t);const k=P(g,_.node),K=o(t,"node_modules","@messenger-agent","client","dist","index.js"),ee=["#!/bin/sh","set -eu",...m?[`export PATH=${E(m)}`]:[],`export AGENT_CONFIG_PATH=${E(l)}`,`exec ${E(k)} ${E(K)} run-service --config ${E(l)}`,""].join(`
|
|
2
|
+
`),re=["#!/bin/sh","set -eu",`export AGENT_CONFIG_PATH=${E(l)}`,`exec ${E(k)} ${E(K)} "$@"`,""].join(`
|
|
3
|
+
`);await D(n,ee,{mode:448}),await D(a,ee,{mode:448}),await D(i,re,{mode:448}),await D(c,re,{mode:448})}catch(k){throw await j(U,t),await j($,g),await ce(H),k}return{releaseDir:r,currentLink:t,wrapperPath:n,legacyServiceWrapperPath:a,cliWrapperPath:i,legacyCliWrapperPath:c,version:s,hostCurrentLink:g,previousReleaseDir:U,previousHostReleaseDir:$,previousWrappers:H}}async function q(e,r){return C(e,[r,"self-check"],{allowFailure:!0})}function ie(e){const r=Se();if(h(e)===h(r.configPath))return r;const t=Ce();return h(e)===h(t.configPath)?t:void 0}function wr(e){return ie(e)?.runtimeDir??oe}async function hr(e){await Promise.all([se(o(e,"releases"),o(e,"current")),se(o(e,"host","releases"),o(e,"host","current"))])}async function se(e,r){const t=await X(r);if(!t||A(h(t))!==h(e))return;let n;try{n=await we(e)}catch(a){if(a.code==="ENOENT")return;throw a}await Promise.all(n.map(a=>o(e,a)).filter(a=>h(a)!==h(t)).map(w))}async function gr(e){await j(e.previousReleaseDir,e.currentLink),await j(e.previousHostReleaseDir,e.hostCurrentLink),await ce(e.previousWrappers)}async function j(e,r){e?await Y(e,r):await w(r)}async function Te(e){try{return await T(e,"utf8")}catch(r){if(r.code==="ENOENT")return;throw r}}async function ce(e){await Promise.all(e.map(({path:r,content:t})=>t===void 0?w(r):D(r,t,{mode:448})))}function je(e,r){return`${be}/node-host-${e}-${r}`}function Oe(e,r,t,n=le()){return`${n.replace(/\/$/,"")}/${e}/${r}/${encodeURIComponent(t)}.tgz`}function le(e,r=process.env.MESSENGER_AGENT_NODE_HOST_MIRROR_URL){return(Pe(r)??`${Ne(e).server}/messenger/agent/node-host`).replace(/\/$/,"")}async function Ge(e,r){return(await ue(J,e,r)).version}async function We(e){const r=je(e.platform,e.arch),t=e.artifactDirectory?void 0:await Ve(r,"latest",e.registryUrl),a=(e.artifactDirectory?await Q(o(e.artifactDirectory,"manifest.json"),{platform:e.platform,arch:e.arch}):void 0)?.version??t?.version;if(!a)throw new Error(`Unable to resolve ${r}`);const i=o(e.runtimeDir,"host"),c=o(i,"releases"),s=`${a}-${e.platform}-${e.arch}`.replaceAll("/","_").replaceAll(":","_"),l=o(c,s),m=o(i,"current"),p=o(l,"manifest.json");if(await R(c,{recursive:!0,mode:448}),!await S(p)){const f=`${l}.tmp-${process.pid}`;await w(f),await R(f,{recursive:!0,mode:448});try{e.artifactDirectory?await V(e.artifactDirectory,f,{recursive:!0}):t&&await Ie(t,f,Oe(e.platform,e.arch,t.version,e.mirrorUrl)),await w(l),await b(f,l)}catch(y){throw await w(f),y}}const u=await Q(p,{version:a,platform:e.platform,arch:e.arch});await Fe(l,u);const N=P(l,u.node),x=P(l,u.npm);if(!await S(N)||!await S(x))throw new Error(`Node Host ${r}@${a} is incomplete`);if(u.platform==="darwin"){const f=o(l,"Messenger Agent.app");await C("codesign",["--verify","--deep","--strict",f]),await C("spctl",["--assess","--type","execute",f])}return{releaseDir:l,currentLink:m,nodeExecutable:N,npmCli:x,manifest:u}}async function Ie(e,r,t){const n=`${r}.tgz`;try{const a=[];let i=!1;for(const c of new Set([t,e.tarball]))try{await v(n,{force:!0});const s=await fetch(c);if(!s.ok||!s.body)throw new Error(`HTTP ${s.status}`);await ke(Ee.fromWeb(s.body),me(n,{mode:384})),await ze(n,e.integrity),i=!0;break}catch(s){a.push(`${c}: ${s instanceof Error?s.message:String(s)}`)}if(!i)throw new Error(`Unable to download ${e.packageName}@${e.version}: ${a.join("; ")}`);await C("tar",["-xzf",n,"-C",r,"--strip-components=2","package/host"])}finally{await v(n,{force:!0})}}async function O(e,r){try{const t=JSON.parse(await T(e,"utf8"));return t.name===J&&t.version===r}catch{return!1}}function Le(e,r=process.env.PATH){const t=A(e);return r?`${t}${$e}${r}`:t}async function Ve(e,r,t=process.env.MESSENGER_AGENT_NPM_REGISTRY??F){const{metadata:n,version:a}=await ue(e,r,t),i=n.versions?.[a]?.dist;if(!i?.tarball||!i.integrity)throw new Error(`Registry returned incomplete artifact metadata for ${e}@${a}`);return{packageName:e,version:a,tarball:i.tarball,integrity:i.integrity}}async function ue(e,r,t=process.env.MESSENGER_AGENT_NPM_REGISTRY??F){const n=`${t.replace(/\/$/,"")}/${encodeURIComponent(e)}`,a=await fetch(n,{headers:{accept:"application/json"}});if(!a.ok)throw new Error(`Unable to resolve ${e}: HTTP ${a.status}`);const i=await a.json(),c=B(r)?i["dist-tags"]?.[r]:r;if(!c)throw new Error(`Registry has no ${r} release for ${e}`);return{metadata:i,version:c}}async function ze(e,r){const t=r.indexOf("-");if(t<=0)throw new Error("Node Host has an invalid integrity value");const n=r.slice(0,t),a=r.slice(t+1),i=fe(n);for await(const c of de(e))i.update(c);if(i.digest("base64")!==a)throw new Error("Node Host integrity verification failed")}async function Q(e,r){const t=JSON.parse(await T(e,"utf8"));if(t.schemaVersion!==1||t.product!=="messenger-agent-node-host"||r.version!==void 0&&t.version!==r.version||typeof t.version!="string"||typeof t.nodeVersion!="string"||t.platform!==r.platform||t.arch!==r.arch||typeof t.node!="string"||typeof t.npm!="string"||t.payload!==void 0&&typeof t.payload!="string")throw new Error(`Node Host manifest does not match ${r.platform}-${r.arch}${r.version?`@${r.version}`:""}`);return t}async function Fe(e,r){if(!r.payload)return;const t=P(e,r.node);if(await S(t))return;if(r.platform!=="darwin")throw new Error("Only macOS Node Hosts may contain a zip payload");const n=P(e,r.payload);await C("ditto",["-x","-k",n,e])}function P(e,r){if(!r||z(r))throw new Error(`Node Host contains an unsafe path: ${r}`);const t=h(e),n=h(e,r),a=ve(t,n);if(a.startsWith("..")||z(a))throw new Error(`Node Host contains an unsafe path: ${r}`);return n}function Je(e){if(e==="linux"||e==="darwin")return e;throw new Error(`No Messenger Agent runtime is available for platform: ${e}`)}function Be(e){if(e==="x64"||e==="arm64")return e;throw new Error(`No Messenger Agent runtime is available for architecture: ${e}`)}async function X(e){if(!await Z(e))return;const r=await he(e);return z(r)?r:h(A(e),r)}async function S(e){try{return await pe(e),!0}catch{return!1}}async function Ye(e,r){const t="manage-messenger-agent",n="manage-coding-agent-client",a=o(e,t),i=await Ze(a);for(const c of new Set(r)){const s=o(c,"skills"),l=o(s,t),m=o(s,`.${t}.tmp-${process.pid}`),p=o(s,`.${t}.old-${process.pid}`);if(await v(m,{recursive:!0,force:!0}),await v(p,{recursive:!0,force:!0}),await v(o(s,n),{recursive:!0,force:!0}),!i){await v(l,{recursive:!0,force:!0});continue}await R(s,{recursive:!0,mode:448}),await V(a,m,{recursive:!0}),await b(l,p).catch(u=>{if(u.code!=="ENOENT")throw u});try{await b(m,l),await v(p,{recursive:!0,force:!0})}catch(u){throw await b(p,l).catch(()=>{}),u}}}async function Ze(e){try{return(await te(e)).isDirectory()}catch(r){if(r.code==="ENOENT")return!1;throw r}}function E(e){return`'${e.replaceAll("'","'\\''")}'`}export{Ue as activateRuntime,dr as compareSemverVersions,mr as currentBundledSkillsDir,Ae as currentPackageVersion,_e as defaultAgentHomes,pr as installRuntime,fr as isPrereleaseVersion,Oe as nodeHostMirrorTarballUrl,je as nodeHostPackageName,lr as normalizeReleaseChannel,ur as normalizeUpgradeVersion,B as parseReleaseChannel,Me as prepareRuntime,hr as pruneRuntimeReleases,cr as releaseChannels,Ge as resolveChannelPackageVersion,le as resolveNodeHostMirrorUrl,gr as rollbackRuntime,wr as runtimeDirectoryForConfig,Ye as syncBundledSkills};
|
package/dist/supervisor.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawn as
|
|
1
|
+
import{spawn as $}from"node:child_process";import{randomUUID as k}from"node:crypto";import{createRequire as x}from"node:module";import{dirname as h,join as m,resolve as f}from"node:path";import{parse as C}from"yaml";import{readFile as R,unlink as P}from"node:fs/promises";import{readAgentServer as y,readClientPath as v,readUpgradeChannel as b,writeClientPath as I}from"./config-file.js";import{readControlSocketPath as L,startControlServer as N}from"./control.js";import{MaintenanceScheduler as q}from"./maintenance.js";import{activateRuntime as O,currentBundledSkillsDir as F,currentPackageVersion as _,defaultAgentHomes as D,installRuntime as T,prepareRuntime as U,pruneRuntimeReleases as j,rollbackRuntime as S,runtimeDirectoryForConfig as G,syncBundledSkills as W}from"./runtime.js";import{launchdLabel as B,serviceCommandsForConfig as H,serviceName as K,systemdUserEnvironment as M}from"./service.js";import{legacyLaunchdLabel as Y,legacyServiceName as V}from"./identity.js";import{legacyCodingAgentPaths as E}from"./paths.js";import{runCommand as p}from"./exec.js";import{AutoUpgradeScheduler as X}from"./auto-upgrade.js";import{migrateLegacyClient as z}from"./migration.js";import{scheduleMigrationHandoff as J,shouldAttemptAutomaticMigration as Q}from"./install.js";import{isAgentActivityResponse as Z}from"@messenger-agent/shared/agent-activity";import{isAgentWorkspacesReloadResponse as ee}from"@messenger-agent/shared/agent-workspaces";const A=x(import.meta.url);function te(){return[{name:"codex",entry:A.resolve("@messenger-agent/codex-agent")},{name:"claude",entry:A.resolve("@messenger-agent/claude-agent")},{name:"workspace",entry:A.resolve("@messenger-agent/messenger-agent")}]}function re(r,e){let t=r;for(const s of e){if(!t||typeof t!="object"||Array.isArray(t))return;t=t[s]}return t}async function se(r){const e=C(await R(r,"utf8")),t=re(e,["workspaces"]);if(Array.isArray(t)){const s=t.find(i=>!!i&&typeof i=="object"&&!Array.isArray(i)&&typeof i.path=="string");if(typeof s?.path=="string"&&s.path.trim())return s.path}return h(r)}class ae{options;stopping=!1;running;restartBaseMs;restartMaxMs;workspaceReloadTimeoutMs;constructor(e){this.options=e,this.running=(e.agents??te()).map(t=>({definition:t,restartAttempts:0})),this.restartBaseMs=e.restartBaseMs??1e3,this.restartMaxMs=e.restartMaxMs??3e4,this.workspaceReloadTimeoutMs=e.workspaceReloadTimeoutMs??5e3}start(){for(const e of this.running)this.startAgent(e)}async stop(){this.stopping=!0;for(const e of this.running)e.restartTimer&&clearTimeout(e.restartTimer),e.process?.kill("SIGTERM");await Promise.all(this.running.map(e=>e.process).filter(e=>!!e&&e.exitCode===null&&!e.killed).map(e=>new Promise(t=>{const s=setTimeout(()=>{e.kill("SIGKILL"),t()},8e3);e.once("exit",()=>{clearTimeout(s),t()})})))}restartAgent(e){const t=this.running.find(({definition:s})=>s.name===e);return t?(t.restartPromise||(t.restartPromise=this.restartAgentProcess(t).finally(()=>{t.restartPromise=void 0})),t.restartPromise):Promise.reject(new Error(`Agent is not managed by this client: ${e}`))}async activityStatus(e=1e3){const[t,s]=await Promise.all([this.agentActivityStatus("codex",e),this.agentActivityStatus("claude",e)]),i=[t,s].filter(a=>a.available);return{active:i.reduce((a,n)=>a+n.active,0),waiting:i.reduce((a,n)=>a+n.waiting,0),agents:{codex:t,claude:s}}}agentActivityStatus(e,t){const s=this.running.find(({definition:i})=>i.name===e)?.process;return!s||!s.connected||!s.send?Promise.resolve({available:!1,error:`${e} agent is not connected`}):new Promise(i=>{const a=k(),n={type:"client.activity.request",requestId:a};let c=!1;const u=o=>{c||(c=!0,clearTimeout(d),s.off("message",l),i(o))},l=o=>{!Z(o)||o.requestId!==a||o.agent!==e||u({available:!0,...o.snapshot})},d=setTimeout(()=>u({available:!1,error:`${e} agent did not respond`}),t);s.on("message",l),s.send(n,o=>{o&&u({available:!1,error:o.message})})})}async restartAgentProcess(e){e.restartTimer&&(clearTimeout(e.restartTimer),e.restartTimer=void 0);const t=e.process;if(t&&t.exitCode===null&&!t.killed&&(t.kill("SIGTERM"),await ce(t)),this.stopping)throw new Error("Client service is stopping");e.restartAttempts=0,this.startAgent(e)}async reloadAgentWorkspaces(){await Promise.all([this.requestAgentWorkspacesReload("codex"),this.requestAgentWorkspacesReload("claude")])}requestAgentWorkspacesReload(e){const t=this.running.find(({definition:s})=>s.name===e)?.process;return!t||!t.connected||!t.send?Promise.reject(new Error(`${e} agent is not connected`)):new Promise((s,i)=>{const a=k(),n={type:"client.workspaces.reload.request",requestId:a};let c=!1;const u=o=>{c||(c=!0,clearTimeout(d),t.off("message",l),o?i(o):s())},l=o=>{if(!(!ee(o)||o.requestId!==a||o.agent!==e)){if(!o.success){u(new Error(`${e} agent failed to reload workspaces: ${o.error??"unknown error"}`));return}console.log(`[client] reloaded ${e}-agent workspaces count=${o.workspaceCount??0}`),u()}},d=setTimeout(()=>u(new Error(`${e} agent did not reload workspaces`)),this.workspaceReloadTimeoutMs);t.on("message",l),t.send(n,o=>{o&&u(o)})})}startAgent(e){const t={...process.env,AGENT_CONFIG_PATH:this.options.configPath};e.definition.name==="workspace"&&(delete t.OPENAI_API_KEY,delete t.CODEX_API_KEY,delete t.ANTHROPIC_API_KEY,delete t.ANTHROPIC_AUTH_TOKEN);const s=(this.options.spawnProcess??$)(process.execPath,[e.definition.entry],{cwd:this.options.workspacePath,env:t,stdio:["inherit","inherit","inherit","ipc"]});e.process=s,e.definition.name==="workspace"&&s.on("message",i=>{i&&typeof i=="object"&&"type"in i&&i.type==="client.workspaces.changed"&&this.reloadAgentWorkspaces().catch(a=>{console.error("[client] failed to reload agents after workspace configuration changed",a)})}),console.log(`[client] started ${e.definition.name}-agent pid=${s.pid}`),s.once("exit",(i,a)=>{if(e.process=void 0,this.stopping||e.restartPromise)return;const n=Math.min(this.restartBaseMs*2**e.restartAttempts,this.restartMaxMs);e.restartAttempts+=1,console.error(`[client] ${e.definition.name}-agent exited with code=${i??"null"} signal=${a??"null"}; restarting in ${n}ms`),e.restartTimer=setTimeout(()=>{e.restartTimer=void 0,this.startAgent(e)},n)})}}async function xe(r){if(await ie(r))return;await W(F(),D());const e=await se(r),t=new ae({configPath:r,workspacePath:e}),s=await L(r),i=new q({statePath:m(h(s),"maintenance.json"),getActivity:()=>t.activityStatus(),execute:(l,d)=>ne(l,r,t,d)}),a=await i.start();a?.status==="restarting"&&a.operation.type==="upgrade"&&await j(G(r)).catch(l=>{console.error(`[client] failed to remove old runtime releases: ${String(l)}`)});const n=new X({statePath:m(h(s),"auto-upgrade.json"),maintenance:i,getChannel:()=>b(r),prepareUpgrade:async l=>U({version:l,configPath:r,server:await y(r),path:await v(r)})});await n.start();const c=await N(s,{restartAgent:l=>t.restartAgent(l),getActivity:()=>t.activityStatus(),maintenance:i});t.start();const u=async()=>{n.stop(),i.stop(),await c.close(),await t.stop(),process.exit(0)};process.once("SIGINT",()=>{u()}),process.once("SIGTERM",()=>{u()})}async function ie(r,e={}){const t=E();if(f(r)!==f(t.configPath))return!1;const s=await(e.currentVersion??_)();if(!await(e.shouldAttempt??Q)(t.rootDir,s))return!1;let i;try{const a=await(e.migrate??z)();if(!a.migrated)return!1;const n=await(e.readPath??v)(a.paths.configPath),c=await(e.readServer??y)(a.paths.configPath);return i=await(e.install??T)({version:s,configPath:a.paths.configPath,runtimeDir:a.paths.runtimeDir,binDir:a.paths.binDir,path:n,server:c}),await(e.handoff??J)(a,i,a.paths.configPath,n),!0}catch(a){return i&&await(e.rollback??S)(i).catch(()=>{}),console.error(`[client] automatic legacy migration failed: ${a instanceof Error?a.message:String(a)}`),!1}}async function ne(r,e,t,s){if(r.type==="upgrade"){if(r.path&&await I(e,r.path),r.prepared&&r.prepared.version!==r.version)throw new Error(`Prepared runtime ${r.prepared.version} does not match upgrade ${r.version}`);if(r.prepared&&f(r.prepared.configPath)!==f(e))throw new Error("Prepared runtime does not match the active client configuration");const i=r.prepared?await O(r.prepared):await T({version:r.version,configPath:e,server:await y(e),path:r.path??await v(e)});await s("restarting");try{await g(w(e).restart)}catch(a){throw await S(i),await g(w(e).restart).catch(()=>{}),a}return}if(r.type==="restart"&&r.agent){await t.restartAgent(r.agent);return}if(r.type==="restart"){await s("restarting"),await g(w(e).restart);return}if(r.type==="stop"){await s("stopping"),await g(w(e).stop);return}await s("stopping"),await oe(e)}function w(r){return H(r)}async function g(r){const e=process.getuid?.(),t=await p("/bin/sh",["-lc",r],{allowFailure:!0,env:process.platform==="linux"&&e!==void 0?M(e):void 0});if(t.status!==0)throw new Error(t.stderr||t.stdout||`Service command failed: ${r}`)}async function oe(r){const e=process.env.HOME??"",t=r===E().configPath,s=t?V:K,i=t?Y:B;if(process.platform==="linux"){const a=process.getuid?.(),n=a===void 0?void 0:M(a);await p("systemctl",["--user","disable",`${s}.service`],{allowFailure:!0,env:n}),await P(m(e,".config","systemd","user",`${s}.service`)).catch(c=>{if(c.code!=="ENOENT")throw c}),await p("systemctl",["--user","daemon-reload"],{allowFailure:!0,env:n}),await p("systemctl",["--user","stop",`${s}.service`],{allowFailure:!0,env:n});return}if(process.platform==="darwin"){const a=process.getuid?.();if(a===void 0)throw new Error("Unable to determine current uid for launchctl");const n=m(e,"Library","LaunchAgents",`${i}.plist`);await P(n).catch(c=>{if(c.code!=="ENOENT")throw c}),await p("launchctl",["bootout",`gui/${a}/${i}`],{allowFailure:!0});return}throw new Error("Only Linux and macOS are supported")}function ce(r){return new Promise(e=>{const t=setTimeout(()=>{r.kill("SIGKILL")},8e3);r.once("exit",()=>{clearTimeout(t),e()})})}export{ae as AgentSupervisor,ie as migrateLegacyServiceAtStartup,se as readWorkspacePathFromConfig,te as resolveAgentEntries,xe as runSupervisor};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@messenger-agent/client",
|
|
3
|
-
"version": "0.38.0-alpha.
|
|
3
|
+
"version": "0.38.0-alpha.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"cac": "^7.0.0",
|
|
23
23
|
"yaml": "^2.9.0",
|
|
24
|
-
"@messenger-agent/claude-agent": "0.38.0-alpha.
|
|
25
|
-
"@messenger-agent/codex-agent": "0.38.0-alpha.
|
|
26
|
-
"@messenger-agent/
|
|
27
|
-
"@messenger-agent/
|
|
24
|
+
"@messenger-agent/claude-agent": "0.38.0-alpha.4",
|
|
25
|
+
"@messenger-agent/codex-agent": "0.38.0-alpha.4",
|
|
26
|
+
"@messenger-agent/shared": "0.38.0-alpha.4",
|
|
27
|
+
"@messenger-agent/messenger-agent": "0.38.0-alpha.4"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "rm -rf dist && tsc -p tsconfig.json && node ../../scripts/copy-client-assets.mjs && chmod +x dist/index.js",
|