shennian 0.4.23 → 0.4.25
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.
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
"file": "src/agents/acp/discovery.js",
|
|
49
|
-
"beforeBytes":
|
|
50
|
-
"afterBytes":
|
|
49
|
+
"beforeBytes": 9533,
|
|
50
|
+
"afterBytes": 4336
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
"file": "src/agents/acp/events.js",
|
|
@@ -306,8 +306,8 @@
|
|
|
306
306
|
},
|
|
307
307
|
{
|
|
308
308
|
"file": "src/commands/daemon.js",
|
|
309
|
-
"beforeBytes":
|
|
310
|
-
"afterBytes":
|
|
309
|
+
"beforeBytes": 45355,
|
|
310
|
+
"afterBytes": 21889
|
|
311
311
|
},
|
|
312
312
|
{
|
|
313
313
|
"file": "src/commands/integration.js",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RequestError as
|
|
1
|
+
import{RequestError as x}from"@agentclientprotocol/sdk";import{buildCommandStringLaunchSpec as M,commandExists as R,resolveCommandFileIdentity as T}from"../command-spec.js";import{registerAcpAgent as S}from"./adapter.js";import{getRegisteredAgents as E,unregisterAgent as L}from"../adapter.js";import{readAcpManifests as D}from"./manifests.js";import{AcpProcessClient as F}from"./process-client.js";import{acpAgentType as g}from"./types.js";import{loadAcpCatalog as N}from"./catalog.js";import{buildAcpCapabilityCacheKey as P,readAcpCapabilityCache as _,writeAcpCapabilityCache as q}from"./capability-cache.js";import{getAcpRuntimeAuthState as b,setAcpRuntimeAuthState as K}from"./auth-state.js";import{recordAcpScan as O}from"./metrics.js";const W=[{id:"qwen-code",name:"Qwen Code",source:"registry",launch:{command:"qwen",args:["--acp"]}},{id:"kimi",name:"Kimi CLI",source:"registry",launch:{command:"kimi",args:["acp"]}}],$=new Set(["claude","codex","codebuddy","cursor","opencode","pi"]);async function se(t={}){const i=Date.now();let a=0,n=0;const r={},f=new Set(E().filter(e=>e.startsWith("acp:"))),l=t.candidates?{candidates:t.candidates,revision:void 0}:await N(t),w=U([...l.candidates.length?l.candidates:W,...D()]),I=w.filter(e=>{const h=e.launch.command;return $.has(h)?!1:R(h)}).filter((e,h,s)=>s.findIndex(m=>m.id===e.id)===h),y=(await V(I,3,async e=>{const s={...M(e.launch.command,e.launch.args??[],t.cwd??process.cwd()),...e.launch.env?{env:e.launch.env}:{}},m=P({manifest:e,platform:process.platform,catalogRevision:l.revision,executableIdentity:T(e.launch.command)}),d=m?_(m):null;if(d?.type===g(e.id)&&d.integration==="acp"&&d.acpCapabilities?.protocolVersion===1)return a+=1,S({...e,launch:s,authLaunch:e.launch}),{...d,authState:b(g(e.id))??d.authState,command:s.command,args:s.args??[],display:{...d.display,name:e.name},...l.revision?{catalogRevision:l.revision}:{}};const C=new F(s,{onSessionUpdate:()=>{},onPermission:async()=>({outcome:{outcome:"cancelled"}})},process.env,{terminalAuth:!0});try{const c=await C.start(t.cwd??process.cwd()),o=c.agentCapabilities??{},k={protocolVersion:1,listSessions:!!o.sessionCapabilities?.list,loadSession:!!o.loadSession,resumeSession:!!o.sessionCapabilities?.resume,closeSession:!!o.sessionCapabilities?.close,deleteSession:!!o.sessionCapabilities?.delete,terminal:!!e.clientCapabilities?.terminal,fileRead:!!e.clientCapabilities?.readTextFile,fileWrite:!!e.clientCapabilities?.writeTextFile,permission:!0,modelConfig:!1};let p=c.authMethods?.length?"unknown":"ready";if(o.sessionCapabilities?.list)try{await C.listSessions(t.cwd??process.cwd()),p=c.authMethods?.length?"unknown":"ready"}catch(u){p=u instanceof x&&u.code===-32e3?"required":"unknown"}const A=b(g(e.id));A?p=A:p==="required"&&K(g(e.id),p),S({...e,launch:s,authLaunch:e.launch});const v={type:g(e.id),command:s.command,args:s.args??[],version:c.agentInfo?.version??void 0,runtimePlatform:process.platform,integration:"acp",display:{name:e.name,version:c.agentInfo?.version??void 0},acpCapabilities:k,authState:p,acpAuthMethods:(c.authMethods??[]).slice(0,8).map(u=>({id:u.id.slice(0,128),name:u.name.slice(0,80),type:"type"in u&&u.type==="terminal"?"terminal":"agent"})),...l.revision?{catalogRevision:l.revision}:{}};return m&&q(m,v),v}catch(c){n+=1;const o=H(c);return r[o]=(r[o]??0)+1,null}finally{await C.close()}})).filter(e=>!!e),B=new Set(y.map(e=>e.type));for(const e of f)B.has(e)||L(e);return O({durationMs:Date.now()-i,candidateCount:w.length,installedCount:y.length,cacheHits:a,handshakeFailures:n,handshakeFailuresByKind:r}),y}function H(t){const i=t instanceof Error?t.message:"";return/timed out/i.test(i)?"timeout":/protocol version/i.test(i)?"version":/safety limit|exceeded/i.test(i)?"output_limit":/json|parse/i.test(i)?"invalid_protocol":/enoent|not found/i.test(i)?"launch":"other"}function U(t){const i=new Set(t.filter(n=>n.source==="local").map(n=>n.id)),a=new Map;for(const n of t){if(n.source!=="local"&&i.has(n.id))continue;const r=`${n.id}\0${n.launch.command}\0${JSON.stringify(n.launch.args??[])}`;a.has(r)||a.set(r,n)}return[...a.values()]}async function V(t,i,a){const n=new Array(t.length);let r=0;return await Promise.all(Array.from({length:Math.min(i,t.length)},async()=>{for(;;){const f=r++;if(f>=t.length)return;n[f]=await a(t[f])}})),n}export{se as discoverAcpAgents};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import c from"chalk";import o from"node:fs";import a from"node:path";import d from"node:os";import{execSync as u,spawn as
|
|
2
|
-
`)}function
|
|
1
|
+
import c from"chalk";import o from"node:fs";import a from"node:path";import d from"node:os";import{execSync as u,spawn as ge}from"node:child_process";import{randomUUID as B}from"node:crypto";import{fileURLToPath as ye}from"node:url";import{getShennianDir as we,loadConfig as V,resolveShennianPath as S,saveConfig as Ee}from"../config/index.js";import{buildAugmentedPath as ve}from"../env-path.js";import{buildWindowsLauncherCommand as Pe,buildWindowsScheduledTaskCommands as Ae,buildWindowsScheduledTaskXml as Ne,buildWindowsStartupVbs as Ie,escapeXml as x,isWindowsCmdScript as De,quoteCmdArg as G,quoteSystemdArg as ke,suspendWindowsScheduledTask as _e}from"./daemon-windows.js";import{waitForDaemonReadyStatus as T}from"./daemon-start-wait.js";import{findRunningWindowsDaemonProcessIds as be,isShennianRunServiceCommand as Re}from"./daemon-process.js";import{getCurrentVersion as K}from"../upgrade/engine.js";import{buildWindowsLauncherCommand as Rn,buildWindowsScheduledTaskCommands as xn,buildWindowsScheduledTaskSuspendCommands as Tn,buildWindowsScheduledTaskXml as Ln,buildWindowsStartupVbs as On,suspendWindowsScheduledTask as Cn}from"./daemon-windows.js";import{isShennianRunServiceCommand as $n}from"./daemon-process.js";const xe=a.dirname(ye(import.meta.url)),h=we(),y=S("daemon.pid"),m=S("daemon.log"),L=S("remote-access.disabled"),k=S("daemon-launcher.json"),J=a.resolve(xe,"../../bin/shennian.js"),q=process.execPath,X=new Set(["PATH","HOME","USERPROFILE","HOMEDRIVE","HOMEPATH","USERNAME","USERDOMAIN","COMPUTERNAME","USER","LOGNAME","SHELL","TMPDIR","LANG","LC_ALL","LC_CTYPE","SSH_AUTH_SOCK","XDG_CONFIG_HOME","XDG_DATA_HOME","TEMP","TMP","APPDATA","LOCALAPPDATA","ELECTRON_RUN_AS_NODE","SHENNIAN_DESKTOP_CLI_SCRIPT","SHENNIAN_DESKTOP_CLI_BRIDGE","SHENNIAN_DESKTOP_SERVER_URL","SHENNIAN_WECHAT_CHANNEL_HELPER_DIR","SHENNIAN_HOME","SHENNIAN_ACCOUNT_NAMESPACE_ID","SHENNIAN_NATIVE_FUSION_DISABLED","SHENNIAN_WECHAT_DELIVERABILITY_TRACE"]);function Te(e){return X.has(e)}function p(){const e=d.platform();return e==="darwin"||e==="linux"||e==="win32"?e:"linux"}function O(e){const n=e.replace(/\\/g,"/").toLowerCase(),r=d.tmpdir().replace(/\\/g,"/").toLowerCase();return n.includes("/_npx/")||n.includes("/npm-cache/_npx/")||n.includes("/pnpm/dlx/")||n.startsWith(r.endsWith("/")?r:`${r}/`)}function Le(e){return process.env.ELECTRON_RUN_AS_NODE==="1"&&e.desktopBridgePath&&o.existsSync(e.scriptPath)&&o.existsSync(e.desktopBridgePath)?{command:e.nodeExec,args:[e.desktopBridgePath,e.scriptPath,"run-service"],mode:"direct"}:o.existsSync(e.scriptPath)&&(process.env.SHENNIAN_E2E_ISOLATED_DAEMON==="1"||!O(e.scriptPath))?{command:e.nodeExec,args:[e.scriptPath,"run-service"],mode:"direct"}:e.shennianCommandPath&&!O(e.shennianCommandPath)?{command:e.shennianCommandPath,args:["run-service"],mode:"global-shim"}:e.npxPath?{command:e.npxPath,args:["--yes","shennian","run-service"],mode:"npx"}:{command:e.nodeExec,args:[e.scriptPath,"run-service"],mode:"direct"}}function Oe(e){const n=e.trim();if(!n)return null;if(n.startsWith("{"))try{const t=JSON.parse(n),s=Number(t.pid);return!Number.isInteger(s)||s<=0?null:{pid:s,...typeof t.instanceId=="string"?{instanceId:t.instanceId}:{},...typeof t.version=="string"?{version:t.version}:{},...t.launcher==="desktop-managed"||t.launcher==="global-cli"||t.launcher==="unknown"?{launcher:t.launcher}:{},...typeof t.startedAt=="string"?{startedAt:t.startedAt}:{},...t.adopted===!0?{adopted:!0}:{}}}catch{return null}const r=parseInt(n,10);return isNaN(r)?null:{pid:r}}function A(){try{return Oe(o.readFileSync(y,"utf-8"))}catch{return null}}function v(e){try{return process.kill(e,0),!0}catch{return!1}}function Y(e,n=3e3){const r=Date.now();for(;Date.now()-r<n;){if(!v(e))return!0;Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,100)}return!v(e)}function Ce(){return o.existsSync(L)}function He(){try{o.unlinkSync(L)}catch{}}function $e(e,n){const r=a.dirname(e),t=`${e}.${process.pid}.${B()}.tmp`;o.mkdirSync(r,{recursive:!0});let s=null;try{s=o.openSync(t,"w",384),o.writeSync(s,n,void 0,"utf8"),o.fsyncSync(s),o.closeSync(s),s=null,o.renameSync(t,e);try{const i=o.openSync(r,"r");try{o.fsyncSync(i)}finally{o.closeSync(i)}}catch{}}finally{s!==null&&o.closeSync(s);try{o.unlinkSync(t)}catch{}}}function Me(e={}){const n=e.disabledAt??new Date().toISOString(),r=e.markerFile??L,t=e.platform??p(),s=e.servicePresent??(H()&&U(t)),i=e.execCommand??(l=>{u(l,{stdio:"pipe",windowsHide:!0})});if($e(r,n),!s)return{disabledAt:n,autoStartDisabled:!0};try{return i(t==="darwin"?`launchctl disable "${P()}"`:t==="linux"?"systemctl --user disable shennian":`schtasks /change /tn "${D}" /disable`),{disabledAt:n,autoStartDisabled:!0}}catch(l){return{disabledAt:n,autoStartDisabled:!1,autoStartError:l instanceof Error?l.message:String(l)}}}function Ue(e={}){const n=e.platform??p();if(!(e.servicePresent??(H()&&U(n))))return{serviceStopped:!0};const t=e.execCommand??(s=>{u(s,{stdio:"pipe",windowsHide:!0})});try{return t(n==="darwin"?`launchctl bootout "${P()}"`:n==="linux"?"systemctl --user stop shennian":`schtasks /end /tn "${D}"`),{serviceStopped:!0}}catch(s){return{serviceStopped:!1,error:s instanceof Error?s.message:String(s)}}}function z(){return process.env.SHENNIAN_DESKTOP_CLI_SCRIPT?"desktop-managed":"global-cli"}function je(){return`${process.pid}-${Date.now()}-${B()}`}function We(e,n,r={}){o.mkdirSync(h,{recursive:!0}),o.writeFileSync(y,JSON.stringify({pid:e,instanceId:n,...r.version?{version:r.version}:{},launcher:r.launcher??z(),...r.adopted?{adopted:!0}:{},startedAt:new Date().toISOString()},null,2))}function Dn(e,n){const r=A();if(!(r?.pid!==e||r.instanceId!==n))try{o.unlinkSync(y)}catch{}}function Q(e,n=z(),r){o.mkdirSync(h,{recursive:!0}),o.writeFileSync(k,JSON.stringify({pid:e,launcher:n,...r?{instanceId:r}:{},updatedAt:new Date().toISOString()},null,2))}function Fe(e){if(e)try{if(JSON.parse(o.readFileSync(k,"utf-8")).instanceId!==e)return}catch{return}try{o.unlinkSync(k)}catch{}}function Be(e){e&&Q(e)}function Ve(e,n){if(!e||!n)return"unknown";try{const r=JSON.parse(o.readFileSync(k,"utf-8"));if(r.pid!==e)return"unknown";if(r.launcher==="desktop-managed"||r.launcher==="global-cli")return r.launcher}catch{}return C(e)}function C(e){if(p()==="win32")return"unknown";try{const n=u(`ps -p ${e} -o command=`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:1e3,windowsHide:!0}).replace(/\\/g,"/");if(n.includes("/cli-bridge.js")||n.includes("/Resources/daemon/")||n.includes("\\resources\\daemon\\"))return"desktop-managed";if(n.includes("/node_modules/shennian/")||n.includes("/bin/shennian")||n.includes(" shennian run-service")||n.includes(" shennian.js run-service"))return"global-cli"}catch{}return"unknown"}function Z(e=process.pid){if(p()==="win32")return be(e);try{return u("ps -axo pid=,command=",{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:1e3,windowsHide:!0}).split(/\r?\n/).map(r=>{const t=r.trim().match(/^(\d+)\s+(.+)$/);if(!t)return null;const s=Number(t[1]),i=t[2];return!Number.isInteger(s)||s===e?null:Re(i)?s:null}).filter(r=>typeof r=="number")}catch{return[]}}function ee(e=process.env,n=h,r=d.tmpdir(),t=a.join(d.homedir(),".shennian")){if(e.SHENNIAN_E2E_ISOLATED_DAEMON!=="1"||!e.SHENNIAN_HOME?.trim()||a.resolve(n)===a.resolve(t))return!1;const s=a.relative(a.resolve(r),a.resolve(n));return s!==""&&s!==".."&&!s.startsWith(`..${a.sep}`)&&!a.isAbsolute(s)||a.resolve(n)===a.resolve(e.SHENNIAN_HOME)}function ne(e=process.env,n=h){return!ee(e,n)}function H(e=process.env,n=h){return!ee(e,n)}function f(e={}){let n=A(),r=n?.pid??null,t=r!==null&&v(r),s=r!==null&&!t,i=n?.adopted===!0;const l=V();if(s&&e.cleanupStale){try{o.unlinkSync(y)}catch{}n=null,r=null,t=!1,s=!1}if(!t&&ne()){const E=Z()[0];if(E&&(r=E,t=!0,s=!1,i=!0,e.cleanupStale)){const F=je();We(E,F,{launcher:C(E),adopted:!0}),Q(E,C(E)),n={pid:E,instanceId:F,adopted:!0}}}return{running:t,pid:r,stale:s,remoteAccessDisabled:Ce(),launcher:Ve(r,t),platform:p(),shennianDir:h,pidFile:y,logFile:m,...n?.instanceId?{instanceId:n.instanceId}:{},...i?{adopted:!0}:{},...l.machineId?{machineId:l.machineId}:{},paired:!!(l.machineToken&&l.machineId),...l.serverUrl?{serverUrl:l.serverUrl}:{}}}function w(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
2
|
+
`)}function te(e){const n=e?.trim();if(!n)return;const r=V();r.serverUrl=n,Ee(r)}function re(e){return e?.trim()||process.env.SHENNIAN_DESKTOP_SERVER_URL?.trim()||void 0}const $="com.shennian.agent",g=a.join(d.homedir(),"Library/LaunchAgents",`${$}.plist`),oe=S("Shennian.app"),Ge=a.join(d.homedir(),"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup"),_=S("autostart.cmd"),b=S("autostart.vbs"),R=S("autostart.xml"),Ke=a.join(Ge,"ShennianAgent.vbs");function se(e){const n=p()==="win32"?`where ${e}`:`command -v ${e}`;try{return u(n,{stdio:["ignore","pipe","pipe"],encoding:"utf-8",windowsHide:!0}).split(/\r?\n/).map(s=>s.trim()).find(Boolean)??null}catch{return null}}function Je(){const e=p()==="win32"?"npx.cmd":"npx",n=a.join(a.dirname(q),e);return o.existsSync(n)?n:se("npx")}function N(){return Le({nodeExec:q,scriptPath:J,shennianCommandPath:se("shennian"),npxPath:Je(),desktopBridgePath:process.env.SHENNIAN_DESKTOP_CLI_BRIDGE})}function ie(){try{u(`schtasks /delete /tn "${D}" /f`,{stdio:"pipe",windowsHide:!0})}catch{}}function ce(){try{o.unlinkSync(Ke)}catch{}}function qe(){const e=process.env.USERDOMAIN?.trim(),n=process.env.COMPUTERNAME?.trim(),r=process.env.USERNAME?.trim()||d.userInfo().username;return e&&e.toUpperCase()!=="WORKGROUP"?`${e}\\${r}`:n?`${n}\\${r}`:r}function Xe(e){if(p()==="win32"&&De(e.command)){const n=[e.command,...e.args].map(G).join(" ");return{command:process.env.ComSpec||"cmd.exe",args:["/d","/s","/c",`"${n}"`],windowsVerbatimArguments:!0}}return{command:e.command,args:e.args}}function Ye(e,n,r=process.env){return{detached:!0,stdio:["ignore",n,n],env:r,windowsHide:!0,...e.windowsVerbatimArguments?{windowsVerbatimArguments:!0}:{}}}function ze(){const e=N();o.writeFileSync(_,Pe(e,m)),o.writeFileSync(b,Ie(_)),ce(),ie();const n=Ne({userId:qe(),command:a.join(process.env.SystemRoot||"C:\\Windows","System32","wscript.exe"),arguments:[G(b)]});o.writeFileSync(R,n,"utf8");const r=Ae({taskName:D,xmlPath:R});try{return u(r.create,{stdio:"pipe",windowsHide:!0}),u(r.run,{stdio:"pipe",windowsHide:!0}),!0}catch{return!1}}function Qe(){_e(D,e=>{u(e,{stdio:"pipe",windowsHide:!0})})}function ae(){const e={};for(const n of X)process.env[n]&&(e[n]=process.env[n]);if(e.HOME??=d.homedir(),e.PATH=ve({pathValue:e.PATH,env:e}),e.USER??=d.userInfo().username,p()==="win32"){const n=process.env.TEMP||process.env.TMP||d.tmpdir(),r=d.homedir();e.USERPROFILE??=r;const t=a.win32.parse(r);e.HOMEDRIVE??=t.root.replace(/[\\/]$/,"")||process.env.HOMEDRIVE||"",e.HOMEPATH??=r.slice((e.HOMEDRIVE||"").length)||process.env.HOMEPATH||"",e.USERNAME??=process.env.USERNAME||d.userInfo().username,e.COMPUTERNAME??=process.env.COMPUTERNAME||"",e.TMPDIR??=n,e.TEMP??=n,e.TMP??=n}else e.TMPDIR??="/tmp";return e}function Ze(e={}){const n=ae(),r=e.launch??N(),t=Object.entries(n).map(([i,l])=>` <key>${x(i)}</key>
|
|
3
3
|
<string>${x(l)}</string>`).join(`
|
|
4
4
|
`),s=[r.command,...r.args].map(i=>` <string>${x(i)}</string>`).join(`
|
|
5
5
|
`);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -7,7 +7,7 @@ import c from"chalk";import o from"node:fs";import a from"node:path";import d fr
|
|
|
7
7
|
<plist version="1.0">
|
|
8
8
|
<dict>
|
|
9
9
|
<key>Label</key>
|
|
10
|
-
<string>${
|
|
10
|
+
<string>${$}</string>
|
|
11
11
|
<key>ProgramArguments</key>
|
|
12
12
|
<array>
|
|
13
13
|
${s}
|
|
@@ -27,8 +27,8 @@ ${t}
|
|
|
27
27
|
<key>StandardErrorPath</key>
|
|
28
28
|
<string>${m}</string>
|
|
29
29
|
</dict>
|
|
30
|
-
</plist>`}function
|
|
31
|
-
`),t=[n.command,...n.args].map(
|
|
30
|
+
</plist>`}function ue(e=oe){o.rmSync(e,{recursive:!0,force:!0})}function en(e=p()){return e!=="darwin"?null:"macOS may show \u201CNode.js Foundation\u201D under Allow in the Background. This is the Node.js runtime used by Shennian Client."}const I=a.join(d.homedir(),".config/systemd/user/shennian.service");function nn(){const e=ae(),n=N(),r=Object.entries(e).map(([s,i])=>`Environment=${s}=${i}`).join(`
|
|
31
|
+
`),t=[n.command,...n.args].map(ke).join(" ");return`[Unit]
|
|
32
32
|
Description=Shennian Agent Daemon
|
|
33
33
|
After=network.target
|
|
34
34
|
|
|
@@ -41,6 +41,6 @@ StandardOutput=append:${m}
|
|
|
41
41
|
StandardError=append:${m}
|
|
42
42
|
|
|
43
43
|
[Install]
|
|
44
|
-
WantedBy=default.target`}const D="ShennianAgent";function tn(e){u(e,{stdio:"pipe",windowsHide:!0})}function rn(){const e=process.getuid?.();if(typeof e=="number")return e;const n=d.userInfo();return typeof n.uid=="number"?n.uid:n.username}function P(e=rn()){return`gui/${e}/${
|
|
44
|
+
WantedBy=default.target`}const D="ShennianAgent";function tn(e){u(e,{stdio:"pipe",windowsHide:!0})}function rn(){const e=process.getuid?.();if(typeof e=="number")return e;const n=d.userInfo();return typeof n.uid=="number"?n.uid:n.username}function P(e=rn()){return`gui/${e}/${$}`}function on(e=tn){try{return e(`launchctl enable "${P()}"; launchctl unload "${g}" 2>/dev/null; launchctl load -w "${g}"`),e(`launchctl kickstart -k "${P()}"`),!0}catch{try{return e(`launchctl enable "${P()}"`),e(`launchctl load -w "${g}"`),e(`launchctl kickstart -k "${P()}"`),!0}catch{return!1}}}function sn(){o.mkdirSync(h,{recursive:!0});const e={};for(const[n,r]of Object.entries(process.env))r!==void 0&&Te(n)&&(e[n]=r);o.writeFileSync(S("env.json"),JSON.stringify(e,null,2))}function de(e={}){o.mkdirSync(h,{recursive:!0});const n=f({cleanupStale:!0});if(n.pid!==null&&n.running&&!M(n)){e.quiet||console.log(c.green(`\u2713 Background service already running (PID ${n.pid})`));return}le(n);const r=o.openSync(m,"a"),t=Xe(N()),s=ge(t.command,t.args,Ye(t,r));s.unref(),o.closeSync(r),Be(s.pid),e.quiet||(console.log(c.green(`\u2713 Background service started (PID ${s.pid})`)),console.log(c.gray(` Logs: ${m}`)))}function M(e,n=A(),r=K()){return e.pid===null||!e.running?!1:e.adopted===!0||n?.version!==r}function U(e=p()){switch(e){case"darwin":return o.existsSync(g)&&!o.existsSync(oe);case"linux":return o.existsSync(I);case"win32":return o.existsSync(_)&&o.existsSync(b)&&o.existsSync(R)}}function cn(e,n,r,t=A(),s=K()){return!n.api?.trim()&&e.pid!==null&&e.running&&!e.stale&&!e.remoteAccessDisabled&&r&&!M(e,t,s)}function le(e=f({cleanupStale:!0})){if(!(!M(e)||e.pid===null))try{process.kill(e.pid,"SIGTERM"),Y(e.pid,5e3)||(process.kill(e.pid,"SIGKILL"),Y(e.pid,2e3));try{A()?.pid===e.pid&&o.unlinkSync(y)}catch{}}catch{}}function pe(e={}){if(o.mkdirSync(h,{recursive:!0}),!H())return!1;const n=p();switch(N().mode==="direct"&&O(J)&&console.warn(c.yellow("\u26A0 Warning: Current CLI path is temporary (npx). Auto-start may not work after reboot.\n Run `npm install -g shennian@latest` for reliable auto-start.")),n){case"darwin":{const t=a.dirname(g);o.mkdirSync(t,{recursive:!0}),ue(),o.writeFileSync(g,Ze());const s=on(),i=en(n);return!e.quiet&&i&&console.log(c.gray(`\u2139 ${i}`)),s}case"linux":{const t=a.dirname(I);o.mkdirSync(t,{recursive:!0}),o.writeFileSync(I,nn());try{u("systemctl --user daemon-reload && systemctl --user enable shennian",{stdio:"pipe",windowsHide:!0})}catch{return!1}try{u(`loginctl enable-linger ${d.userInfo().username}`,{stdio:"pipe",windowsHide:!0})}catch{}try{return u("systemctl --user restart shennian",{stdio:"pipe",windowsHide:!0}),!0}catch{return!1}}case"win32":return ze()}}function an(){const n=f({cleanupStale:!0}).pid;if(n===null)return{};if(!v(n)){try{o.unlinkSync(y)}catch{}return{stalePid:n}}try{return process.kill(n,"SIGTERM"),{stoppedPid:n}}catch(r){return{error:r instanceof Error?r.message:String(r)}}}async function me(e=5e3){const n=an();if(!n.stoppedPid)return n;if(!await W(n.stoppedPid,e))try{process.kill(n.stoppedPid,"SIGKILL"),await W(n.stoppedPid,2e3)}catch(t){return{...n,error:t instanceof Error?t.message:String(t)}}try{o.unlinkSync(y)}catch{}if(Fe(),ne()){for(const t of Z())if(t!==n.stoppedPid)try{process.kill(t,"SIGTERM"),await W(t,2e3)}catch{}}return n}function un(e={}){te(re(e.api)),He(),le(),pe({quiet:e.json})||de({quiet:e.json}),e.json?w(T(()=>f({cleanupStale:!0}))):console.log(c.green("\u2713 Background service started"))}async function dn(e={}){const n=Me(),r=Ue(),t=await me(),s=f({cleanupStale:!0}),i=t.error??n.autoStartError??r.error;if(e.json){w(i?{...s,error:i}:s);return}i?console.error(c.red(`\u2717 Failed to stop completely: ${i}`)):console.log(c.green("\u2713 Background service stopped"))}function fe(e){const n=f({cleanupStale:!0});if(cn(n,e,U())){e.json?w(n):console.log(c.green(`\u2713 Background service already running (PID ${n.pid})`));return}sn(),un(e)}async function j(e={}){await dn(e)}async function W(e,n=5e3){const r=Date.now();for(;Date.now()-r<n;){if(!v(e))return!0;await new Promise(t=>setTimeout(t,100))}return!v(e)}async function ln(e={}){const n=f({cleanupStale:!0});if(n.remoteAccessDisabled){e.json?w({...n,error:"remote_access_disabled_use_shennian_start"}):console.error(c.yellow("Remote access is paused. Run `shennian start` on this computer to resume."));return}te(re(e.api));const r=p();r==="win32"&&Qe();const t=await me();if(t.error){e.json?w({...f(),error:t.error}):console.error(c.red(`\u2717 Failed to stop: ${t.error}`));return}if(t.stoppedPid!==void 0?e.json||console.log(c.green(`\u2713 Background service stopped (PID ${t.stoppedPid})`)):t.stalePid!==void 0?e.json||console.log(c.yellow(`\u26A0 Service process no longer exists, cleaned up stale PID ${t.stalePid}`)):e.json||console.log(c.gray("\u25CF Background service not running, starting it now")),(r==="linux"||r==="win32")&&pe()){e.json&&w(T(()=>f({cleanupStale:!0})));return}de({quiet:e.json}),e.json&&w(T(()=>f({cleanupStale:!0})))}function Se(e={}){const n=f({cleanupStale:!0});if(e.json){w(n);return}if(n.pid===null){console.log(c.gray("\u25CF Background service not running"));return}n.running?(console.log(c.green(`\u25CF Background service running (PID ${n.pid})`)),console.log(c.gray(` Logs: ${m}`))):console.log(c.yellow(`\u25CF Background service stopped (PID ${n.pid} is stale)`))}function he(e){if(!o.existsSync(m)){console.log(c.gray("No logs yet"));return}try{const n=u(d.platform()==="win32"?`powershell Get-Content -Tail ${e.lines} "${m}"`:`tail -n ${e.lines} "${m}"`,{encoding:"utf-8",windowsHide:!0});process.stdout.write(n)}catch{const n=o.readFileSync(m,"utf-8").split(`
|
|
45
45
|
`).slice(-e.lines);console.log(n.join(`
|
|
46
|
-
`))}}async function pn(){switch(await
|
|
46
|
+
`))}}async function pn(){switch(await j(),p()){case"darwin":{if(o.existsSync(g)){try{u(`launchctl unload -w "${g}"`,{stdio:"pipe",windowsHide:!0})}catch{}o.unlinkSync(g)}ue(),console.log(c.green("\u2713 Auto-start uninstalled (launchd)"));break}case"linux":{try{u("systemctl --user disable --now shennian",{stdio:"pipe",windowsHide:!0})}catch{}if(o.existsSync(I)){o.unlinkSync(I);try{u("systemctl --user daemon-reload",{stdio:"pipe",windowsHide:!0})}catch{}}console.log(c.green("\u2713 Auto-start uninstalled (systemd)"));break}case"win32":{ie();try{o.unlinkSync(_)}catch{}try{o.unlinkSync(b)}catch{}try{o.unlinkSync(R)}catch{}ce(),console.log(c.green("\u2713 Auto-start uninstalled (Task Scheduler)"));break}}}function kn(e){e.command("start").description("Start the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(t=>fe(t)),e.command("stop").description("Stop the background service").option("--json","Print machine-readable status JSON").action(t=>j(t)),e.command("status").description("Show background service status").option("--json","Print machine-readable status JSON").action(t=>Se(t)),e.command("logs").description("Show recent logs").option("-n, --lines <n>","Number of lines","50").action(t=>he({lines:parseInt(t.lines,10)}));const n=e.command("daemon",{hidden:!0}).description("Deprecated: use top-level start/stop/status/logs"),r=(t,s)=>{s||console.error(c.yellow(`\u26A0 Deprecated command. Use \`shennian ${t}\` instead.`))};n.command("start").description("Start the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(t=>{r("start",t.json),fe(t)}),n.command("stop").description("Stop the background service").option("--json","Print machine-readable status JSON").action(async t=>{r("stop",t.json),await j(t)}),n.command("restart").description("Restart the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(t=>{r("stop && shennian start",t.json),ln(t)}),n.command("status").description("Show background service status").option("--json","Print machine-readable status JSON").action(t=>{r("status",t.json),Se(t)}),n.command("logs").description("Show recent logs").option("-n, --lines <n>","Number of lines","50").action(t=>{r("logs"),he({lines:parseInt(t.lines,10)})}),n.command("uninstall").description("Uninstall auto-start service").action(pn)}export{Ye as buildDaemonSpawnOptions,Ze as buildMacLaunchdPlist,nn as buildSystemdUnit,Rn as buildWindowsLauncherCommand,xn as buildWindowsScheduledTaskCommands,Tn as buildWindowsScheduledTaskSuspendCommands,Ln as buildWindowsScheduledTaskXml,On as buildWindowsStartupVbs,cn as canReuseRunningDaemonForStart,ae as captureEnvForService,Fe as clearDaemonLauncher,Dn as clearDaemonPidIfOwner,He as clearRemoteAccessDisabled,je as createDaemonInstanceId,Z as findRunningDaemonProcessIds,z as getCurrentProcessDaemonLauncher,f as getDaemonStatus,P as getLaunchdServiceTarget,en as getMacBackgroundItemNotice,pe as installService,U as isAutoStartServicePresent,O as isEphemeralCliPath,ee as isIsolatedDaemonE2eInstance,Ce as isRemoteAccessDisabled,Te as isSafeSnapshotEnvKey,$n as isShennianRunServiceCommand,Me as prepareRemoteAccessPause,Be as recordStartedDaemon,kn as registerDaemonCommand,on as reloadLaunchdAgent,ue as removeLegacyMacBackgroundApp,Le as resolveServiceLaunchSpec,sn as saveEnvSnapshot,ne as shouldDiscoverGlobalDaemonProcesses,H as shouldInstallPlatformService,M as shouldReplaceRunningDaemon,de as startDaemonProcess,Ue as stopPreparedRemoteAccessService,Cn as suspendWindowsScheduledTask,Q as writeDaemonLauncher,We as writeDaemonPid};
|