shennian 0.4.69 → 0.4.71

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 (88) hide show
  1. package/dist/publish-build-manifest.json +125 -70
  2. package/dist/src/agent-env.js +4 -4
  3. package/dist/src/agents/adapter.d.ts +7 -3
  4. package/dist/src/agents/auth-status.d.ts +4 -0
  5. package/dist/src/agents/auth-status.js +2 -0
  6. package/dist/src/agents/codex-protocol.d.ts +103 -0
  7. package/dist/src/agents/codex-protocol.js +3 -0
  8. package/dist/src/agents/codex-runtime.d.ts +91 -0
  9. package/dist/src/agents/codex-runtime.js +14 -0
  10. package/dist/src/agents/codex.d.ts +15 -91
  11. package/dist/src/agents/codex.js +2 -17
  12. package/dist/src/agents/command-spec.js +4 -3
  13. package/dist/src/agents/detect.js +1 -1
  14. package/dist/src/agents/manager.d.ts +4 -3
  15. package/dist/src/agents/manager.js +4 -4
  16. package/dist/src/agents/opencode.d.ts +4 -0
  17. package/dist/src/agents/opencode.js +1 -1
  18. package/dist/src/commands/agent-readiness.d.ts +17 -0
  19. package/dist/src/commands/agent-readiness.js +2 -0
  20. package/dist/src/commands/agent.js +2 -2
  21. package/dist/src/commands/daemon-instance-lock.js +1 -1
  22. package/dist/src/commands/daemon-process.d.ts +1 -0
  23. package/dist/src/commands/daemon-process.js +1 -1
  24. package/dist/src/commands/daemon-service-spec.d.ts +28 -0
  25. package/dist/src/commands/daemon-service-spec.js +1 -0
  26. package/dist/src/commands/daemon-start-wait.d.ts +1 -1
  27. package/dist/src/commands/daemon-start-wait.js +1 -1
  28. package/dist/src/commands/daemon-state.d.ts +57 -0
  29. package/dist/src/commands/daemon-state.js +1 -0
  30. package/dist/src/commands/daemon-windows.d.ts +8 -0
  31. package/dist/src/commands/daemon-windows.js +10 -10
  32. package/dist/src/commands/daemon.d.ts +4 -64
  33. package/dist/src/commands/daemon.js +13 -13
  34. package/dist/src/commands/upgrade.js +1 -1
  35. package/dist/src/daemon-ipc/agent-readiness.d.ts +14 -0
  36. package/dist/src/daemon-ipc/agent-readiness.js +1 -0
  37. package/dist/src/daemon-ipc/control.d.ts +1 -1
  38. package/dist/src/daemon-ipc/control.js +1 -1
  39. package/dist/src/index.js +3 -3
  40. package/dist/src/native-fusion/local-repository.d.ts +6 -1
  41. package/dist/src/native-fusion/local-repository.js +2 -2
  42. package/dist/src/native-fusion/service.d.ts +2 -0
  43. package/dist/src/native-fusion/service.js +2 -2
  44. package/dist/src/native-fusion/source-visibility-audit.d.ts +16 -0
  45. package/dist/src/native-fusion/source-visibility-audit.js +1 -0
  46. package/dist/src/native-fusion/source-visibility.d.ts +25 -0
  47. package/dist/src/native-fusion/source-visibility.js +1 -0
  48. package/dist/src/native-fusion/state.d.ts +1 -0
  49. package/dist/src/native-fusion/state.js +2 -2
  50. package/dist/src/native-fusion/types.d.ts +5 -0
  51. package/dist/src/room/managed-room-binding.d.ts +2 -0
  52. package/dist/src/room/managed-room-binding.js +1 -1
  53. package/dist/src/room/room-binding-client.d.ts +1 -0
  54. package/dist/src/room/room-binding-client.js +1 -1
  55. package/dist/src/runtime-distribution.d.ts +13 -0
  56. package/dist/src/runtime-distribution.js +1 -0
  57. package/dist/src/security/managed-agent-policy.d.ts +7 -0
  58. package/dist/src/security/managed-agent-policy.js +1 -1
  59. package/dist/src/session/handlers/agent-workspace-validation.d.ts +1 -0
  60. package/dist/src/session/handlers/agent-workspace-validation.js +1 -1
  61. package/dist/src/session/handlers/agents.d.ts +7 -1
  62. package/dist/src/session/handlers/agents.js +1 -1
  63. package/dist/src/session/handlers/chat-context.d.ts +31 -0
  64. package/dist/src/session/handlers/chat-context.js +1 -0
  65. package/dist/src/session/handlers/chat-events.d.ts +1 -1
  66. package/dist/src/session/handlers/chat-events.js +2 -2
  67. package/dist/src/session/handlers/chat-session-lifecycle.d.ts +2 -2
  68. package/dist/src/session/handlers/chat-session-lifecycle.js +1 -1
  69. package/dist/src/session/handlers/chat.d.ts +3 -29
  70. package/dist/src/session/handlers/chat.js +1 -1
  71. package/dist/src/session/manager.js +2 -2
  72. package/dist/src/session/queue-helpers.js +2 -2
  73. package/dist/src/session/queue-message.d.ts +2 -0
  74. package/dist/src/session/queue.d.ts +7 -1
  75. package/dist/src/session/queue.js +1 -1
  76. package/dist/src/session/queued-chat-dispatch.d.ts +4 -1
  77. package/dist/src/session/queued-chat-dispatch.js +1 -1
  78. package/dist/src/session/store.d.ts +4 -2
  79. package/dist/src/session/store.js +2 -2
  80. package/dist/src/session/types.d.ts +1 -0
  81. package/dist/src/upgrade/engine.js +2 -2
  82. package/dist/src/upgrade/scheduler.js +1 -1
  83. package/dist/src/upgrade/updater-launcher.js +3 -3
  84. package/node_modules/@shennian/wire/dist/room.d.ts +2 -0
  85. package/node_modules/@shennian/wire/dist/session-sync.d.ts +2 -1
  86. package/node_modules/@shennian/wire/dist/session.d.ts +19 -1
  87. package/node_modules/@shennian/wire/dist/session.js +8 -0
  88. package/package.json +1 -1
@@ -15,6 +15,7 @@ export declare class OpenCodeAdapter extends AgentAdapter {
15
15
  private seq;
16
16
  private runId;
17
17
  private terminalState;
18
+ private runUsage;
18
19
  private externalChannel;
19
20
  private shennianSessionId;
20
21
  private extraEnv;
@@ -35,6 +36,9 @@ export declare class OpenCodeAdapter extends AgentAdapter {
35
36
  private prepareManagedLaunch;
36
37
  private disposeManagedConfig;
37
38
  private handleStreamEvent;
39
+ private handleProcessLine;
40
+ private recordStepUsage;
41
+ private completeRunAfterProcessExit;
38
42
  private emitEvent;
39
43
  private emitFinalIfOpen;
40
44
  private emitErrorIfOpen;
@@ -1 +1 @@
1
- import{createInterface as f}from"node:readline";import{randomUUID as c}from"node:crypto";import{AgentAdapter as p,registerAgent as h}from"./adapter.js";import{resolveBuiltinCommand as m,spawnAgentCommand as E}from"./command-spec.js";import{buildAgentProcessEnv as C,buildManagedAgentProcessEnv as I,buildManagedNativeFullProcessEnv as O}from"../agent-env.js";import{buildInlineChannelPreamble as y}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as D,isManagedAgentNativeFull as S}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as w}from"../security/managed-agent-runtime.js";import{compileOpenCodeManagedPermissions as P,createOpenCodeManagedConfigDirectory as _,disposeOpenCodeManagedConfigDirectory as v,OPENCODE_MANAGED_RUNTIME_SECURITY as A}from"./opencode-managed-permissions.js";w("opencode",A);function N(n){if(!n)return;const e=n.input,t=n.output;if(!(typeof e!="number"&&typeof t!="number"))return{inputTokens:typeof e=="number"?e:0,outputTokens:typeof t=="number"?t:0}}function g(n){if(n==null)return"";if(typeof n=="string")return n;try{return JSON.stringify(n)}catch{return String(n)}}function u(n){if(!n)return"opencode request failed";if(typeof n=="string")return n;if(typeof n!="object")return String(n);const e=n;return typeof e.message=="string"?e.message:typeof e.name=="string"?e.name:"data"in e?u(e.data):g(n)||"opencode request failed"}class x extends p{type="opencode";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="closed";externalChannel=null;shennianSessionId=null;extraEnv={};managedAgentPolicy=null;managedConfigDir=null;configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir)}async start(e,t,a){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,a&&(this.agentSessionId=a),this.resetRunState()}async send(e,t,a,s,r,l){if(l?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=c(),this.resetRunState();const o=["run","--format","json","--dir",this.workDir??process.cwd()];this.agentSessionId&&o.push("--session",this.agentSessionId),t&&o.push("--model",t);const i=`${y(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,r)}${e}`;await this.spawnAndParse(o,i)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=c(),this.resetRunState(),this.emitEvent({state:"start",agentSessionId:e}),this.emitFinalIfOpen({state:"final",agentSessionId:e})}async stop(){await this.killProcess()}resetRunState(){this.seq=0,this.terminalState="open"}async spawnAndParse(e,t){const a=m("opencode");if(!a){this.emit("error",new Error('Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".'));return}const s=await this.prepareManagedLaunch();let r;try{r=E(a,[e[0],...s.args,...e.slice(1)],{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:s.env})}catch(i){throw await this.disposeManagedConfig(s.configDir),i}this.process=r,this.managedConfigDir=s.configDir,f({input:r.stdout}).on("line",i=>{if(i.trim())try{const d=JSON.parse(i);this.handleStreamEvent(d)}catch{this.emitEvent({state:"delta",text:i})}});let o="";r.stderr?.on("data",i=>{o+=i.toString()}),r.on("close",i=>{if(this.process!==r||(this.process=null,this.disposeManagedConfig(s.configDir),this.terminalState!=="open"))return;const d=o.trim();if(i!==0&&i!==null){this.emitErrorIfOpen({state:"error",message:d||`opencode exited with code ${i}`});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}),r.on("error",i=>{this.process===r&&(this.process=null,this.disposeManagedConfig(s.configDir),i.code==="ENOENT"?this.emit("error",new Error('Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".')):this.emit("error",i))}),r.stdin.on("error",i=>{this.process===r&&this.emitErrorIfOpen({state:"error",message:i.message})}),r.stdin.end(t)}async prepareManagedLaunch(){const e=this.managedAgentPolicy;if(!e)return{args:["--auto"],env:C({NO_COLOR:"1",...this.extraEnv}),configDir:null};if(S(e))return{args:["--auto"],env:O({NO_COLOR:"1",...this.extraEnv}),configDir:null};const t=P(D(e),e.adapterPolicy.workDir),a=await _(t),s=I({agentType:"opencode",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}});return s.OPENCODE_CONFIG=a.configPath,s.OPENCODE_CONFIG_DIR=a.directory,s.OPENCODE_CONFIG_CONTENT=JSON.stringify(t.config),s.OPENCODE_DISABLE_PROJECT_CONFIG="true",s.OPENCODE_DISABLE_CLAUDE_CODE="1",s.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT="1",s.OPENCODE_DISABLE_CLAUDE_CODE_SKILLS="1",{args:t.args,env:s,configDir:a.directory}}async disposeManagedConfig(e){e&&(this.managedConfigDir===e&&(this.managedConfigDir=null),await v(e).catch(()=>{}))}handleStreamEvent(e){e.sessionID&&e.sessionID!==this.agentSessionId&&(this.agentSessionId=e.sessionID,this.emitEvent({state:"start",agentSessionId:e.sessionID}));const t=e.part;if(e.type==="text"&&t?.text){this.emitEvent({state:"delta",text:t.text});return}if(e.type==="reasoning"&&t?.text){this.emitEvent({state:"delta",text:t.text,thinking:!0});return}if(e.type==="tool_use"&&t?.type==="tool"){t.state?.status==="completed"||t.state?.status==="error"?this.emitEvent({state:"tool-result",name:t.tool??"tool",result:t.state.status==="error"?t.state.error??"tool failed":g(t.state?.output)}):this.emitEvent({state:"tool-call",name:t.tool??"tool",args:t.state?.input??{}});return}if(e.type==="error"){this.emitErrorIfOpen({state:"error",message:u(e.error)});return}e.type==="step_finish"&&this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??e.sessionID,usage:N(t?.tokens)})}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(e))}async killProcess(){const e=this.process;if(!e){await this.disposeManagedConfig(this.managedConfigDir);return}this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}),await this.disposeManagedConfig(this.managedConfigDir)}}h("opencode",()=>new x);export{x as OpenCodeAdapter};
1
+ import{createInterface as g}from"node:readline";import{randomUUID as l}from"node:crypto";import{AgentAdapter as h,registerAgent as f}from"./adapter.js";import{resolveBuiltinCommand as m,spawnAgentCommand as E}from"./command-spec.js";import{buildAgentProcessEnv as C,buildManagedAgentProcessEnv as y,buildManagedNativeFullProcessEnv as O}from"../agent-env.js";import{buildInlineChannelPreamble as D}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as I,isManagedAgentNativeFull as S}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as P}from"../security/managed-agent-runtime.js";import{compileOpenCodeManagedPermissions as w,createOpenCodeManagedConfigDirectory as _,disposeOpenCodeManagedConfigDirectory as A,OPENCODE_MANAGED_RUNTIME_SECURITY as v}from"./opencode-managed-permissions.js";P("opencode",v);function N(n){if(!n)return;const e=n.input,t=n.output;if(!(typeof e!="number"&&typeof t!="number"))return{inputTokens:typeof e=="number"?e:0,outputTokens:typeof t=="number"?t:0}}function u(n){if(n==null)return"";if(typeof n=="string")return n;try{return JSON.stringify(n)}catch{return String(n)}}function c(n){if(!n)return"opencode request failed";if(typeof n=="string")return n;if(typeof n!="object")return String(n);const e=n;return typeof e.message=="string"?e.message:typeof e.name=="string"?e.name:"data"in e?c(e.data):u(n)||"opencode request failed"}class x extends h{type="opencode";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="closed";runUsage;externalChannel=null;shennianSessionId=null;extraEnv={};managedAgentPolicy=null;managedConfigDir=null;configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir)}async start(e,t,o){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,o&&(this.agentSessionId=o),this.resetRunState()}async send(e,t,o,i,s,d){if(d?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=l(),this.resetRunState();const a=["run","--format","json","--dir",this.workDir??process.cwd()];this.agentSessionId&&a.push("--session",this.agentSessionId),t&&a.push("--model",t);const r=`${D(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,s)}${e}`;await this.spawnAndParse(a,r)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=l(),this.resetRunState(),this.emitEvent({state:"start",agentSessionId:e}),this.emitFinalIfOpen({state:"final",agentSessionId:e})}async stop(){await this.killProcess()}resetRunState(){this.seq=0,this.terminalState="open",this.runUsage=void 0}async spawnAndParse(e,t){const o=m("opencode");if(!o){this.emit("error",new Error('Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".'));return}const i=await this.prepareManagedLaunch();let s;try{s=E(o,[e[0],...i.args,...e.slice(1)],{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:i.env})}catch(r){throw await this.disposeManagedConfig(i.configDir),r}this.process=s,this.managedConfigDir=i.configDir,g({input:s.stdout}).on("line",r=>{this.handleProcessLine(s,r)});let a="";s.stderr?.on("data",r=>{a+=r.toString()}),s.on("close",(r,p)=>{this.process===s&&(this.process=null,this.disposeManagedConfig(i.configDir),this.terminalState==="open"&&this.completeRunAfterProcessExit(r,p,a.trim()))}),s.on("error",r=>{this.process===s&&(this.process=null,this.disposeManagedConfig(i.configDir),r.code==="ENOENT"?this.emit("error",new Error('Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".')):this.emit("error",r))}),s.stdin.on("error",r=>{this.process===s&&this.emitErrorIfOpen({state:"error",message:r.message})}),s.stdin.end(t)}async prepareManagedLaunch(){const e=this.managedAgentPolicy;if(!e)return{args:["--auto"],env:C({NO_COLOR:"1",...this.extraEnv}),configDir:null};if(S(e))return{args:["--auto"],env:O({NO_COLOR:"1",...this.extraEnv}),configDir:null};const t=w(I(e),e.adapterPolicy.workDir),o=await _(t),i=y({agentType:"opencode",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}});return i.OPENCODE_CONFIG=o.configPath,i.OPENCODE_CONFIG_DIR=o.directory,i.OPENCODE_CONFIG_CONTENT=JSON.stringify(t.config),i.OPENCODE_DISABLE_PROJECT_CONFIG="true",i.OPENCODE_DISABLE_CLAUDE_CODE="1",i.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT="1",i.OPENCODE_DISABLE_CLAUDE_CODE_SKILLS="1",{args:t.args,env:i,configDir:o.directory}}async disposeManagedConfig(e){e&&(this.managedConfigDir===e&&(this.managedConfigDir=null),await A(e).catch(()=>{}))}handleStreamEvent(e){e.sessionID&&e.sessionID!==this.agentSessionId&&(this.agentSessionId=e.sessionID,this.emitEvent({state:"start",agentSessionId:e.sessionID}));const t=e.part;if(e.type==="text"&&t?.text){this.emitEvent({state:"delta",text:t.text});return}if(e.type==="reasoning"&&t?.text){this.emitEvent({state:"delta",text:t.text,thinking:!0});return}if(e.type==="tool_use"&&t?.type==="tool"){t.state?.status==="completed"||t.state?.status==="error"?this.emitEvent({state:"tool-result",name:t.tool??"tool",result:t.state.status==="error"?t.state.error??"tool failed":u(t.state?.output)}):this.emitEvent({state:"tool-call",name:t.tool??"tool",args:t.state?.input??{}});return}if(e.type==="error"){this.emitErrorIfOpen({state:"error",message:c(e.error)});return}e.type==="step_finish"&&this.recordStepUsage(N(t?.tokens))}handleProcessLine(e,t){if(!(this.process!==e||!t.trim()))try{this.handleStreamEvent(JSON.parse(t))}catch{this.emitEvent({state:"delta",text:t})}}recordStepUsage(e){e&&(this.runUsage={inputTokens:(this.runUsage?.inputTokens??0)+e.inputTokens,outputTokens:(this.runUsage?.outputTokens??0)+e.outputTokens})}completeRunAfterProcessExit(e=0,t=null,o=""){if(e!==0||t!==null){this.emitErrorIfOpen({state:"error",message:o||(t?`opencode exited with signal ${t}`:`opencode exited with code ${String(e)}`)});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.runUsage})}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(e))}async killProcess(){const e=this.process;if(!e){await this.disposeManagedConfig(this.managedConfigDir);return}this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}),await this.disposeManagedConfig(this.managedConfigDir)}}f("opencode",()=>new x);export{x as OpenCodeAdapter};
@@ -0,0 +1,17 @@
1
+ import type { Command } from 'commander';
2
+ import { callDaemonIpc } from '../daemon-ipc/client.js';
3
+ import type { JsonValue } from '../daemon-ipc/json.js';
4
+ export declare function executeAgentReadinessCommand(method: 'agent.discover' | 'agent.check', params?: JsonValue, call?: typeof callDaemonIpc): Promise<{
5
+ ok: boolean;
6
+ command: "agent.discover" | "agent.check";
7
+ result: JsonValue;
8
+ error?: undefined;
9
+ nextAction?: undefined;
10
+ } | {
11
+ ok: boolean;
12
+ command: "agent.discover" | "agent.check";
13
+ error: string;
14
+ nextAction: string;
15
+ result?: undefined;
16
+ }>;
17
+ export declare function registerAgentReadinessCommands(agent: Command): void;
@@ -0,0 +1,2 @@
1
+ import{callDaemonIpc as a}from"../daemon-ipc/client.js";import{DaemonIpcError as r}from"../daemon-ipc/protocol.js";const s={method_not_found:"Update the existing Shennian installation: Desktop through Desktop updates, standalone CLI through its own update flow. Do not install a second Client.",daemon_unavailable:"Check shennian status --json on the target computer. Do not resume an intentional pause without the user requesting it.",daemon_paused:"Shennian is paused. Ask the user to resume it before checking.",ipc_timeout:"The result is unknown. Check the target machine and wait for the current check to finish; do not repeatedly send tests.",agent_check_in_progress:"Wait for the running check to finish before trying again.",agent_validation_runtime_unavailable:"Refresh discovery. If the tool is still missing, guide the user through its official installation on this computer.",agent_validation_runtime_auth_required:"Guide the user through the provider\u2019s own sign-in on this computer, then retry the selected AI and model.",agent_validation_model_unavailable:"Choose a model returned by discovery and check the provider account\u2019s model access.",agent_validation_quota_exceeded:"Check the provider account\u2019s credits, subscription or rate limit before another test.",agent_validation_network_failed:"Check the target computer\u2019s connection to the provider, then retry when it is available."};async function c(t,i,n=a){try{const e=await n({method:t,params:i,timeoutMs:9e4});if(t==="agent.check"&&(!e||typeof e!="object"||Array.isArray(e)||e.ready!==!0))throw new r("agent_check_invalid_response","The daemon did not confirm a successful hello reply.");return{ok:!0,command:t,result:e}}catch(e){const o=e instanceof r?e.code:"agent_check_failed";return{ok:!1,command:t,error:o,nextAction:s[o]??"Return to the AI preparation guide on this machine. Check the selected directory, account, model and network; do not reinstall by default."}}}function h(t){const i=async(n,e)=>{const o=await c(n,e);process.stdout.write(`${JSON.stringify(o)}
2
+ `),o.ok||(process.exitCode=1)};t.command("discover").description("Refresh AI discovery and sign-in summaries on the running local daemon; no model requests").option("--json","Print JSON (default)").action(()=>i("agent.discover")),t.command("check <agentType>").description("Send one hello test using the selected AI and model; uses provider quota, creates no managed Agent or room").requiredOption("--workdir <path>","Absolute project directory on this machine").option("--model <id>","Model returned by discovery; otherwise use the provider default").option("--json","Print JSON (default)").action((n,e)=>i("agent.check",{agentType:n,workDir:e.workdir,modelId:e.model??null}))}export{c as executeAgentReadinessCommand,h as registerAgentReadinessCommands};
@@ -1,2 +1,2 @@
1
- import{createAgent as p}from"../agents/adapter.js";import{AcpAgentAdapter as u}from"../agents/acp/adapter.js";import{discoverAcpAgents as h}from"../agents/acp/discovery.js";import{callDaemonIpc as A}from"../daemon-ipc/client.js";import{readAcpManifests as f,removeAcpManifest as w,validateAcpId as s,writeAcpManifest as C}from"../agents/acp/manifests.js";function x(i){const o=i.command("agent").description("Manage local ACP Agent integrations");o.command("add <id>").description("Register an installed ACP v1 Agent (does not install it)").requiredOption("--name <name>","Display name").requiredOption("--command <command>","Absolute executable path or command name").option("--arg <args...>","Arguments passed to the ACP Agent").action((a,e)=>{try{const t=s(a);C({schemaVersion:1,id:t,name:e.name,protocol:"acp",command:e.command,args:e.arg??[],enabled:!0}),r(!0,"agent.add",{agentRef:`acp:${t}`,installedByShennian:!1})}catch(t){r(!1,"agent.add",void 0,t instanceof Error?t.message:String(t))}}),o.command("list").description("List locally registered ACP Agents").action(()=>{r(!0,"agent.list",{agents:f().map(a=>({agentRef:`acp:${a.id}`,name:a.name,command:a.launch.command,args:a.launch.args??[]}))})}),o.command("remove <id>").description("Remove a local ACP Agent registration (does not uninstall it)").action(a=>{try{const e=s(a),t=w(e);r(t,"agent.remove",t?{agentRef:`acp:${e}`}:void 0,t?void 0:`No local ACP Agent named "${e}" exists.`)}catch(e){r(!1,"agent.remove",void 0,e instanceof Error?e.message:String(e))}}),o.command("auth <id>").description("Authenticate an installed ACP Agent on this computer").option("--method <method>","Authentication method id").action(async(a,e)=>{let t=null;try{const n=s(a.replace(/^acp:/,""));if(!(await h()).some(d=>d.type===`acp:${n}`))throw new Error(`Installed ACP Agent "${n}" was not found.`);const m=p(`acp:${n}`);if(!(m instanceof u))throw new Error("ACP Agent adapter is unavailable");t=m,await t.start(`acp-auth-${process.pid}`,process.cwd());const c=t.getAuthMethods(),l=e.method?c.find(d=>d.id===e.method):c.length===1?c[0]:void 0;if(!l)throw new Error(c.length?`Choose an authentication method with --method: ${c.map(d=>d.id).join(", ")}`:"This ACP Agent did not advertise an authentication method.");await t.authenticate(l.id,{interactiveTerminal:!0});let g=!1;try{g=(await A({method:"agent.auth.completed",params:{agentType:`acp:${n}`}})).resumed}catch{}r(!0,"agent.auth",{agentRef:`acp:${n}`,authenticated:!0,resumed:g})}catch(n){r(!1,"agent.auth",void 0,n instanceof Error?n.message:String(n))}finally{await t?.stop().catch(()=>{})}})}function r(i,o,a,e){process.stdout.write(`${JSON.stringify(i?{ok:i,command:o,result:a}:{ok:i,command:o,error:"acp_agent_manifest_error",message:e,nextAction:null})}
2
- `),i||(process.exitCode=1)}export{x as registerAgentCommand};
1
+ import{registerAgentReadinessCommands as p}from"./agent-readiness.js";import{createAgent as h}from"../agents/adapter.js";import{AcpAgentAdapter as u}from"../agents/acp/adapter.js";import{discoverAcpAgents as A}from"../agents/acp/discovery.js";import{callDaemonIpc as f}from"../daemon-ipc/client.js";import{readAcpManifests as w,removeAcpManifest as v,validateAcpId as s,writeAcpManifest as C}from"../agents/acp/manifests.js";function b(i){const r=i.command("agent").description("Discover and check local AI tools, or manage registered integrations");p(r),r.command("add <id>").description("Register an installed ACP v1 Agent (does not install it)").requiredOption("--name <name>","Display name").requiredOption("--command <command>","Absolute executable path or command name").option("--arg <args...>","Arguments passed to the ACP Agent").action((a,e)=>{try{const t=s(a);C({schemaVersion:1,id:t,name:e.name,protocol:"acp",command:e.command,args:e.arg??[],enabled:!0}),o(!0,"agent.add",{agentRef:`acp:${t}`,installedByShennian:!1})}catch(t){o(!1,"agent.add",void 0,t instanceof Error?t.message:String(t))}}),r.command("list").description("List locally registered ACP Agents").action(()=>{o(!0,"agent.list",{agents:w().map(a=>({agentRef:`acp:${a.id}`,name:a.name,command:a.launch.command,args:a.launch.args??[]}))})}),r.command("remove <id>").description("Remove a local ACP Agent registration (does not uninstall it)").action(a=>{try{const e=s(a),t=v(e);o(t,"agent.remove",t?{agentRef:`acp:${e}`}:void 0,t?void 0:`No local ACP Agent named "${e}" exists.`)}catch(e){o(!1,"agent.remove",void 0,e instanceof Error?e.message:String(e))}}),r.command("auth <id>").description("Authenticate an installed ACP Agent on this computer").option("--method <method>","Authentication method id").action(async(a,e)=>{let t=null;try{const n=s(a.replace(/^acp:/,""));if(!(await A()).some(d=>d.type===`acp:${n}`))throw new Error(`Installed ACP Agent "${n}" was not found.`);const m=h(`acp:${n}`);if(!(m instanceof u))throw new Error("ACP Agent adapter is unavailable");t=m,await t.start(`acp-auth-${process.pid}`,process.cwd());const c=t.getAuthMethods(),l=e.method?c.find(d=>d.id===e.method):c.length===1?c[0]:void 0;if(!l)throw new Error(c.length?`Choose an authentication method with --method: ${c.map(d=>d.id).join(", ")}`:"This ACP Agent did not advertise an authentication method.");await t.authenticate(l.id,{interactiveTerminal:!0});let g=!1;try{g=(await f({method:"agent.auth.completed",params:{agentType:`acp:${n}`}})).resumed}catch{}o(!0,"agent.auth",{agentRef:`acp:${n}`,authenticated:!0,resumed:g})}catch(n){o(!1,"agent.auth",void 0,n instanceof Error?n.message:String(n))}finally{await t?.stop().catch(()=>{})}})}function o(i,r,a,e){process.stdout.write(`${JSON.stringify(i?{ok:i,command:r,result:a}:{ok:i,command:r,error:"acp_agent_manifest_error",message:e,nextAction:null})}
2
+ `),i||(process.exitCode=1)}export{b as registerAgentCommand};
@@ -1 +1 @@
1
- import t from"node:fs";import u from"node:path";function i(e){try{const r=JSON.parse(t.readFileSync(e,"utf8"));return Number.isInteger(r.pid)&&Number(r.pid)>0&&typeof r.instanceId=="string"?{pid:Number(r.pid),instanceId:r.instanceId}:null}catch{return null}}function f(e){try{return process.kill(e,0),!0}catch(r){return!!(r&&typeof r=="object"&&"code"in r&&r.code==="EPERM")}}function S(e){const r=e.pid??process.pid,l=e.isProcessAlive??f,o=e.now??Date.now,s=e.malformedStaleAfterMs??5e3;t.mkdirSync(u.dirname(e.lockPath),{recursive:!0});for(let d=0;d<3;d+=1)try{const c=t.openSync(e.lockPath,"wx",384);t.writeFileSync(c,JSON.stringify({pid:r,instanceId:e.instanceId})),t.fsyncSync(c);let a=!1;return{acquired:!0,release:()=>{if(a)return;a=!0,t.closeSync(c);const n=i(e.lockPath);if(!(n?.pid!==r||n.instanceId!==e.instanceId))try{t.unlinkSync(e.lockPath)}catch{}}}}catch(c){if((c&&typeof c=="object"&&"code"in c?c.code:null)!=="EEXIST")throw c;const n=i(e.lockPath);if(n&&l(n.pid))return{acquired:!1,ownerPid:n.pid};if(!n)try{if(Math.max(0,o()-t.statSync(e.lockPath).mtimeMs)<s)return{acquired:!1,ownerPid:null}}catch{}try{t.unlinkSync(e.lockPath)}catch{}}return{acquired:!1,ownerPid:i(e.lockPath)?.pid??null}}export{S as acquireDaemonInstanceLock};
1
+ import r from"node:fs";import h from"node:path";import{isDaemonProcessRunning as k}from"./daemon-process.js";function d(e){let n;try{n=r.readFileSync(e,"utf8")}catch(c){if(c&&typeof c=="object"&&"code"in c&&c.code==="ENOENT")return null;throw u("read",c)}try{const c=JSON.parse(n);return Number.isInteger(c.pid)&&Number(c.pid)>0&&typeof c.instanceId=="string"?{pid:Number(c.pid),instanceId:c.instanceId}:null}catch{return null}}function u(e,n){const c=n&&typeof n=="object"&&"code"in n?String(n.code):"unknown";return Object.assign(new Error(`daemon_instance_lock_${e}_failed: ${c}`),{code:c})}function I(e){const n=e.pid??process.pid,c=e.isProcessAlive??k,m=e.now??Date.now,y=e.malformedStaleAfterMs??5e3;r.mkdirSync(h.dirname(e.lockPath),{recursive:!0});for(let f=0;f<3;f+=1)try{const i=r.openSync(e.lockPath,"wx",384);r.writeFileSync(i,JSON.stringify({pid:n,instanceId:e.instanceId})),r.fsyncSync(i);let l=!1;return{acquired:!0,release:()=>{if(l)return;l=!0,r.closeSync(i);const o=d(e.lockPath);if(!(o?.pid!==n||o.instanceId!==e.instanceId))try{r.unlinkSync(e.lockPath)}catch{}}}}catch(i){if((i&&typeof i=="object"&&"code"in i?i.code:null)!=="EEXIST")throw i;const o=d(e.lockPath);let a;try{a=r.statSync(e.lockPath)}catch(t){if(t&&typeof t=="object"&&"code"in t&&t.code==="ENOENT")continue;throw u("inspect",t)}if(o&&c(o.pid))return{acquired:!1,ownerPid:o.pid};if(!o&&Math.max(0,m()-a.mtimeMs)<y)return{acquired:!1,ownerPid:null};try{const t=d(e.lockPath),s=r.statSync(e.lockPath);if(t?.pid!==o?.pid||t?.instanceId!==o?.instanceId||a.dev!==s.dev||a.ino!==s.ino||a.mtimeMs!==s.mtimeMs)continue;r.unlinkSync(e.lockPath)}catch(t){if(t&&typeof t=="object"&&"code"in t&&t.code==="ENOENT")continue;throw u("cleanup",t)}}return{acquired:!1,ownerPid:d(e.lockPath)?.pid??null}}export{I as acquireDaemonInstanceLock};
@@ -1,3 +1,4 @@
1
+ export declare function isDaemonProcessRunning(pid: number): boolean;
1
2
  export declare function isShennianRunServiceCommand(command: string): boolean;
2
3
  export declare function inferDaemonLauncherFromCommand(command: string): 'desktop-managed' | 'global-cli' | 'unknown';
3
4
  export declare function parseWindowsDaemonProcessJson(raw: string, excludePid?: number): number[];
@@ -1 +1 @@
1
- import{execFileSync as u}from"node:child_process";const d=5e3;function l(n){const e=n.replace(/\\/g,"/").trim();return f(e)||h(e)||x(e)||a(e,"shennian")||a(e,"npx")}function g(n){const e=n.replace(/\\/g,"/").toLowerCase();return e.includes("/cli-bridge.js")||e.includes("/resources/daemon/")?"desktop-managed":e.includes("/node_modules/shennian/")||e.includes("/bin/shennian")||e.includes(" shennian run-service")||e.includes(" shennian.js run-service")?"global-cli":"unknown"}function m(n,e=process.pid){let s;try{s=JSON.parse(p(n))}catch{return[]}return(Array.isArray(s)?s:s?[s]:[]).map(t=>{if(!t||typeof t!="object")return null;const i=t,r=Number(i.ProcessId),c=typeof i.CommandLine=="string"?i.CommandLine:"";return!Number.isInteger(r)||r<=0||r===e?null:l(c)?r:null}).filter(t=>typeof t=="number")}function p(n){const e=n.trim(),s=[...e].map((r,c)=>r==="["||r==="{"?c:-1).find(r=>r>=0)??-1;if(s<0)return e;const t=e[s]==="["?"]":"}",i=e.lastIndexOf(t);return i>=s?e.slice(s,i+1):e.slice(s)}function S(n=process.pid){try{const e=["$ProgressPreference = 'SilentlyContinue'","Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -match 'run-service' } | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress"].join("; "),s=u("powershell.exe",["-NoProfile","-NonInteractive","-Command",e],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:d,windowsHide:!0});return m(s,n)}catch{return[]}}function v(n){if(!Number.isSafeInteger(n)||n<=0)return null;try{const e=["$ProgressPreference = 'SilentlyContinue'",`Get-CimInstance Win32_Process -Filter "ProcessId = ${n}" | Select-Object -ExpandProperty CommandLine`].join("; ");return u("powershell.exe",["-NoProfile","-NonInteractive","-Command",e],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:d,windowsHide:!0}).trim()||null}catch{return null}}function f(n){return/(?:^|["\s])[^"\s]*updater-worker\.js["\s]/i.test(n)&&/(?:^|["\s])--service(?:["\s]|$)/i.test(n)&&/(?:^|["\s])run-service(?:["\s]|$)/i.test(n)}function h(n){return/(?:^|["\s])[^"\s]*shennianclient\.exe["\s]/i.test(n)&&/(?:^|["\s])[^"\s]*cli-bridge\.js["\s]/i.test(n)&&/(?:^|["\s])[^"\s]*\/daemon\/dist\/bin\/shennian\.js["\s]/i.test(n)&&/(?:^|["\s])run-service(?:["\s]|$)/i.test(n)}function x(n){return/^"[^"]*\/node(?:\.exe)?"\s+"?[^"]*(?:\/node_modules\/shennian\/|\/dist\/bin\/shennian\.js|\/bin\/shennian)"?\s+run-service(?:\s|$)/i.test(n)||/^(?:\S*\/)?node(?:\.exe)?\s+\S*(?:\/node_modules\/shennian\/|\/dist\/bin\/shennian\.js|\/bin\/shennian)\s+run-service(?:\s|$)/i.test(n)}function a(n,e){const s=e==="shennian"?`${e}(?:\\.cmd|\\.exe)?`:`${e}(?:\\.cmd|\\.exe)?`,o=e==="npx"?"\\s+(?:--yes\\s+)?shennian\\s+run-service(?:\\s|$)":"\\s+run-service(?:\\s|$)";return new RegExp(`^"[^"]*\\/${s}"${o}`,"i").test(n)||new RegExp(`^(?:\\S*\\/)?${s}${o}`,"i").test(n)}export{S as findRunningWindowsDaemonProcessIds,g as inferDaemonLauncherFromCommand,l as isShennianRunServiceCommand,m as parseWindowsDaemonProcessJson,v as readWindowsProcessCommand};
1
+ import{execFileSync as u}from"node:child_process";import l from"node:os";const d=5e3;function m(e){try{const n=["$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'",`try { $rows = @(Get-CimInstance Win32_Process -Filter 'ProcessId = ${e}' -ErrorAction Stop)`,`[ordered]@{ pid = ${e}; queryCompleted = $true; running = ($rows.Count -gt 0) } | ConvertTo-Json -Compress`,"} catch { exit 1 }"].join("; "),r=u("powershell.exe",["-NoProfile","-NonInteractive","-Command",n],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:d,windowsHide:!0}),t=JSON.parse(r.trim());return t?.pid===e&&t.queryCompleted===!0&&typeof t.running=="boolean"?t.running:null}catch{return null}}function $(e){if(!Number.isSafeInteger(e)||e<=0)return!1;try{return process.kill(e,0),!0}catch(n){const r=n&&typeof n=="object"&&"code"in n?n.code:null;return r==="ESRCH"?!1:(r==="EPERM"||r==="EACCES")&&l.platform()==="win32"?m(e)??!0:!0}}function p(e){const n=e.replace(/\\/g,"/").trim();return g(n)||h(n)||S(n)||a(n,"shennian")||a(n,"npx")}function y(e){const n=e.replace(/\\/g,"/").toLowerCase();return n.includes("/cli-bridge.js")||n.includes("/resources/daemon/")?"desktop-managed":n.includes("/node_modules/shennian/")||n.includes("/bin/shennian")||n.includes(" shennian run-service")||n.includes(" shennian.js run-service")?"global-cli":"unknown"}function f(e,n=process.pid){let r;try{r=JSON.parse(C(e))}catch{return[]}return(Array.isArray(r)?r:r?[r]:[]).map(i=>{if(!i||typeof i!="object")return null;const o=i,s=Number(o.ProcessId),c=typeof o.CommandLine=="string"?o.CommandLine:"";return!Number.isInteger(s)||s<=0||s===n?null:p(c)?s:null}).filter(i=>typeof i=="number")}function C(e){const n=e.trim(),r=[...n].map((s,c)=>s==="["||s==="{"?c:-1).find(s=>s>=0)??-1;if(r<0)return n;const i=n[r]==="["?"]":"}",o=n.lastIndexOf(i);return o>=r?n.slice(r,o+1):n.slice(r)}function w(e=process.pid){try{const n=["$ProgressPreference = 'SilentlyContinue'","Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -match 'run-service' } | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress"].join("; "),r=u("powershell.exe",["-NoProfile","-NonInteractive","-Command",n],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:d,windowsHide:!0});return f(r,e)}catch{return[]}}function v(e){if(!Number.isSafeInteger(e)||e<=0)return null;try{const n=["$ProgressPreference = 'SilentlyContinue'",`Get-CimInstance Win32_Process -Filter "ProcessId = ${e}" | Select-Object -ExpandProperty CommandLine`].join("; ");return u("powershell.exe",["-NoProfile","-NonInteractive","-Command",n],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:d,windowsHide:!0}).trim()||null}catch{return null}}function g(e){return/(?:^|["\s])[^"\s]*updater-worker\.js["\s]/i.test(e)&&/(?:^|["\s])--service(?:["\s]|$)/i.test(e)&&/(?:^|["\s])run-service(?:["\s]|$)/i.test(e)}function h(e){return/(?:^|["\s])[^"\s]*shennianclient\.exe["\s]/i.test(e)&&/(?:^|["\s])[^"\s]*cli-bridge\.js["\s]/i.test(e)&&/(?:^|["\s])[^"\s]*\/daemon\/dist\/bin\/shennian\.js["\s]/i.test(e)&&/(?:^|["\s])run-service(?:["\s]|$)/i.test(e)}function S(e){return/^"[^"]*\/node(?:\.exe)?"\s+"?[^"]*(?:\/node_modules\/shennian\/|\/dist\/bin\/shennian\.js|\/bin\/shennian)"?\s+run-service(?:\s|$)/i.test(e)||/^(?:\S*\/)?node(?:\.exe)?\s+\S*(?:\/node_modules\/shennian\/|\/dist\/bin\/shennian\.js|\/bin\/shennian)\s+run-service(?:\s|$)/i.test(e)}function a(e,n){const r=n==="shennian"?`${n}(?:\\.cmd|\\.exe)?`:`${n}(?:\\.cmd|\\.exe)?`,t=n==="npx"?"\\s+(?:--yes\\s+)?shennian\\s+run-service(?:\\s|$)":"\\s+run-service(?:\\s|$)";return new RegExp(`^"[^"]*\\/${r}"${t}`,"i").test(e)||new RegExp(`^(?:\\S*\\/)?${r}${t}`,"i").test(e)}export{w as findRunningWindowsDaemonProcessIds,y as inferDaemonLauncherFromCommand,$ as isDaemonProcessRunning,p as isShennianRunServiceCommand,f as parseWindowsDaemonProcessJson,v as readWindowsProcessCommand};
@@ -0,0 +1,28 @@
1
+ export declare function isSafeSnapshotEnvKey(key: string): boolean;
2
+ type ServiceLaunchMode = 'direct' | 'global-shim' | 'npx';
3
+ export type ServiceLaunchSpec = {
4
+ command: string;
5
+ args: string[];
6
+ mode: ServiceLaunchMode;
7
+ electronRunAsNode?: boolean;
8
+ };
9
+ export type DetachedLaunchSpec = {
10
+ command: string;
11
+ args: string[];
12
+ windowsVerbatimArguments?: boolean;
13
+ };
14
+ export declare function isEphemeralCliPath(candidate: string): boolean;
15
+ export declare function resolveServiceLaunchSpec(input: {
16
+ nodeExec: string;
17
+ scriptPath: string;
18
+ shennianCommandPath?: string | null;
19
+ npxPath?: string | null;
20
+ desktopBridgePath?: string | null;
21
+ }): ServiceLaunchSpec;
22
+ export declare function captureEnvForService(): Record<string, string>;
23
+ /**
24
+ * Save current env vars so the daemon can load them at startup.
25
+ * This is critical for launchd/systemd which start with minimal env.
26
+ */
27
+ export declare function saveEnvSnapshot(): void;
28
+ export {};
@@ -0,0 +1 @@
1
+ import o from"node:fs";import a from"node:path";import s from"node:os";import{resolveShennianPath as i}from"../config/index.js";import{buildAugmentedPath as N}from"../env-path.js";import{getPlatform as A,SHENNIAN_DIR as m}from"./daemon-state.js";const E=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 S(e){return E.has(e)}function t(e){const r=e.replace(/\\/g,"/").toLowerCase(),n=s.tmpdir().replace(/\\/g,"/").toLowerCase();return r.includes("/_npx/")||r.includes("/npm-cache/_npx/")||r.includes("/pnpm/dlx/")||r.startsWith(n.endsWith("/")?n:`${n}/`)}function I(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",electronRunAsNode:!0}:o.existsSync(e.scriptPath)&&(process.env.SHENNIAN_E2E_ISOLATED_DAEMON==="1"||!t(e.scriptPath))?{command:e.nodeExec,args:[e.scriptPath,"run-service"],mode:"direct"}:e.shennianCommandPath&&!t(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 T(){const e={};for(const r of E)process.env[r]&&(e[r]=process.env[r]);if(e.HOME??=s.homedir(),e.PATH=N({pathValue:e.PATH,env:e}),e.USER??=s.userInfo().username,A()==="win32"){const r=process.env.TEMP||process.env.TMP||s.tmpdir(),n=s.homedir();e.USERPROFILE??=n;const c=a.win32.parse(n);e.HOMEDRIVE??=c.root.replace(/[\\/]$/,"")||process.env.HOMEDRIVE||"",e.HOMEPATH??=n.slice((e.HOMEDRIVE||"").length)||process.env.HOMEPATH||"",e.USERNAME??=process.env.USERNAME||s.userInfo().username,e.COMPUTERNAME??=process.env.COMPUTERNAME||"",e.TMPDIR??=r,e.TEMP??=r,e.TMP??=r}else e.TMPDIR??="/tmp";return e}function O(){o.mkdirSync(m,{recursive:!0});const e={};for(const[r,n]of Object.entries(process.env))n!==void 0&&S(r)&&(e[r]=n);o.writeFileSync(i("env.json"),JSON.stringify(e,null,2))}export{T as captureEnvForService,t as isEphemeralCliPath,S as isSafeSnapshotEnvKey,I as resolveServiceLaunchSpec,O as saveEnvSnapshot};
@@ -1,5 +1,5 @@
1
1
  import type { DaemonStatus } from './daemon.js';
2
- export declare function isDaemonReadyStatus(status: Pick<DaemonStatus, 'running' | 'stale'>): boolean;
2
+ export declare function isDaemonReadyStatus(status: Pick<DaemonStatus, 'running' | 'stale' | 'adopted'>): boolean;
3
3
  export declare function waitForDaemonReadyStatus(readStatus: () => DaemonStatus, opts?: {
4
4
  timeoutMs?: number;
5
5
  intervalMs?: number;
@@ -1 +1 @@
1
- const T=2e4,c=500;function M(n){return n.running===!0&&n.stale!==!0}function s(n){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,n)}function u(n,t={}){const r=Math.max(0,t.timeoutMs??2e4),i=Math.max(1,t.intervalMs??500),e=t.now??Date.now,A=t.sleep??s,o=e()+r;let a=n();for(;!M(a)&&e()<o;){const _=Math.max(1,o-e());A(Math.min(i,_)),a=n()}return a}export{M as isDaemonReadyStatus,u as waitForDaemonReadyStatus};
1
+ const c=2e4,s=500;function M(n){return n.running===!0&&n.stale!==!0&&n.adopted!==!0}function T(n){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,n)}function u(n,e={}){const r=Math.max(0,e.timeoutMs??2e4),i=Math.max(1,e.intervalMs??500),t=e.now??Date.now,A=e.sleep??T,o=t()+r;let a=n();for(;!M(a)&&t()<o;){const _=Math.max(1,o-t());A(Math.min(i,_)),a=n()}return a}export{M as isDaemonReadyStatus,u as waitForDaemonReadyStatus};
@@ -0,0 +1,57 @@
1
+ export declare const SHENNIAN_DIR: string;
2
+ export declare const PID_FILE: string;
3
+ export declare const LOG_FILE: string;
4
+ export declare const REMOTE_ACCESS_DISABLED_FILE: string;
5
+ export declare const LAUNCHER_FILE: string;
6
+ export type Platform = 'darwin' | 'linux' | 'win32';
7
+ export type DaemonLauncher = 'desktop-managed' | 'global-cli' | 'unknown';
8
+ export type DaemonStatus = {
9
+ running: boolean;
10
+ pid: number | null;
11
+ stale: boolean;
12
+ remoteAccessDisabled: boolean;
13
+ launcher: DaemonLauncher;
14
+ daemonVersion?: string;
15
+ platform: Platform;
16
+ shennianDir: string;
17
+ pidFile: string;
18
+ logFile: string;
19
+ machineId?: string;
20
+ paired?: boolean;
21
+ serverUrl?: string;
22
+ instanceId?: string;
23
+ adopted?: boolean;
24
+ };
25
+ export declare function getPlatform(): Platform;
26
+ type DaemonPidRecord = {
27
+ pid: number;
28
+ instanceId?: string;
29
+ version?: string;
30
+ launcher?: DaemonLauncher;
31
+ startedAt?: string;
32
+ adopted?: boolean;
33
+ };
34
+ export declare function readPidRecord(): DaemonPidRecord | null;
35
+ export declare function isRunning(pid: number): boolean;
36
+ export declare function waitForPidExitSync(pid: number, timeoutMs?: number): boolean;
37
+ export declare function isRemoteAccessDisabled(): boolean;
38
+ export declare function clearRemoteAccessDisabled(): void;
39
+ export declare function getCurrentProcessDaemonLauncher(): DaemonLauncher;
40
+ export declare function createDaemonInstanceId(): string;
41
+ export declare function writeDaemonPid(pid: number, instanceId: string, meta?: {
42
+ version?: string;
43
+ launcher?: DaemonLauncher;
44
+ adopted?: boolean;
45
+ }): void;
46
+ export declare function clearDaemonPidIfOwner(pid: number, instanceId: string): void;
47
+ export declare function writeDaemonLauncher(pid: number, launcher?: DaemonLauncher, instanceId?: string): void;
48
+ export declare function clearDaemonLauncher(instanceId?: string): void;
49
+ export declare function recordStartedDaemon(childPid: number | undefined): void;
50
+ export declare function findRunningDaemonProcessIds(excludePid?: number): number[];
51
+ export declare function isIsolatedDaemonE2eInstance(env?: NodeJS.ProcessEnv, shennianDir?: string, tempDir?: string, defaultDir?: string): boolean;
52
+ export declare function shouldDiscoverGlobalDaemonProcesses(env?: NodeJS.ProcessEnv, shennianDir?: string): boolean;
53
+ export declare function shouldInstallPlatformService(env?: NodeJS.ProcessEnv, shennianDir?: string): boolean;
54
+ export declare function getDaemonStatus(opts?: {
55
+ cleanupStale?: boolean;
56
+ }): DaemonStatus;
57
+ export {};
@@ -0,0 +1 @@
1
+ import i from"node:fs";import c from"node:path";import f from"node:os";import{execSync as y}from"node:child_process";import{randomUUID as A}from"node:crypto";import{getShennianDir as b,loadConfig as O,resolveShennianPath as p}from"../config/index.js";import{isDesktopDistribution as P}from"../runtime-distribution.js";import{findRunningWindowsDaemonProcessIds as k,inferDaemonLauncherFromCommand as D,isDaemonProcessRunning as L,isShennianRunServiceCommand as _,readWindowsProcessCommand as F}from"./daemon-process.js";const u=b(),l=p("daemon.pid"),R=p("daemon.log"),w=p("remote-access.disabled"),m=p("daemon-launcher.json");function h(){const e=f.platform();return e==="darwin"||e==="linux"||e==="win32"?e:"linux"}function C(e){const n=e.trim();if(!n)return null;if(n.startsWith("{"))try{const t=JSON.parse(n),o=Number(t.pid);return!Number.isInteger(o)||o<=0?null:{pid:o,...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 N(){try{return C(i.readFileSync(l,"utf-8"))}catch{return null}}function S(e){return L(e)}function Q(e,n=3e3){const r=Date.now();for(;Date.now()-r<n;){if(!S(e))return!0;Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,100)}return!S(e)}function H(){try{return i.lstatSync(w),!0}catch(e){return!(e&&typeof e=="object"&&"code"in e&&e.code==="ENOENT")}}function X(){try{i.unlinkSync(w)}catch(e){if(e&&typeof e=="object"&&"code"in e&&e.code==="ENOENT")return;throw e}}function v(){return P()||process.env.SHENNIAN_DESKTOP_CLI_SCRIPT?"desktop-managed":"global-cli"}function T(){return`${process.pid}-${Date.now()}-${A()}`}function U(e,n,r={}){i.mkdirSync(u,{recursive:!0}),i.writeFileSync(l,JSON.stringify({pid:e,instanceId:n,...r.version?{version:r.version}:{},launcher:r.launcher??v(),...r.adopted?{adopted:!0}:{},startedAt:new Date().toISOString()},null,2))}function Y(e,n){const r=N();if(!(r?.pid!==e||r.instanceId!==n))try{i.unlinkSync(l)}catch{}}function x(e,n=v(),r){i.mkdirSync(u,{recursive:!0}),i.writeFileSync(m,JSON.stringify({pid:e,launcher:n,...r?{instanceId:r}:{},updatedAt:new Date().toISOString()},null,2))}function Z(e){if(e)try{if(JSON.parse(i.readFileSync(m,"utf-8")).instanceId!==e)return}catch{return}try{i.unlinkSync(m)}catch{}}function ee(e){e&&x(e)}function $(e,n){if(!e||!n)return"unknown";try{const r=JSON.parse(i.readFileSync(m,"utf-8"));if(r.pid!==e)return"unknown";if(r.launcher==="desktop-managed"||r.launcher==="global-cli")return r.launcher}catch{}return I(e)}function I(e){if(h()==="win32"){const n=F(e);return n?D(n):"unknown"}try{const n=y(`ps -p ${e} -o command=`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:1e3,windowsHide:!0}).replace(/\\/g,"/");return D(n)}catch{}return"unknown"}function J(e=process.pid){if(h()==="win32")return k(e);try{return y("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 o=Number(t[1]),d=t[2];return!Number.isInteger(o)||o===e?null:_(d)?o:null}).filter(r=>typeof r=="number")}catch{return[]}}function E(e=process.env,n=u,r=f.tmpdir(),t=c.join(f.homedir(),".shennian")){if(e.SHENNIAN_E2E_ISOLATED_DAEMON!=="1"||!e.SHENNIAN_HOME?.trim()||c.resolve(n)===c.resolve(t))return!1;const o=c.relative(c.resolve(r),c.resolve(n));return o!==""&&o!==".."&&!o.startsWith(`..${c.sep}`)&&!c.isAbsolute(o)||c.resolve(n)===c.resolve(e.SHENNIAN_HOME)}function j(e=process.env,n=u){return!E(e,n)}function ne(e=process.env,n=u){return!E(e,n)}function re(e={}){let n=N(),r=n?.pid??null,t=r!==null&&S(r),o=r!==null&&!t,d=n?.adopted===!0;const s=O();if(o&&e.cleanupStale){try{i.unlinkSync(l)}catch{}n=null,r=null,t=!1,o=!1}if(!t&&j()){const a=J()[0];if(a&&(r=a,t=!0,o=!1,d=!0,e.cleanupStale)){const g=T();U(a,g,{launcher:I(a),adopted:!0}),x(a,I(a)),n={pid:a,instanceId:g,adopted:!0}}}return{running:t,pid:r,stale:o,remoteAccessDisabled:H(),launcher:$(r,t),...t&&n?.pid===r&&n.version?{daemonVersion:n.version}:{},platform:h(),shennianDir:u,pidFile:l,logFile:R,...n?.instanceId?{instanceId:n.instanceId}:{},...d?{adopted:!0}:{},...s.machineId?{machineId:s.machineId}:{},paired:!!(s.machineToken&&s.machineId),...s.serverUrl?{serverUrl:s.serverUrl}:{}}}export{m as LAUNCHER_FILE,R as LOG_FILE,l as PID_FILE,w as REMOTE_ACCESS_DISABLED_FILE,u as SHENNIAN_DIR,Z as clearDaemonLauncher,Y as clearDaemonPidIfOwner,X as clearRemoteAccessDisabled,T as createDaemonInstanceId,J as findRunningDaemonProcessIds,v as getCurrentProcessDaemonLauncher,re as getDaemonStatus,h as getPlatform,E as isIsolatedDaemonE2eInstance,H as isRemoteAccessDisabled,S as isRunning,N as readPidRecord,ee as recordStartedDaemon,j as shouldDiscoverGlobalDaemonProcesses,ne as shouldInstallPlatformService,Q as waitForPidExitSync,x as writeDaemonLauncher,U as writeDaemonPid};
@@ -1,6 +1,7 @@
1
1
  type WindowsLaunchSpec = {
2
2
  command: string;
3
3
  args: string[];
4
+ electronRunAsNode?: boolean;
4
5
  };
5
6
  export declare function escapeXml(text: string): string;
6
7
  export declare function quoteSystemdArg(text: string): string;
@@ -12,6 +13,7 @@ export declare function buildWindowsScheduledTaskXml(input: {
12
13
  userId: string;
13
14
  command: string;
14
15
  arguments: string[];
16
+ desktopManaged?: boolean;
15
17
  }): string;
16
18
  export declare function buildWindowsScheduledTaskCommands(input: {
17
19
  taskName: string;
@@ -20,6 +22,12 @@ export declare function buildWindowsScheduledTaskCommands(input: {
20
22
  create: string;
21
23
  run: string;
22
24
  };
25
+ /** Managed Desktop cannot promise durable autostart after a detached fallback. */
26
+ export declare function registerWindowsScheduledTask(input: {
27
+ taskName: string;
28
+ xmlPath: string;
29
+ desktopManaged: boolean;
30
+ }, execute: (command: string) => void): boolean;
23
31
  export declare function buildWindowsScheduledTaskSuspendCommands(taskName: string): {
24
32
  disable: string;
25
33
  end: string;
@@ -1,20 +1,20 @@
1
- import i from"node:path";function s(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function m(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function t(e){return`"${e.replace(/"/g,'""')}"`}function l(e){return e.replace(/"/g,'""')}function o(e){return s(e)}function d(e){const n=i.extname(e).toLowerCase();return n===".cmd"||n===".bat"}function g(e,n){const r=[e.command,...e.args].map(t).join(" ");return["@echo off","setlocal",'if not defined SHENNIAN_HOME set "SHENNIAN_HOME=%~dp0."',`${d(e.command)?`call ${r}`:r} >> ${t(n)} 2>&1`,""].join(`\r
2
- `)}function p(e){return['Set shell = CreateObject("WScript.Shell")',`shell.Run Chr(34) & "${l(e)}" & Chr(34), 0, False`,""].join(`\r
3
- `)}function S(e){const n=e.arguments.join(" ");return`<?xml version="1.0" encoding="UTF-16"?>
1
+ import l from"node:path";function d(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function f(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function r(e){return`"${e.replace(/"/g,'""')}"`}function c(e){return e.replace(/"/g,'""')}function o(e){return d(e)}function u(e){const n=l.extname(e).toLowerCase();return n===".cmd"||n===".bat"}function S(e,n){const t=i=>r(i.replace(/%/g,"%%")),a=[e.command,...e.args].map(t).join(" "),s=u(e.command)?`call ${a}`:a;return["@echo off","chcp 65001 >nul","setlocal DisableDelayedExpansion",...e.electronRunAsNode?['set "ELECTRON_RUN_AS_NODE=1"']:[],'if not defined SHENNIAN_HOME set "SHENNIAN_HOME=%~dp0."',`${s} >> ${t(n)} 2>&1`,""].join(`\r
2
+ `)}function h(e){return['Set shell = CreateObject("WScript.Shell")',`shell.Run Chr(34) & "${c(e)}" & Chr(34), 0, False`,""].join(`\r
3
+ `)}function I(e){const n=e.arguments.join(" ");return`<?xml version="1.0" encoding="UTF-16"?>
4
4
  <Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
5
5
  <RegistrationInfo>
6
6
  <Description>Shennian Agent Daemon</Description>
7
7
  </RegistrationInfo>
8
8
  <Triggers>
9
- <BootTrigger>
9
+ ${e.desktopManaged?"":`<BootTrigger>
10
10
  <Enabled>true</Enabled>
11
11
  <Delay>PT15S</Delay>
12
- </BootTrigger>
12
+ </BootTrigger>`}
13
13
  <LogonTrigger>
14
14
  <Enabled>true</Enabled>
15
15
  <UserId>${o(e.userId)}</UserId>
16
16
  </LogonTrigger>
17
- <EventTrigger>
17
+ ${e.desktopManaged?"":`<EventTrigger>
18
18
  <Enabled>true</Enabled>
19
19
  <Subscription><![CDATA[
20
20
  <QueryList>
@@ -22,12 +22,12 @@ import i from"node:path";function s(e){return e.replace(/&/g,"&amp;").replace(/<
22
22
  <Select Path="System">*[System[Provider[@Name='Microsoft-Windows-Power-Troubleshooter'] and EventID=1]]</Select>
23
23
  </Query>
24
24
  </QueryList>]]></Subscription>
25
- </EventTrigger>
25
+ </EventTrigger>`}
26
26
  </Triggers>
27
27
  <Principals>
28
28
  <Principal id="Author">
29
29
  <UserId>${o(e.userId)}</UserId>
30
- <LogonType>S4U</LogonType>
30
+ <LogonType>${e.desktopManaged?"InteractiveToken":"S4U"}</LogonType>
31
31
  <RunLevel>LeastPrivilege</RunLevel>
32
32
  </Principal>
33
33
  </Principals>
@@ -46,7 +46,7 @@ import i from"node:path";function s(e){return e.replace(/&/g,"&amp;").replace(/<
46
46
  <Enabled>true</Enabled>
47
47
  <Hidden>true</Hidden>
48
48
  <RunOnlyIfIdle>false</RunOnlyIfIdle>
49
- <WakeToRun>true</WakeToRun>
49
+ <WakeToRun>${!e.desktopManaged}</WakeToRun>
50
50
  <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
51
51
  <Priority>7</Priority>
52
52
  <RestartOnFailure>
@@ -60,4 +60,4 @@ import i from"node:path";function s(e){return e.replace(/&/g,"&amp;").replace(/<
60
60
  <Arguments>${o(n)}</Arguments>
61
61
  </Exec>
62
62
  </Actions>
63
- </Task>`}function f(e){return{create:`schtasks /create /tn ${t(e.taskName)} /xml ${t(e.xmlPath)} /f`,run:`schtasks /run /tn ${t(e.taskName)}`}}function c(e){return{disable:`schtasks /change /tn ${t(e)} /disable`,end:`schtasks /end /tn ${t(e)}`}}function I(e,n){const r=c(e);for(const a of[r.disable,r.end])try{n(a)}catch{}}export{g as buildWindowsLauncherCommand,f as buildWindowsScheduledTaskCommands,c as buildWindowsScheduledTaskSuspendCommands,S as buildWindowsScheduledTaskXml,p as buildWindowsStartupVbs,s as escapeXml,d as isWindowsCmdScript,t as quoteCmdArg,m as quoteSystemdArg,I as suspendWindowsScheduledTask};
63
+ </Task>`}function m(e){return{create:`schtasks /create /tn ${r(e.taskName)} /xml ${r(e.xmlPath)} /f`,run:`schtasks /run /tn ${r(e.taskName)}`}}function b(e,n){const t=m(e);try{return n(t.create),n(t.run),!0}catch{if(e.desktopManaged)throw new Error("windows_autostart_registration_failed: Open Shennian Desktop in your normal Windows login and retry. An existing administrator-owned ShennianAgent task may require administrator-assisted migration; no background startup fallback was installed.");return!1}}function g(e){return{disable:`schtasks /change /tn ${r(e)} /disable`,end:`schtasks /end /tn ${r(e)}`}}function T(e,n){const t=g(e);for(const a of[t.disable,t.end])try{n(a)}catch{}}export{S as buildWindowsLauncherCommand,m as buildWindowsScheduledTaskCommands,g as buildWindowsScheduledTaskSuspendCommands,I as buildWindowsScheduledTaskXml,h as buildWindowsStartupVbs,d as escapeXml,u as isWindowsCmdScript,r as quoteCmdArg,f as quoteSystemdArg,b as registerWindowsScheduledTask,T as suspendWindowsScheduledTask};
@@ -2,46 +2,10 @@ import { spawn } from 'node:child_process';
2
2
  import type { Command } from 'commander';
3
3
  export { buildWindowsLauncherCommand, buildWindowsScheduledTaskCommands, buildWindowsScheduledTaskSuspendCommands, buildWindowsScheduledTaskXml, buildWindowsStartupVbs, suspendWindowsScheduledTask, } from './daemon-windows.js';
4
4
  export { inferDaemonLauncherFromCommand, isShennianRunServiceCommand } from './daemon-process.js';
5
- export declare function isSafeSnapshotEnvKey(key: string): boolean;
6
- type Platform = 'darwin' | 'linux' | 'win32';
7
- type ServiceLaunchMode = 'direct' | 'global-shim' | 'npx';
8
- type DaemonLauncher = 'desktop-managed' | 'global-cli' | 'unknown';
9
- export type DaemonStatus = {
10
- running: boolean;
11
- pid: number | null;
12
- stale: boolean;
13
- remoteAccessDisabled: boolean;
14
- launcher: DaemonLauncher;
15
- platform: Platform;
16
- shennianDir: string;
17
- pidFile: string;
18
- logFile: string;
19
- machineId?: string;
20
- paired?: boolean;
21
- serverUrl?: string;
22
- instanceId?: string;
23
- adopted?: boolean;
24
- };
25
- export type ServiceLaunchSpec = {
26
- command: string;
27
- args: string[];
28
- mode: ServiceLaunchMode;
29
- };
30
- export type DetachedLaunchSpec = {
31
- command: string;
32
- args: string[];
33
- windowsVerbatimArguments?: boolean;
34
- };
35
- export declare function isEphemeralCliPath(candidate: string): boolean;
36
- export declare function resolveServiceLaunchSpec(input: {
37
- nodeExec: string;
38
- scriptPath: string;
39
- shennianCommandPath?: string | null;
40
- npxPath?: string | null;
41
- desktopBridgePath?: string | null;
42
- }): ServiceLaunchSpec;
43
- export declare function isRemoteAccessDisabled(): boolean;
44
- export declare function clearRemoteAccessDisabled(): void;
5
+ import { type Platform, type DaemonStatus } from './daemon-state.js';
6
+ import { type ServiceLaunchSpec, type DetachedLaunchSpec } from './daemon-service-spec.js';
7
+ export { isRemoteAccessDisabled, clearRemoteAccessDisabled, getCurrentProcessDaemonLauncher, createDaemonInstanceId, writeDaemonPid, clearDaemonPidIfOwner, writeDaemonLauncher, clearDaemonLauncher, recordStartedDaemon, findRunningDaemonProcessIds, isIsolatedDaemonE2eInstance, shouldDiscoverGlobalDaemonProcesses, shouldInstallPlatformService, getDaemonStatus, type DaemonStatus } from './daemon-state.js';
8
+ export { isSafeSnapshotEnvKey, isEphemeralCliPath, resolveServiceLaunchSpec, captureEnvForService, saveEnvSnapshot, type ServiceLaunchSpec, type DetachedLaunchSpec } from './daemon-service-spec.js';
45
9
  export type RemoteAccessPausePreparation = {
46
10
  disabledAt: string;
47
11
  autoStartDisabled: boolean;
@@ -70,26 +34,7 @@ export declare function prepareRemoteAccessPause(options?: RemoteAccessPauseOpti
70
34
  * KeepAlive/Restart policy from relaunching the current daemon in the interim.
71
35
  */
72
36
  export declare function stopPreparedRemoteAccessService(options?: Pick<RemoteAccessPauseOptions, 'platform' | 'servicePresent' | 'execCommand'>): RemoteAccessServiceStopResult;
73
- export declare function getCurrentProcessDaemonLauncher(): DaemonLauncher;
74
- export declare function createDaemonInstanceId(): string;
75
- export declare function writeDaemonPid(pid: number, instanceId: string, meta?: {
76
- version?: string;
77
- launcher?: DaemonLauncher;
78
- adopted?: boolean;
79
- }): void;
80
- export declare function clearDaemonPidIfOwner(pid: number, instanceId: string): void;
81
- export declare function writeDaemonLauncher(pid: number, launcher?: DaemonLauncher, instanceId?: string): void;
82
- export declare function clearDaemonLauncher(instanceId?: string): void;
83
- export declare function recordStartedDaemon(childPid: number | undefined): void;
84
- export declare function findRunningDaemonProcessIds(excludePid?: number): number[];
85
- export declare function isIsolatedDaemonE2eInstance(env?: NodeJS.ProcessEnv, shennianDir?: string, tempDir?: string, defaultDir?: string): boolean;
86
- export declare function shouldDiscoverGlobalDaemonProcesses(env?: NodeJS.ProcessEnv, shennianDir?: string): boolean;
87
- export declare function shouldInstallPlatformService(env?: NodeJS.ProcessEnv, shennianDir?: string): boolean;
88
- export declare function getDaemonStatus(opts?: {
89
- cleanupStale?: boolean;
90
- }): DaemonStatus;
91
37
  export declare function buildDaemonSpawnOptions(launch: DetachedLaunchSpec, logFd: number, env?: NodeJS.ProcessEnv): Parameters<typeof spawn>[2];
92
- export declare function captureEnvForService(): Record<string, string>;
93
38
  export declare function buildMacLaunchdPlist(input?: {
94
39
  launch?: ServiceLaunchSpec;
95
40
  }): string;
@@ -99,11 +44,6 @@ export declare function buildSystemdUnit(): string;
99
44
  type LaunchdCommandExecutor = (command: string) => void;
100
45
  export declare function getLaunchdServiceTarget(uid?: number | string): string;
101
46
  export declare function reloadLaunchdAgent(execCommand?: LaunchdCommandExecutor): boolean;
102
- /**
103
- * Save current env vars so the daemon can load them at startup.
104
- * This is critical for launchd/systemd which start with minimal env.
105
- */
106
- export declare function saveEnvSnapshot(): void;
107
47
  export declare function startDaemonProcess(opts?: {
108
48
  quiet?: boolean;
109
49
  }): void;