@z_ptah/agent 0.0.4 → 0.0.6

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 (2) hide show
  1. package/dist/index.js +4 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import"dotenv/config";function H(e){let o=process.env[e];if(!o)throw new Error(`Missing required environment variable: ${e}`);return o}var i={serverUrl:H("PTAH_SERVER_URL"),token:H("PTAH_AGENT_TOKEN"),healthPort:Number(process.env.AGENT_HEALTH_PORT||9090),heartbeatIntervalMs:Number(process.env.HEARTBEAT_INTERVAL_MS||3e4),reconnectIntervalMs:Number(process.env.RECONNECT_INTERVAL_MS||5e3),projectsDir:process.env.PROJECTS_DIR||"/projects"};import k from"ws";import{spawn as oe}from"child_process";function B(e){let{commandId:o,sessionId:t,projectDir:n,message:r,claudeSessionId:s}=e,l=["-p",r,"--output-format","stream-json","--allowedTools","Read,Edit,Write,Glob,Grep","--directory",n];s&&l.push("--resume",s),console.log(`Starting Claude for session ${t} in ${n}`);let g=oe("claude",l,{cwd:n,env:{...process.env},stdio:["pipe","pipe","pipe"]}),v="";g.stdout.on("data",d=>{let u=d.toString();v+=u,a({type:"agent:claude-output",payload:{commandId:o,sessionId:t,output:u,isComplete:!1}})}),g.stderr.on("data",d=>{let u=d.toString(),S={type:"agent:claude-output",payload:{commandId:o,sessionId:t,output:`[stderr] ${u}`,isComplete:!1}};a(S)}),g.on("close",d=>{console.log(`Claude exited with code ${d} for session ${t}`),P(t);let u;try{let Z=v.split(`
3
- `).filter(Boolean);for(let ee of Z){let j=JSON.parse(ee);typeof j.session_id=="string"&&(u=j.session_id)}}catch{}let S={type:"agent:claude-output",payload:{commandId:o,sessionId:t,output:d===0?"":`Process exited with code ${d}`,isComplete:!0,claudeSessionId:u??s}};a(S)}),g.on("error",d=>{console.error(`Claude spawn error for session ${t}:`,d),P(t);let u={type:"agent:claude-output",payload:{commandId:o,sessionId:t,output:`Error spawning Claude: ${d.message}`,isComplete:!0}};a(u)})}var M=new Map;function G(e){if(M.has(e.sessionId)){console.warn(`Session ${e.sessionId} already has an active Claude process`);return}M.set(e.sessionId,{commandId:e.commandId}),B(e)}function P(e){M.delete(e)}import{spawn as te}from"child_process";async function W(e){return new Promise((o,t)=>{console.log(`Building Docker in ${e}...`);let n=te("docker",["compose","up","-d","--build"],{cwd:e,stdio:"inherit"});n.on("close",r=>{r===0?(console.log("Docker build successful"),o()):t(new Error(`Docker build failed with code ${r}`))}),n.on("error",r=>{t(new Error(`Docker build error: ${r.message}`))})})}import{writeFile as ne}from"fs/promises";import{spawn as re}from"child_process";function w(e,o){return new Promise((t,n)=>{let r=re(e,o,{stdio:"inherit"});r.on("close",s=>{s===0?t():n(new Error(`${e} failed with code ${s}`))}),r.on("error",n)})}async function J(e,o,t,n){let r=/^[a-z0-9][a-z0-9-]*$/;if(!r.test(e)||!r.test(o))throw new Error("Invalid project or org code for Nginx config");if(t<1024||t>65535||n<1024||n>65535)throw new Error("Invalid port number");let s=`${e}.${o}.mybptah.com`,l=`
2
+ import"dotenv/config";function H(e){let o=process.env[e];if(!o)throw new Error(`Missing required environment variable: ${e}`);return o}var i={serverUrl:H("PTAH_SERVER_URL"),token:H("PTAH_AGENT_TOKEN"),healthPort:Number(process.env.AGENT_HEALTH_PORT||9090),heartbeatIntervalMs:Number(process.env.HEARTBEAT_INTERVAL_MS||3e4),reconnectIntervalMs:Number(process.env.RECONNECT_INTERVAL_MS||5e3),projectsDir:process.env.PROJECTS_DIR||"/projects"};import k from"ws";import{spawn as oe}from"child_process";function B(e){let{commandId:o,sessionId:t,projectDir:n,message:r,claudeSessionId:s}=e,l=["-p",r,"--output-format","stream-json","--allowedTools","Read,Edit,Write,Glob,Grep","--directory",n];s&&l.push("--resume",s),console.log(`Starting Claude for session ${t} in ${n}`);let g=oe("claude",l,{cwd:n,env:{...process.env},stdio:["pipe","pipe","pipe"]}),v="";g.stdout.on("data",d=>{let p=d.toString();v+=p,a({type:"agent:claude-output",payload:{commandId:o,sessionId:t,output:p,isComplete:!1}})}),g.stderr.on("data",d=>{let p=d.toString(),S={type:"agent:claude-output",payload:{commandId:o,sessionId:t,output:`[stderr] ${p}`,isComplete:!1}};a(S)}),g.on("close",d=>{console.log(`Claude exited with code ${d} for session ${t}`),P(t);let p;try{let Z=v.split(`
3
+ `).filter(Boolean);for(let ee of Z){let j=JSON.parse(ee);typeof j.session_id=="string"&&(p=j.session_id)}}catch{}let S={type:"agent:claude-output",payload:{commandId:o,sessionId:t,output:d===0?"":`Process exited with code ${d}`,isComplete:!0,claudeSessionId:p??s}};a(S)}),g.on("error",d=>{console.error(`Claude spawn error for session ${t}:`,d),P(t);let p={type:"agent:claude-output",payload:{commandId:o,sessionId:t,output:`Error spawning Claude: ${d.message}`,isComplete:!0}};a(p)})}var M=new Map;function G(e){if(M.has(e.sessionId)){console.warn(`Session ${e.sessionId} already has an active Claude process`);return}M.set(e.sessionId,{commandId:e.commandId}),B(e)}function P(e){M.delete(e)}import{spawn as te}from"child_process";async function W(e){return new Promise((o,t)=>{console.log(`Building Docker in ${e}...`);let n=te("docker",["compose","up","-d","--build"],{cwd:e,stdio:"inherit"});n.on("close",r=>{r===0?(console.log("Docker build successful"),o()):t(new Error(`Docker build failed with code ${r}`))}),n.on("error",r=>{t(new Error(`Docker build error: ${r.message}`))})})}import{writeFile as ne}from"fs/promises";import{spawn as re}from"child_process";function w(e,o){return new Promise((t,n)=>{let r=re(e,o,{stdio:"inherit"});r.on("close",s=>{s===0?t():n(new Error(`${e} failed with code ${s}`))}),r.on("error",n)})}async function J(e,o,t,n){let r=/^[a-z0-9][a-z0-9-]*$/;if(!r.test(e)||!r.test(o))throw new Error("Invalid project or org code for Nginx config");if(t<1024||t>65535||n<1024||n>65535)throw new Error("Invalid port number");let s=`${e}.${o}.mybptah.com`,l=`
4
4
  server {
5
5
  listen 80;
6
6
  server_name ${s};
@@ -25,7 +25,7 @@ server {
25
25
  proxy_cache_bypass $http_upgrade;
26
26
  }
27
27
  }
28
- `,g=`/etc/nginx/sites-available/${s}`,v=`/etc/nginx/sites-enabled/${s}`;await ne(g,l);try{await w("ln",["-sf",g,v])}catch{}return await w("nginx",["-t"]),await w("nginx",["-s","reload"]),console.log(`Nginx configured for ${s}`),s}async function V(e){try{await w("certbot",["--nginx","-d",e,"--non-interactive","--agree-tos","--email","ssl@mybptah.com"]),console.log(`SSL configured for ${e}`)}catch(o){console.error(`SSL setup failed for ${e}:`,o)}}function I(e,o,t){let n={type:"agent:deploy-status",payload:{commandId:e.commandId,deploymentId:e.deploymentId,status:o,...t}};a(n)}async function F(e){try{I(e,"building"),await W(e.projectDir),I(e,"deploying");let n=await J(e.projectCode,e.orgCode,3001,3002);await V(n).catch(()=>{});let r=`https://${n}`;I(e,"live",{demoUrl:r}),console.log(`Deploy complete: ${r}`)}catch(o){let t=o instanceof Error?o.message:"Unknown deploy error";console.error("Deploy failed:",t),I(e,"failed",{errorMessage:t})}}import{spawn as h,execSync as se}from"child_process";var ae=5*60*1e3,p=null,m=null,T=!1,b=null;function ie(){if(b===null)try{se("which unbuffer",{stdio:"ignore"}),b=!0}catch{b=!1}return b}function A(){m&&(clearTimeout(m),m=null),p&&(p.kill(),p=null)}function x(e){if(T)return;T=!0,a({type:"agent:claude-login-result",payload:e})}function q(){if(p){console.warn("Login already in progress, ignoring");return}console.log("Starting Claude auth login..."),T=!1;let e=ie();console.log(`Using ${e?"unbuffer (PTY)":"direct spawn"} for claude auth login`);let o=e?h("unbuffer",["-p","claude","auth","login"],{env:{...process.env,TERM:"dumb"},stdio:["pipe","pipe","pipe"]}):h("claude",["auth","login"],{env:{...process.env},stdio:["pipe","pipe","pipe"]});p=o;let t=!1;m=setTimeout(()=>{console.warn("Claude login timed out"),A(),x({success:!1,error:"Login timed out after 5 minutes"})},ae),o.stdout.on("data",n=>{let r=n.toString();if(console.log(`[claude login stdout] ${r.trim()}`),!t){let s=r.match(/(https?:\/\/[^\s]+)/);if(s){t=!0;let l={type:"agent:claude-login-url",payload:{url:s[1]}};a(l)}}}),o.stderr.on("data",n=>{let r=n.toString();if(console.log(`[claude login stderr] ${r.trim()}`),!t){let s=r.match(/(https?:\/\/[^\s]+)/);if(s){t=!0;let l={type:"agent:claude-login-url",payload:{url:s[1]}};a(l)}}}),o.on("close",async n=>{console.log(`Claude auth login exited with code ${n}`),p=null,m&&(clearTimeout(m),m=null);let r=await R();r.loggedIn?(await le(["superpowers@claude-plugins-official"]),x({success:!0,email:r.email,subscriptionType:r.subscriptionType})):x({success:!1,error:"Login failed or was cancelled"})}),o.on("error",n=>{console.error("Claude auth login spawn error:",n),A(),x({success:!1,error:`Spawn error: ${n.message}`})})}function X(e){if(!p){console.warn("No login process running, ignoring input");return}if(e.startsWith("http://localhost")){if(!/^http:\/\/localhost(:\d+)?(\/[^\s]*)?$/.test(e)){console.warn("Invalid localhost URL, rejecting:",e);return}console.log("Curling localhost redirect URL:",e);let t=h("curl",["-s",e]);t.on("close",n=>{console.log(`Curl exited with code ${n}`)}),t.on("error",n=>{console.error("Curl error:",n.message)});return}console.log("Writing code to login process stdin"),p.stdin?.write(e+`
29
- `)}function $(){p&&(console.log("Cancelling Claude login..."),A())}async function R(){return new Promise(e=>{let o=h("claude",["auth","status"],{env:{...process.env},stdio:["pipe","pipe","pipe"]}),t="";o.stdout.on("data",n=>{t+=n.toString()}),o.stderr.on("data",n=>{t+=n.toString()}),o.on("close",()=>{try{let n=JSON.parse(t.trim());e({loggedIn:n.loggedIn===!0,email:n.email,subscriptionType:n.subscriptionType})}catch{e({loggedIn:!1})}}),o.on("error",()=>{e({loggedIn:!1})})})}async function le(e){for(let o of e)console.log(`Installing plugin: ${o}`),await new Promise(t=>{let n=h("claude",["plugin","install",o,"--scope","user"],{env:{...process.env},stdio:["pipe","pipe","pipe"]});n.on("close",r=>{r===0?console.log(`Plugin ${o} installed successfully`):console.warn(`Plugin ${o} install exited with code ${r}`),t()}),n.on("error",r=>{console.warn(`Plugin ${o} install error: ${r.message}`),t()})})}function z(e){E({loggedIn:e.loggedIn,email:e.email}),a({type:"agent:claude-status",payload:e})}function K(e){switch(e.type){case"server:auth-result":e.payload.success||(console.error("Authentication failed:",e.payload.error),process.exit(1));break;case"server:command":console.log(`Received command: ${e.payload.action}`,e.payload);break;case"server:doc-sync":console.log(`Doc sync: ${e.payload.action} ${e.payload.fileName}`);break;case"server:claude-start":{let{commandId:o,sessionId:t,projectId:n,message:r,claudeSessionId:s,projectDir:l}=e.payload;console.log(`Starting Claude session ${t} for project ${n}`),G({commandId:o,sessionId:t,projectDir:l,message:r,claudeSessionId:s});break}case"server:claude-stop":{console.log(`Stop requested for session ${e.payload.sessionId}`);break}case"server:deploy-start":{let{commandId:o,deploymentId:t,projectId:n,projectCode:r,orgCode:s,projectDir:l}=e.payload;console.log(`Starting deployment for project ${r}`),F({commandId:o,deploymentId:t,projectId:n,projectCode:r,orgCode:s,projectDir:l});break}case"server:claude-login-start":{console.log("Received claude-login-start command"),q();break}case"server:claude-login-input":{let{value:o}=e.payload;console.log("Received claude-login-input"),X(o);break}case"server:claude-login-cancel":{console.log("Received claude-login-cancel"),$();break}default:console.warn("Unknown message type:",e.type)}}var c=null,C=null,f=null,y=!1,_=0,Y={loggedIn:!1};function E(e){Y=e}var ce=6e4;function a(e){c?.readyState===k.OPEN&&c.send(JSON.stringify(e))}function de(){N(),C=setInterval(()=>{let e={type:"agent:heartbeat",payload:{cpuUsage:0,memoryUsage:Math.round(process.memoryUsage().heapUsed/1024/1024),activeProjects:0,claude:Y}};a(e)},i.heartbeatIntervalMs)}function N(){C&&(clearInterval(C),C=null)}function ue(){if(f)return;let e=Math.min(i.reconnectIntervalMs*Math.pow(2,_),ce);_++,console.log(`Reconnecting in ${e/1e3}s (attempt ${_})...`),f=setTimeout(()=>{f=null,D()},e)}function D(){y||c?.readyState===k.OPEN||(y=!0,console.log(`Connecting to ${i.serverUrl}...`),c=new k(i.serverUrl),c.on("open",()=>{y=!1,console.log("Connected to Ptah Server");let e={type:"agent:auth",payload:{token:i.token}};a(e)}),c.on("message",e=>{try{let o=JSON.parse(e.toString());K(o),o.type==="server:auth-result"&&o.payload?.success&&(console.log(`Authenticated as VPS ${o.payload.vpsId}`),_=0,de(),R().then(t=>{E({loggedIn:t.loggedIn,email:t.email}),z(t)}))}catch(o){console.error("Failed to parse message:",o)}}),c.on("close",()=>{y=!1,N(),$(),console.log("Disconnected from Ptah Server"),ue()}),c.on("error",e=>{y=!1,console.error("WebSocket error:",e.message)}))}function O(){f&&(clearTimeout(f),f=null),N(),c&&(c.close(),c=null)}import pe from"fastify";var U=pe({logger:!1});U.get("/health",async()=>({status:"ok",timestamp:new Date().toISOString(),uptime:process.uptime()}));async function Q(){await U.listen({port:i.healthPort,host:"0.0.0.0"}),console.log(`Agent health server on http://0.0.0.0:${i.healthPort}`)}async function L(){await U.close()}async function ge(){console.log("Starting Ptah Agent..."),console.log(` Server: ${i.serverUrl}`),console.log(` Health port: ${i.healthPort}`),console.log(` Projects dir: ${i.projectsDir}`),await Q(),D()}process.on("SIGINT",async()=>{console.log(`
28
+ `,g=`/etc/nginx/sites-available/${s}`,v=`/etc/nginx/sites-enabled/${s}`;await ne(g,l);try{await w("ln",["-sf",g,v])}catch{}return await w("nginx",["-t"]),await w("nginx",["-s","reload"]),console.log(`Nginx configured for ${s}`),s}async function V(e){try{await w("certbot",["--nginx","-d",e,"--non-interactive","--agree-tos","--email","ssl@mybptah.com"]),console.log(`SSL configured for ${e}`)}catch(o){console.error(`SSL setup failed for ${e}:`,o)}}function I(e,o,t){let n={type:"agent:deploy-status",payload:{commandId:e.commandId,deploymentId:e.deploymentId,status:o,...t}};a(n)}async function F(e){try{I(e,"building"),await W(e.projectDir),I(e,"deploying");let n=await J(e.projectCode,e.orgCode,3001,3002);await V(n).catch(()=>{});let r=`https://${n}`;I(e,"live",{demoUrl:r}),console.log(`Deploy complete: ${r}`)}catch(o){let t=o instanceof Error?o.message:"Unknown deploy error";console.error("Deploy failed:",t),I(e,"failed",{errorMessage:t})}}import{spawn as h,execSync as se}from"child_process";var ae=5*60*1e3,u=null,m=null,T=!1,b=null;function ie(){if(b===null)try{se("which unbuffer",{stdio:"ignore"}),b=!0}catch{b=!1}return b}function A(){m&&(clearTimeout(m),m=null),u&&(u.kill(),u=null)}function x(e){if(T)return;T=!0,a({type:"agent:claude-login-result",payload:e})}function q(){if(u){console.warn("Login already in progress, ignoring");return}console.log("Starting Claude auth login..."),T=!1;let e=ie();console.log(`Using ${e?"unbuffer (PTY)":"direct spawn"} for claude auth login`);let o=e?h("unbuffer",["-p","claude","auth","login"],{env:{...process.env,TERM:"dumb"},stdio:["pipe","pipe","pipe"]}):h("claude",["auth","login"],{env:{...process.env},stdio:["pipe","pipe","pipe"]});u=o;let t=!1;m=setTimeout(()=>{console.warn("Claude login timed out"),A(),x({success:!1,error:"Login timed out after 5 minutes"})},ae),o.stdout.on("data",n=>{let r=n.toString();if(console.log(`[claude login stdout] ${r.trim()}`),!t){let s=r.match(/(https?:\/\/[^\s]+)/);if(s){t=!0;let l={type:"agent:claude-login-url",payload:{url:s[1]}};a(l)}}}),o.stderr.on("data",n=>{let r=n.toString();if(console.log(`[claude login stderr] ${r.trim()}`),!t){let s=r.match(/(https?:\/\/[^\s]+)/);if(s){t=!0;let l={type:"agent:claude-login-url",payload:{url:s[1]}};a(l)}}}),o.on("close",async n=>{console.log(`Claude auth login exited with code ${n}`),u=null,m&&(clearTimeout(m),m=null);let r=await R();r.loggedIn?(await le(["superpowers@claude-plugins-official"]),x({success:!0,email:r.email,subscriptionType:r.subscriptionType})):x({success:!1,error:"Login failed or was cancelled"})}),o.on("error",n=>{console.error("Claude auth login spawn error:",n),A(),x({success:!1,error:`Spawn error: ${n.message}`})})}function X(e){if(!u){console.warn("No login process running, ignoring input");return}if(e.startsWith("http://localhost")){if(!/^http:\/\/localhost(:\d+)?(\/[^\s]*)?$/.test(e)){console.warn("Invalid localhost URL, rejecting:",e);return}console.log("Curling localhost redirect URL:",e);let t=h("curl",["-s",e]);t.on("close",n=>{console.log(`Curl exited with code ${n}`)}),t.on("error",n=>{console.error("Curl error:",n.message)});return}console.log("Writing code to login process stdin"),u.stdin?.write(e+`
29
+ `),u.stdin?.end()}function $(){u&&(console.log("Cancelling Claude login..."),A())}async function R(){return new Promise(e=>{let o=h("claude",["auth","status"],{env:{...process.env},stdio:["pipe","pipe","pipe"]}),t="";o.stdout.on("data",n=>{t+=n.toString()}),o.stderr.on("data",n=>{t+=n.toString()}),o.on("close",()=>{try{let n=JSON.parse(t.trim());e({loggedIn:n.loggedIn===!0,email:n.email,subscriptionType:n.subscriptionType})}catch{e({loggedIn:!1})}}),o.on("error",()=>{e({loggedIn:!1})})})}async function le(e){for(let o of e)console.log(`Installing plugin: ${o}`),await new Promise(t=>{let n=h("claude",["plugin","install",o,"--scope","user"],{env:{...process.env},stdio:["pipe","pipe","pipe"]});n.on("close",r=>{r===0?console.log(`Plugin ${o} installed successfully`):console.warn(`Plugin ${o} install exited with code ${r}`),t()}),n.on("error",r=>{console.warn(`Plugin ${o} install error: ${r.message}`),t()})})}function z(e){E({loggedIn:e.loggedIn,email:e.email}),a({type:"agent:claude-status",payload:e})}function K(e){switch(e.type){case"server:auth-result":e.payload.success||(console.error("Authentication failed:",e.payload.error),process.exit(1));break;case"server:command":console.log(`Received command: ${e.payload.action}`,e.payload);break;case"server:doc-sync":console.log(`Doc sync: ${e.payload.action} ${e.payload.fileName}`);break;case"server:claude-start":{let{commandId:o,sessionId:t,projectId:n,message:r,claudeSessionId:s,projectDir:l}=e.payload;console.log(`Starting Claude session ${t} for project ${n}`),G({commandId:o,sessionId:t,projectDir:l,message:r,claudeSessionId:s});break}case"server:claude-stop":{console.log(`Stop requested for session ${e.payload.sessionId}`);break}case"server:deploy-start":{let{commandId:o,deploymentId:t,projectId:n,projectCode:r,orgCode:s,projectDir:l}=e.payload;console.log(`Starting deployment for project ${r}`),F({commandId:o,deploymentId:t,projectId:n,projectCode:r,orgCode:s,projectDir:l});break}case"server:claude-login-start":{console.log("Received claude-login-start command"),q();break}case"server:claude-login-input":{let{value:o}=e.payload;console.log("Received claude-login-input"),X(o);break}case"server:claude-login-cancel":{console.log("Received claude-login-cancel"),$();break}default:console.warn("Unknown message type:",e.type)}}var c=null,C=null,f=null,y=!1,_=0,Y={loggedIn:!1};function E(e){Y=e}var ce=6e4;function a(e){c?.readyState===k.OPEN&&c.send(JSON.stringify(e))}function de(){N(),C=setInterval(()=>{let e={type:"agent:heartbeat",payload:{cpuUsage:0,memoryUsage:Math.round(process.memoryUsage().heapUsed/1024/1024),activeProjects:0,claude:Y}};a(e)},i.heartbeatIntervalMs)}function N(){C&&(clearInterval(C),C=null)}function ue(){if(f)return;let e=Math.min(i.reconnectIntervalMs*Math.pow(2,_),ce);_++,console.log(`Reconnecting in ${e/1e3}s (attempt ${_})...`),f=setTimeout(()=>{f=null,D()},e)}function D(){y||c?.readyState===k.OPEN||(y=!0,console.log(`Connecting to ${i.serverUrl}...`),c=new k(i.serverUrl),c.on("open",()=>{y=!1,console.log("Connected to Ptah Server");let e={type:"agent:auth",payload:{token:i.token}};a(e)}),c.on("message",e=>{try{let o=JSON.parse(e.toString());K(o),o.type==="server:auth-result"&&o.payload?.success&&(console.log(`Authenticated as VPS ${o.payload.vpsId}`),_=0,de(),R().then(t=>{E({loggedIn:t.loggedIn,email:t.email}),z(t)}))}catch(o){console.error("Failed to parse message:",o)}}),c.on("close",()=>{y=!1,N(),$(),console.log("Disconnected from Ptah Server"),ue()}),c.on("error",e=>{y=!1,console.error("WebSocket error:",e.message)}))}function O(){f&&(clearTimeout(f),f=null),N(),c&&(c.close(),c=null)}import pe from"fastify";var U=pe({logger:!1});U.get("/health",async()=>({status:"ok",timestamp:new Date().toISOString(),uptime:process.uptime()}));async function Q(){await U.listen({port:i.healthPort,host:"0.0.0.0"}),console.log(`Agent health server on http://0.0.0.0:${i.healthPort}`)}async function L(){await U.close()}async function ge(){console.log("Starting Ptah Agent..."),console.log(` Server: ${i.serverUrl}`),console.log(` Health port: ${i.healthPort}`),console.log(` Projects dir: ${i.projectsDir}`),await Q(),D()}process.on("SIGINT",async()=>{console.log(`
30
30
  Shutting down...`),O(),await L(),process.exit(0)});process.on("SIGTERM",async()=>{console.log(`
31
31
  Shutting down...`),O(),await L(),process.exit(0)});ge().catch(e=>{console.error("Failed to start agent:",e),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@z_ptah/agent",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "type": "module",
5
5
  "description": "Ptah VPS Agent — connects to Ptah Cloud, manages Claude sessions and deployments",
6
6
  "bin": {