@messenger-agent/client 0.33.0-alpha.7 → 0.33.0-alpha.8
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/install.d.ts +7 -0
- package/dist/install.js +2 -2
- package/dist/supervisor.d.ts +13 -0
- package/dist/supervisor.js +1 -1
- package/package.json +5 -5
package/dist/install.d.ts
CHANGED
|
@@ -16,6 +16,13 @@ export declare function scheduleDarwinMigrationHandoff(migration: ClientMigratio
|
|
|
16
16
|
wait?: (milliseconds: number) => Promise<unknown>;
|
|
17
17
|
attempts?: number;
|
|
18
18
|
}): Promise<boolean>;
|
|
19
|
+
export declare function scheduleMigrationHandoff(migration: ClientMigrationResult, runtime: RuntimeInstallResult, configPath: string, path?: string, dependencies?: {
|
|
20
|
+
run?: typeof runCommand;
|
|
21
|
+
wait?: (milliseconds: number) => Promise<unknown>;
|
|
22
|
+
attempts?: number;
|
|
23
|
+
platform?: NodeJS.Platform;
|
|
24
|
+
}): Promise<boolean>;
|
|
25
|
+
export declare function shouldAttemptAutomaticMigration(rootDir: string, version: string): Promise<boolean>;
|
|
19
26
|
export declare function completeMigrationHandoff(handoffPath: string): Promise<void>;
|
|
20
27
|
type ResolvedInstallArgs = Omit<InstallArgs, "tunnelId" | "token" | "workspace" | "workspaceId" | "workspaceName"> & {
|
|
21
28
|
tunnelId: string;
|
package/dist/install.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{randomUUID as
|
|
2
|
-
`,{mode:384}),await
|
|
1
|
+
import{randomUUID as N}from"node:crypto";import{mkdir as x,readFile as T,realpath as $,rename as O,stat as _,writeFile as L}from"node:fs/promises";import{join as y}from"node:path";import{setTimeout as C}from"node:timers/promises";import{normalizeAgentServer as H}from"@messenger-agent/shared/agent-config";import{readConfigYaml as v,updateClientConfig as j,writeUpgradeChannel as R}from"./config-file.js";import{installRuntime as W,rollbackRuntime as g}from"./runtime.js";import{installService as k,startLegacyService as P,stopLegacyService as A,uninstallLegacyService as S,uninstallService as D}from"./service.js";import{UsageError as w}from"./args.js";import{defaultWorkspacePath as E,legacyCodingAgentPaths as U,messengerAgentPaths as G}from"./paths.js";import{runCommand as q}from"./exec.js";import{completeLegacyMigration as I,migrateLegacyClient as z,rollbackLegacyMigration as F}from"./migration.js";const V="vip.elevo.messenger.agent.migration";async function lt(t,e,r,i){if(!t.migrated)return!1;if(process.platform==="darwin")return B(t,e,r,i);try{return await b(t,e,r,i),!0}catch(n){throw await g(e).catch(()=>{}),await M(t),n}}async function b(t,e,r,i){const n=await v(r),o=m(n,"data_dir")??t.paths.dataDir,s=Array.isArray(n.workspaces)?n.workspaces.find(c=>!!c&&typeof c=="object"&&!Array.isArray(c)&&typeof c.path=="string"):void 0,a=m(s,"path");if(!a)throw new Error("Migrated config does not contain a workspace path");await A(),await k({configPath:r,dataDir:o,workspacePath:a,serviceCommandPath:e.wrapperPath,path:i}),await S(),await I(t)}async function B(t,e,r,i,n={}){return J(t,e,r,i,{...n,platform:"darwin"})}async function J(t,e,r,i,n={}){const o=n.run??q,s=n.wait??C,a=n.attempts??1200,c=n.platform??process.platform;if(c!=="darwin"&&c!=="linux")throw new Error("Only Linux and macOS are supported");const d=y(t.paths.rootDir,"migration-handoff.json"),u=c==="darwin"?`${V}.${process.pid}`:`messenger-agent-migration-${process.pid}`;await p(d,{schemaVersion:1,status:"scheduled",helperLabel:u,migration:t,runtime:e,configPath:r,...i?{path:i}:{},updatedAt:new Date().toISOString()});try{c==="darwin"?await o("launchctl",["submit","-l",u,"--",e.cliWrapperPath,"complete-migration","--handoff",d]):await o("systemd-run",["--user","--quiet","--collect","--unit",u,"--",e.cliWrapperPath,"complete-migration","--handoff",d])}catch(f){throw await p(d,{...await l(d),status:"failed",message:f instanceof Error?f.message:String(f),updatedAt:new Date().toISOString()}),f}for(let f=0;f<a;f+=1){const h=await l(d);if(h.status==="completed")return c==="darwin"&&await o("launchctl",["remove",u],{allowFailure:!0}),!0;if(h.status==="failed")throw new Error(h.message??"Service migration failed");await s(100)}throw new Error(`Timed out waiting for service migration; inspect ${d}`)}async function mt(t,e){try{const r=await l(y(t,"migration-handoff.json"));return r.status!=="completed"&&r.runtime.version!==e}catch(r){if(r.code==="ENOENT")return!0;throw r}}async function ht(t){const e=await l(t);await p(t,{...e,status:"running",updatedAt:new Date().toISOString()});try{await b(e.migration,e.runtime,e.configPath,e.path),await p(t,{...e,status:"completed",updatedAt:new Date().toISOString()})}catch(r){const i=[];await g(e.runtime).catch(o=>{i.push(`runtime rollback failed: ${String(o)}`)}),await D().catch(o=>{i.push(`new service cleanup failed: ${String(o)}`)}),await P().catch(o=>{i.push(`legacy service restart failed: ${String(o)}`)});const n=[r instanceof Error?r.message:String(r),...i].join("; ");throw await p(t,{...e,status:"failed",message:n,updatedAt:new Date().toISOString()}),r}}async function l(t){const e=JSON.parse(await T(t,"utf8"));if(e.schemaVersion!==1||!e.migration||!e.runtime||typeof e.configPath!="string"||typeof e.helperLabel!="string"||e.status!=="scheduled"&&e.status!=="running"&&e.status!=="completed"&&e.status!=="failed")throw new Error(`Invalid Messenger Agent migration handoff: ${t}`);return e}async function p(t,e){const r=`${t}.${process.pid}.tmp`;await L(r,`${JSON.stringify(e,null,2)}
|
|
2
|
+
`,{mode:384}),await O(r,t)}function Z(t=process.platform){if(t!=="linux"&&t!=="darwin")throw new Error("Only Linux and macOS are supported")}function Y(t=process.versions.node){const e=/^(\d+)\.(\d+)\.(\d+)(?:[.-]|$)/.exec(t),r=Number(e?.[1]),i=Number(e?.[2]);if(!(r>22||r===22&&i>=19))throw new Error("Node.js 22.19.0 or newer is required")}function K(t){if(t.server)try{H(t.server)}catch{throw new Error("--server must be a valid HTTP or HTTPS server address")}if(t.tunnelId&&!/^[A-Za-z0-9._:-]+$/.test(t.tunnelId))throw new Error("--tunnel-id may only contain letters, numbers, '.', '_', ':', and '-'");if(t.workspaceId&&!/^[A-Za-z0-9._:-]+$/.test(t.workspaceId))throw new Error("--workspace-id may only contain letters, numbers, '.', '_', ':', and '-'");if(t.workspaceName&&(t.workspaceName.trim().length===0||t.workspaceName.trim().length>128))throw new Error("--workspace-name must be between 1 and 128 characters")}async function Q(t,e=!1){e&&await x(t,{recursive:!0});const r=await $(t);if(!(await _(r)).isDirectory())throw new Error("--workspace must point to an existing directory");return r}async function gt(t){Z(),Y();const e=G(),r=U(),n=t.configPath===e.configPath||t.configPath===r.configPath?await z():void 0;let o;try{const s=n?{...t,configPath:t.configPath===n.legacyPaths.configPath?n.paths.configPath:t.configPath,dataDir:t.dataDir===n.legacyPaths.dataDir?n.paths.dataDir:t.dataDir}:t,a=await X(s);K(a);const c=await Q(a.workspace,a.createWorkspace);await j({configPath:a.configPath,dataDir:a.dataDir,workspacePath:c,workspaceId:a.workspaceId,workspaceName:a.workspaceName,tunnelId:a.tunnelId,token:a.token,server:a.server,serverUrl:a.serverUrl,preserveWorkspaces:a.preserveWorkspaces,path:process.env.PATH}),t.channel&&await R(a.configPath,t.channel),o=await W({version:"current",configPath:a.configPath,runtimeDir:n?.paths.runtimeDir,binDir:n?.paths.binDir,path:process.env.PATH,hostArtifactDirectory:process.env.MESSENGER_AGENT_BOOTSTRAP_HOST_DIR,clientDirectory:process.env.MESSENGER_AGENT_BOOTSTRAP_CLIENT_DIR}),n?.migrated&&await A();const d=await k({configPath:a.configPath,dataDir:a.dataDir,workspacePath:c,serviceCommandPath:o.wrapperPath,path:process.env.PATH});return n?.migrated&&(await S(),await I(n)),{configPath:a.configPath,dataDir:a.dataDir,workspacePath:c,runtime:o,service:d}}catch(s){throw o&&await g(o).catch(()=>{}),n?.migrated&&await M(n),s}}async function M(t){await D().catch(()=>{}),await F(t),await P().catch(()=>{})}async function X(t){const e=await v(t.configPath),r=et(e,"tunnel"),i=t.tunnelId??m(r,"tunnel_id"),n=t.token??m(r,"token"),o=tt(e,t.workspaceId,i),s=t.workspace??o?.path??E,a=t.workspaceId??o?.id??N(),c=t.workspaceName??o?.name??(i?`${i} Default`:void 0),d=s===E;if(!i)throw new w("Missing required option: --tunnel-id");if(!n)throw new w("Missing required option: --token");if(!a)throw new w("Missing required option: --workspace-id");if(!c)throw new w("Missing required option: --workspace-name");return{...t,tunnelId:i,token:n,workspace:s,workspaceId:a,workspaceName:c,preserveWorkspaces:!t.workspace&&!!o,createWorkspace:d}}function tt(t,e,r){const i=t.workspaces;if(!Array.isArray(i))return;const n=i.filter(a=>!!a&&typeof a=="object"&&!Array.isArray(a)&&typeof a.path=="string");if(e){const a=n.find(c=>c.id===e);return!a||typeof a.path!="string"?void 0:{id:e,name:typeof a.name=="string"&&a.name?a.name:`${r??e} Default`,path:a.path}}const o=e??(r?`${r}--default`:void 0),s=(o?n.find(a=>a.id===o):void 0)??n.find(a=>a.id==="default")??n[0];if(!(!s||typeof s.path!="string"))return{id:typeof s.id=="string"&&s.id?s.id:o??"default",name:typeof s.name=="string"&&s.name?s.name:`${r??o??"default"} Default`,path:s.path}}function et(t,e){const r=t[e];if(!(!r||typeof r!="object"||Array.isArray(r)))return r}function m(t,e){const r=t?.[e];return typeof r=="string"&&r?r:void 0}export{lt as activateMigratedService,Y as assertNodeVersion,Z as assertSupportedPlatform,ht as completeMigrationHandoff,gt as installClient,X as resolveInstallArgs,Q as resolveWorkspacePath,B as scheduleDarwinMigrationHandoff,J as scheduleMigrationHandoff,mt as shouldAttemptAutomaticMigration,K as validateInstallArgs};
|
package/dist/supervisor.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { readClientPath } from "./config-file.js";
|
|
3
|
+
import { currentPackageVersion, installRuntime, rollbackRuntime } from "./runtime.js";
|
|
4
|
+
import { migrateLegacyClient } from "./migration.js";
|
|
5
|
+
import { scheduleMigrationHandoff, shouldAttemptAutomaticMigration } from "./install.js";
|
|
2
6
|
import { type AgentActivitySnapshot, type ManagedAgentName } from "@messenger-agent/shared/agent-activity";
|
|
3
7
|
export type { ManagedAgentName } from "@messenger-agent/shared/agent-activity";
|
|
4
8
|
export type AgentActivityStatus = ({
|
|
@@ -43,3 +47,12 @@ export declare class AgentSupervisor {
|
|
|
43
47
|
private startAgent;
|
|
44
48
|
}
|
|
45
49
|
export declare function runSupervisor(configPath: string): Promise<void>;
|
|
50
|
+
export declare function migrateLegacyServiceAtStartup(configPath: string, dependencies?: {
|
|
51
|
+
currentVersion?: typeof currentPackageVersion;
|
|
52
|
+
shouldAttempt?: typeof shouldAttemptAutomaticMigration;
|
|
53
|
+
migrate?: typeof migrateLegacyClient;
|
|
54
|
+
install?: typeof installRuntime;
|
|
55
|
+
handoff?: typeof scheduleMigrationHandoff;
|
|
56
|
+
rollback?: typeof rollbackRuntime;
|
|
57
|
+
readPath?: typeof readClientPath;
|
|
58
|
+
}): Promise<boolean>;
|
package/dist/supervisor.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawn as
|
|
1
|
+
import{spawn as x}from"node:child_process";import{randomUUID as b}from"node:crypto";import{createRequire as M}from"node:module";import{dirname as h,join as f,resolve as w}from"node:path";import{parse as k}from"yaml";import{readFile as C,unlink as y}from"node:fs/promises";import{readClientPath as v,readUpgradeChannel as E,writeClientPath as I}from"./config-file.js";import{readControlSocketPath as $,startControlServer as L}from"./control.js";import{MaintenanceScheduler as N}from"./maintenance.js";import{currentBundledSkillsDir as F,currentPackageVersion as O,defaultAgentHomes as R,installRuntime as A,rollbackRuntime as P,syncBundledSkills as D}from"./runtime.js";import{launchdLabel as G,serviceCommandsForConfig as _,serviceName as j}from"./service.js";import{legacyLaunchdLabel as B,legacyServiceName as q}from"./identity.js";import{legacyCodingAgentPaths as S}from"./paths.js";import{runCommand as u}from"./exec.js";import{AutoUpgradeScheduler as U}from"./auto-upgrade.js";import{migrateLegacyClient as H}from"./migration.js";import{scheduleMigrationHandoff as K,shouldAttemptAutomaticMigration as Y}from"./install.js";import{isAgentActivityResponse as V}from"@messenger-agent/shared/agent-activity";const g=M(import.meta.url);function W(){return[{name:"codex",entry:g.resolve("@messenger-agent/codex-agent")},{name:"claude",entry:g.resolve("@messenger-agent/claude-agent")},{name:"workspace",entry:g.resolve("@messenger-agent/messenger-agent")}]}function X(a,t){let e=a;for(const r of t){if(!e||typeof e!="object"||Array.isArray(e))return;e=e[r]}return e}async function z(a){const t=k(await C(a,"utf8")),e=X(t,["workspaces"]);if(Array.isArray(e)){const r=e.find(s=>!!s&&typeof s=="object"&&!Array.isArray(s)&&typeof s.path=="string");if(typeof r?.path=="string"&&r.path.trim())return r.path}return h(a)}class J{options;stopping=!1;running;restartBaseMs;restartMaxMs;constructor(t){this.options=t,this.running=(t.agents??W()).map(e=>({definition:e,restartAttempts:0})),this.restartBaseMs=t.restartBaseMs??1e3,this.restartMaxMs=t.restartMaxMs??3e4}start(){for(const t of this.running)this.startAgent(t)}async stop(){this.stopping=!0;for(const t of this.running)t.restartTimer&&clearTimeout(t.restartTimer),t.process?.kill("SIGTERM");await Promise.all(this.running.map(t=>t.process).filter(t=>!!t&&t.exitCode===null&&!t.killed).map(t=>new Promise(e=>{const r=setTimeout(()=>{t.kill("SIGKILL"),e()},8e3);t.once("exit",()=>{clearTimeout(r),e()})})))}restartAgent(t){const e=this.running.find(({definition:r})=>r.name===t);return e?(e.restartPromise||(e.restartPromise=this.restartAgentProcess(e).finally(()=>{e.restartPromise=void 0})),e.restartPromise):Promise.reject(new Error(`Agent is not managed by this client: ${t}`))}async activityStatus(t=1e3){const[e,r]=await Promise.all([this.agentActivityStatus("codex",t),this.agentActivityStatus("claude",t)]),s=[e,r].filter(i=>i.available);return{active:s.reduce((i,n)=>i+n.active,0),waiting:s.reduce((i,n)=>i+n.waiting,0),agents:{codex:e,claude:r}}}agentActivityStatus(t,e){const r=this.running.find(({definition:s})=>s.name===t)?.process;return!r||!r.connected||!r.send?Promise.resolve({available:!1,error:`${t} agent is not connected`}):new Promise(s=>{const i=b(),n={type:"client.activity.request",requestId:i};let c=!1;const l=o=>{c||(c=!0,clearTimeout(T),r.off("message",m),s(o))},m=o=>{!V(o)||o.requestId!==i||o.agent!==t||l({available:!0,...o.snapshot})},T=setTimeout(()=>l({available:!1,error:`${t} agent did not respond`}),e);r.on("message",m),r.send(n,o=>{o&&l({available:!1,error:o.message})})})}async restartAgentProcess(t){t.restartTimer&&(clearTimeout(t.restartTimer),t.restartTimer=void 0);const e=t.process;if(e&&e.exitCode===null&&!e.killed&&(e.kill("SIGTERM"),await et(e)),this.stopping)throw new Error("Client service is stopping");t.restartAttempts=0,this.startAgent(t)}startAgent(t){const e={...process.env,AGENT_CONFIG_PATH:this.options.configPath};t.definition.name==="workspace"&&(delete e.OPENAI_API_KEY,delete e.CODEX_API_KEY,delete e.ANTHROPIC_API_KEY);const r=(this.options.spawnProcess??x)(process.execPath,[t.definition.entry],{cwd:this.options.workspacePath,env:e,stdio:["inherit","inherit","inherit","ipc"]});t.process=r,t.definition.name==="workspace"&&r.on("message",s=>{s&&typeof s=="object"&&"type"in s&&s.type==="client.workspaces.changed"&&Promise.all([this.restartAgent("codex"),this.restartAgent("claude")]).catch(i=>{console.error("[client] failed to reload agents after workspace configuration changed",i)})}),console.log(`[client] started ${t.definition.name}-agent pid=${r.pid}`),r.once("exit",(s,i)=>{if(t.process=void 0,this.stopping||t.restartPromise)return;const n=Math.min(this.restartBaseMs*2**t.restartAttempts,this.restartMaxMs);t.restartAttempts+=1,console.error(`[client] ${t.definition.name}-agent exited with code=${s??"null"} signal=${i??"null"}; restarting in ${n}ms`),t.restartTimer=setTimeout(()=>{t.restartTimer=void 0,this.startAgent(t)},n)})}}async function At(a){if(await Q(a))return;await D(F(),R());const t=await z(a),e=new J({configPath:a,workspacePath:t}),r=await $(a),s=new N({statePath:f(h(r),"maintenance.json"),getActivity:()=>e.activityStatus(),execute:(l,m)=>Z(l,a,e,m)});await s.start();const i=new U({statePath:f(h(r),"auto-upgrade.json"),maintenance:s,getChannel:()=>E(a)});await i.start();const n=await L(r,{restartAgent:l=>e.restartAgent(l),getActivity:()=>e.activityStatus(),maintenance:s});e.start();const c=async()=>{i.stop(),s.stop(),await n.close(),await e.stop(),process.exit(0)};process.once("SIGINT",()=>{c()}),process.once("SIGTERM",()=>{c()})}async function Q(a,t={}){const e=S();if(w(a)!==w(e.configPath))return!1;const r=await(t.currentVersion??O)();if(!await(t.shouldAttempt??Y)(e.rootDir,r))return!1;let s;try{const i=await(t.migrate??H)();if(!i.migrated)return!1;const n=await(t.readPath??v)(i.paths.configPath);return s=await(t.install??A)({version:r,configPath:i.paths.configPath,runtimeDir:i.paths.runtimeDir,binDir:i.paths.binDir,path:n}),await(t.handoff??K)(i,s,i.paths.configPath,n),!0}catch(i){return s&&await(t.rollback??P)(s).catch(()=>{}),console.error(`[client] automatic legacy migration failed: ${i instanceof Error?i.message:String(i)}`),!1}}async function Z(a,t,e,r){if(a.type==="upgrade"){a.path&&await I(t,a.path);const s=await A({version:a.version,configPath:t,path:a.path??await v(t)});await r("restarting");try{await d(p(t).restart)}catch(i){throw await P(s),await d(p(t).restart).catch(()=>{}),i}return}if(a.type==="restart"&&a.agent){await e.restartAgent(a.agent);return}if(a.type==="restart"){await r("restarting"),await d(p(t).restart);return}if(a.type==="stop"){await r("stopping"),await d(p(t).stop);return}await r("stopping"),await tt(t)}function p(a){return _(a)}async function d(a){const t=await u("/bin/sh",["-lc",a],{allowFailure:!0});if(t.status!==0)throw new Error(t.stderr||t.stdout||`Service command failed: ${a}`)}async function tt(a){const t=process.env.HOME??"",e=a===S().configPath,r=e?q:j,s=e?B:G;if(process.platform==="linux"){await u("systemctl",["--user","disable",`${r}.service`],{allowFailure:!0}),await y(f(t,".config","systemd","user",`${r}.service`)).catch(i=>{if(i.code!=="ENOENT")throw i}),await u("systemctl",["--user","daemon-reload"],{allowFailure:!0}),await u("systemctl",["--user","stop",`${r}.service`],{allowFailure:!0});return}if(process.platform==="darwin"){const i=process.getuid?.();if(i===void 0)throw new Error("Unable to determine current uid for launchctl");const n=f(t,"Library","LaunchAgents",`${s}.plist`);await y(n).catch(c=>{if(c.code!=="ENOENT")throw c}),await u("launchctl",["bootout",`gui/${i}/${s}`],{allowFailure:!0});return}throw new Error("Only Linux and macOS are supported")}function et(a){return new Promise(t=>{const e=setTimeout(()=>{a.kill("SIGKILL")},8e3);a.once("exit",()=>{clearTimeout(e),t()})})}export{J as AgentSupervisor,Q as migrateLegacyServiceAtStartup,z as readWorkspacePathFromConfig,W as resolveAgentEntries,At as runSupervisor};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@messenger-agent/client",
|
|
3
|
-
"version": "0.33.0-alpha.
|
|
3
|
+
"version": "0.33.0-alpha.8",
|
|
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.33.0-alpha.
|
|
25
|
-
"@messenger-agent/shared": "0.33.0-alpha.
|
|
26
|
-
"@messenger-agent/
|
|
27
|
-
"@messenger-agent/
|
|
24
|
+
"@messenger-agent/claude-agent": "0.33.0-alpha.8",
|
|
25
|
+
"@messenger-agent/shared": "0.33.0-alpha.8",
|
|
26
|
+
"@messenger-agent/codex-agent": "0.33.0-alpha.8",
|
|
27
|
+
"@messenger-agent/messenger-agent": "0.33.0-alpha.8"
|
|
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",
|