shennian 0.4.68 → 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.
- package/dist/publish-build-manifest.json +138 -78
- package/dist/src/agent-env.js +4 -4
- package/dist/src/agents/adapter.d.ts +7 -3
- package/dist/src/agents/auth-status.d.ts +4 -0
- package/dist/src/agents/auth-status.js +2 -0
- package/dist/src/agents/codex-protocol.d.ts +103 -0
- package/dist/src/agents/codex-protocol.js +3 -0
- package/dist/src/agents/codex-runtime.d.ts +91 -0
- package/dist/src/agents/codex-runtime.js +14 -0
- package/dist/src/agents/codex.d.ts +15 -91
- package/dist/src/agents/codex.js +2 -17
- package/dist/src/agents/command-spec.js +4 -3
- package/dist/src/agents/detect.js +1 -1
- package/dist/src/agents/manager.d.ts +4 -3
- package/dist/src/agents/manager.js +4 -4
- package/dist/src/agents/model-registry/cache.js +1 -1
- package/dist/src/agents/model-registry/discovery.js +3 -3
- package/dist/src/agents/model-registry/opencode-api.d.ts +2 -0
- package/dist/src/agents/model-registry/opencode-api.js +1 -0
- package/dist/src/agents/model-registry/parsers.d.ts +1 -0
- package/dist/src/agents/model-registry/parsers.js +4 -4
- package/dist/src/agents/model-registry/service.js +1 -1
- package/dist/src/agents/opencode.d.ts +4 -0
- package/dist/src/agents/opencode.js +1 -1
- package/dist/src/commands/agent-readiness.d.ts +17 -0
- package/dist/src/commands/agent-readiness.js +2 -0
- package/dist/src/commands/agent.js +2 -2
- package/dist/src/commands/daemon-instance-lock.js +1 -1
- package/dist/src/commands/daemon-process.d.ts +1 -0
- package/dist/src/commands/daemon-process.js +1 -1
- package/dist/src/commands/daemon-service-spec.d.ts +28 -0
- package/dist/src/commands/daemon-service-spec.js +1 -0
- package/dist/src/commands/daemon-start-wait.d.ts +1 -1
- package/dist/src/commands/daemon-start-wait.js +1 -1
- package/dist/src/commands/daemon-state.d.ts +57 -0
- package/dist/src/commands/daemon-state.js +1 -0
- package/dist/src/commands/daemon-windows.d.ts +8 -0
- package/dist/src/commands/daemon-windows.js +10 -10
- package/dist/src/commands/daemon.d.ts +4 -64
- package/dist/src/commands/daemon.js +13 -13
- package/dist/src/commands/upgrade.js +1 -1
- package/dist/src/daemon-ipc/agent-readiness.d.ts +14 -0
- package/dist/src/daemon-ipc/agent-readiness.js +1 -0
- package/dist/src/daemon-ipc/control.d.ts +1 -1
- package/dist/src/daemon-ipc/control.js +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/native-fusion/local-repository.d.ts +6 -1
- package/dist/src/native-fusion/local-repository.js +2 -2
- package/dist/src/native-fusion/service.d.ts +2 -0
- package/dist/src/native-fusion/service.js +2 -2
- package/dist/src/native-fusion/source-visibility-audit.d.ts +16 -0
- package/dist/src/native-fusion/source-visibility-audit.js +1 -0
- package/dist/src/native-fusion/source-visibility.d.ts +25 -0
- package/dist/src/native-fusion/source-visibility.js +1 -0
- package/dist/src/native-fusion/state.d.ts +1 -0
- package/dist/src/native-fusion/state.js +2 -2
- package/dist/src/native-fusion/types.d.ts +5 -0
- package/dist/src/room/managed-room-binding.d.ts +2 -0
- package/dist/src/room/managed-room-binding.js +1 -1
- package/dist/src/room/room-binding-client.d.ts +1 -0
- package/dist/src/room/room-binding-client.js +1 -1
- package/dist/src/runtime-distribution.d.ts +13 -0
- package/dist/src/runtime-distribution.js +1 -0
- package/dist/src/security/managed-agent-policy.d.ts +7 -0
- package/dist/src/security/managed-agent-policy.js +1 -1
- package/dist/src/session/handlers/agent-workspace-validation.d.ts +1 -0
- package/dist/src/session/handlers/agent-workspace-validation.js +1 -1
- package/dist/src/session/handlers/agents.d.ts +7 -1
- package/dist/src/session/handlers/agents.js +1 -1
- package/dist/src/session/handlers/chat-context.d.ts +31 -0
- package/dist/src/session/handlers/chat-context.js +1 -0
- package/dist/src/session/handlers/chat-events.d.ts +1 -1
- package/dist/src/session/handlers/chat-events.js +2 -2
- package/dist/src/session/handlers/chat-session-lifecycle.d.ts +2 -2
- package/dist/src/session/handlers/chat-session-lifecycle.js +1 -1
- package/dist/src/session/handlers/chat.d.ts +3 -29
- package/dist/src/session/handlers/chat.js +1 -1
- package/dist/src/session/manager.js +2 -2
- package/dist/src/session/queue-helpers.js +2 -2
- package/dist/src/session/queue-message.d.ts +2 -0
- package/dist/src/session/queue.d.ts +7 -1
- package/dist/src/session/queue.js +1 -1
- package/dist/src/session/queued-chat-dispatch.d.ts +4 -1
- package/dist/src/session/queued-chat-dispatch.js +1 -1
- package/dist/src/session/store.d.ts +4 -2
- package/dist/src/session/store.js +2 -2
- package/dist/src/session/types.d.ts +1 -0
- package/dist/src/upgrade/engine.js +2 -2
- package/dist/src/upgrade/scheduler.js +1 -1
- package/dist/src/upgrade/updater-launcher.js +3 -3
- package/node_modules/@shennian/wire/dist/room.d.ts +2 -0
- package/node_modules/@shennian/wire/dist/session-sync.d.ts +2 -1
- package/node_modules/@shennian/wire/dist/session.d.ts +19 -1
- package/node_modules/@shennian/wire/dist/session.js +8 -0
- package/package.json +1 -1
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createInterface as b}from"node:readline";import{resolveBuiltinCommand as l,spawnResolvedCommand as M}from"../command-spec.js";import{fallbackClaudeAliasModels as k,discoverClaudeAliasModelsFromEnv as E,fallbackCodexModels as R,fallbackWorkBuddyModels as x,fallbackGeminiModels as _,parseCodexAppServerModels as O,parseCursorModels as A,parseOpenCodeModels as I}from"./parsers.js";import{runResolvedCommand as m}from"./runner.js";import{DISCOVERY_WORKDIR as w}from"./types.js";import{buildAgentProcessEnv as C,readLatestUserEnv as S}from"../../agent-env.js";import{CODEX_APP_SERVER_CLIENT_INFO as T}from"../codex-utils.js";import{PiRpcClient as P}from"../pi-rpc-client.js";import{loadConfig as $}from"../../config/index.js";function v(r,e,t,s,n,i){return r.stdin?new Promise((o,a)=>{const c=setTimeout(()=>{e.delete(t),a(new Error(`codex app-server request timed out: ${s}`))},i);e.set(t,{resolve:o,reject:a,timer:c}),r.stdin.write(`${JSON.stringify({id:t,method:s,params:n})}
|
|
2
|
-
`,p=>{p&&(clearTimeout(c),e.delete(t),a(p))})}):Promise.reject(new Error("codex app-server stdin unavailable"))}async function
|
|
3
|
-
${n.stderr}`)?s:s.filter(i=>i.id!=="fable")}async function
|
|
1
|
+
import{createInterface as b}from"node:readline";import{resolveBuiltinCommand as l,spawnResolvedCommand as M}from"../command-spec.js";import{fallbackClaudeAliasModels as k,discoverClaudeAliasModelsFromEnv as E,fallbackCodexModels as R,fallbackWorkBuddyModels as x,fallbackGeminiModels as _,parseCodexAppServerModels as O,parseCursorModels as A,parseOpenCodeModels as I}from"./parsers.js";import{runResolvedCommand as m}from"./runner.js";import{DISCOVERY_WORKDIR as w}from"./types.js";import{buildAgentProcessEnv as C,readLatestUserEnv as S}from"../../agent-env.js";import{CODEX_APP_SERVER_CLIENT_INFO as T}from"../codex-utils.js";import{PiRpcClient as P}from"../pi-rpc-client.js";import{loadConfig as $}from"../../config/index.js";import{discoverOpenCodeModelsViaApi as D}from"./opencode-api.js";function v(r,e,t,s,n,i){return r.stdin?new Promise((o,a)=>{const c=setTimeout(()=>{e.delete(t),a(new Error(`codex app-server request timed out: ${s}`))},i);e.set(t,{resolve:o,reject:a,timer:c}),r.stdin.write(`${JSON.stringify({id:t,method:s,params:n})}
|
|
2
|
+
`,p=>{p&&(clearTimeout(c),e.delete(t),a(p))})}):Promise.reject(new Error("codex app-server stdin unavailable"))}async function L(r){const e=M(r,["app-server","--listen","stdio://"],{cwd:w,stdio:["pipe","pipe","pipe"],env:C({NO_COLOR:"1"})}),t=new Map;let s=1;b({input:e.stdout}).on("line",i=>{if(!i.trim())return;let o;try{o=JSON.parse(i)}catch{return}if(o.id==null)return;const a=t.get(o.id);a&&(clearTimeout(a.timer),t.delete(o.id),o.error?a.reject(new Error(o.error.message||`codex app-server error ${o.error.code??""}`.trim())):a.resolve(o.result))});try{await v(e,t,s++,"initialize",{clientInfo:T,capabilities:{experimentalApi:!0}},1e4);const[i,o]=await Promise.all([v(e,t,s++,"model/list",{},15e3),v(e,t,s++,"config/read",{},15e3).catch(()=>null)]),a=typeof o=="object"&&o!==null&&"config"in o?o.config:void 0;return O({...typeof i=="object"&&i!==null?i:{},config:a})}finally{for(const[i,o]of t)clearTimeout(o.timer),o.reject(new Error("codex app-server stopped")),t.delete(i);e.kill("SIGTERM"),setTimeout(()=>e.kill("SIGKILL"),1e3).unref()}}async function q(){const r=l("cursor");if(!r)return[];const e=await m(r,["--list-models"]);return A(e.stdout)}async function j(){const r=l("opencode");if(!r)return[];const e=await D().catch(()=>[]);if(e.length>0)return e;const t=await m(r,["models"]);return I(t.stdout)}async function G(){const r={id:"shennian-dashscope/deepseek-v4-flash-0731",name:"DeepSeek V4 Flash",provider:"shennian-dashscope",isDefault:!0,supportedReasoningEfforts:["low","high","max"].map(n=>({id:n,name:n})),defaultReasoningEffort:"high"},e=l("pi-coding-agent");if(!e)return[];if($().machineToken?.trim())return[r];const t=M(e,["--mode","rpc","--no-session","--offline","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--no-tools"],{cwd:w,stdio:["pipe","pipe","pipe"],env:C({NO_COLOR:"1"})}),s=new P(t,{requestTimeoutMs:1e4});try{const[n,i]=await Promise.all([s.request("get_available_models"),s.request("get_state")]),o=n.data&&typeof n.data=="object"?n.data:{},a=i.data&&typeof i.data=="object"?i.data:{},c=typeof a.model?.id=="string"&&typeof a.model.provider=="string"?`${a.model.provider}/${a.model.id}`:null;return Array.isArray(o.models)?o.models.flatMap(f=>{if(!f||typeof f!="object")return[];const d=f;if(typeof d.id!="string"||typeof d.provider!="string")return[];const h=`${d.provider}/${d.id}`,g=d.reasoning===!0?["off","minimal","low","medium","high","xhigh","max"].map(y=>({id:y,name:y})):void 0;return[{id:h,name:typeof d.name=="string"&&d.name.trim()?d.name:d.id,provider:d.provider,isDefault:h===c,...g?{supportedReasoningEfforts:g,defaultReasoningEffort:"medium"}:{}}]}):[]}catch{return[]}finally{s.close(),t.kill("SIGTERM"),setTimeout(()=>t.kill("SIGKILL"),1e3).unref()}}async function N(){const r=l("claude");if(!r)return[];const e=S(),t=E(e);if(t.length>0)return t;const s=k(e),n=await m(r,["--help"],3e3).catch(()=>null);return!n||/\bfable\b/i.test(`${n.stdout}
|
|
3
|
+
${n.stderr}`)?s:s.filter(i=>i.id!=="fable")}async function V(){const r=l("codex");if(!r)return[];const e=await L(r).catch(()=>[]);return e.length>0?e:R()}async function B(){return l("gemini")?_():[]}const u=[{id:"qwen3.6-plus",name:"Qwen 3.6 Plus",provider:"dashscope",isDefault:!0}],F=[{id:"codex",name:"Codex",provider:"shennian",isDefault:!0},{id:"claude",name:"Claude Code",provider:"shennian"}];async function K(r){if(!r.serverUrl||!r.authToken)return u;try{const e=await fetch(`${r.serverUrl.replace(/\/$/,"")}/api/models`,{headers:{Authorization:`Bearer ${r.authToken}`}});if(!e.ok)return u;const t=await e.json(),s=(t.models??[]).map(n=>({id:n.id,name:n.name?.trim()||n.id,provider:n.provider,isDefault:n.id===t.default}));return s.length>0?s:u}catch{return u}}async function U(r,e){switch(r){case"claude":return N();case"codex":return V();case"workbuddy":return l("workbuddy")?x():[];case"gemini":return B();case"cursor":return q();case"openclaw":return[];case"opencode":return j();case"pi":return K(e);case"pi-coding-agent":return G();case"manager":return F}}async function te(r,e){return r.type.startsWith("custom:")?r.models??[]:U(r.type,e)}export{te as discoverModelsForAgent};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{randomBytes as m}from"node:crypto";import{createServer as u}from"node:net";import{resolveBuiltinCommand as f,spawnResolvedCommand as w}from"../command-spec.js";import{buildAgentProcessEnv as v}from"../../agent-env.js";import{DISCOVERY_WORKDIR as g}from"./types.js";import{parseOpenCodeProviderModels as h}from"./parsers.js";async function O(){return new Promise((s,r)=>{const o=u();o.once("error",r),o.listen(0,"127.0.0.1",()=>{const e=o.address(),t=e&&typeof e!="string"?e.port:0;o.close(()=>t?s(t):r(new Error("OpenCode discovery port unavailable")))})})}async function _(){const s=f("opencode");if(!s)return[];const r=await O(),o=m(24).toString("hex"),e=w(s,["serve","--hostname","127.0.0.1","--port",String(r)],{cwd:g,stdio:["ignore","pipe","pipe"],env:v({NO_COLOR:"1",OPENCODE_SERVER_PASSWORD:o})});e.stdout?.resume(),e.stderr?.resume();const t=`Basic ${Buffer.from(`opencode:${o}`).toString("base64")}`,a=`http://127.0.0.1:${r}`;let i=!1;e.once("close",()=>{i=!0}),e.once("error",()=>{i=!0});try{const d=Date.now()+1e4;for(;Date.now()<d&&!i;){try{const n=new AbortController,p=setTimeout(()=>n.abort(),2e3);try{const[c,l]=await Promise.all([fetch(`${a}/provider`,{headers:{Authorization:t},signal:n.signal}),fetch(`${a}/config`,{headers:{Authorization:t},signal:n.signal})]);if(c.ok&&l.ok)return h(await c.json(),await l.json())}finally{clearTimeout(p)}}catch{}await new Promise(n=>setTimeout(n,200))}return[]}finally{e.kill("SIGTERM"),setTimeout(()=>e.kill("SIGKILL"),1e3).unref()}}export{_ as discoverOpenCodeModelsViaApi};
|
|
@@ -5,6 +5,7 @@ export declare function fallbackWorkBuddyModels(): ModelInfo[];
|
|
|
5
5
|
export declare function parseCursorModels(raw: string): ModelInfo[];
|
|
6
6
|
export declare function parseOpenClawModels(raw: string): ModelInfo[];
|
|
7
7
|
export declare function parseOpenCodeModels(raw: string): ModelInfo[];
|
|
8
|
+
export declare function parseOpenCodeProviderModels(providerResponse: unknown, configResponse: unknown): ModelInfo[];
|
|
8
9
|
export declare function parseClaudeModels(raw: string): ModelInfo[];
|
|
9
10
|
export type EnvLike = Record<string, string | undefined>;
|
|
10
11
|
export declare function readEnvValue(env: EnvLike, key: string): string | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function
|
|
2
|
-
`)){const i=o.trim().match(/^(\S+)\s+-\s+(.+?)(?:\s+\(([^)]+)\))?$/);if(!i)continue;const[,s,r,
|
|
3
|
-
`).map(
|
|
4
|
-
`)){const i=o.match(/\b(gpt-[a-z0-9][a-z0-9.-]*)\b/i);if(!i)continue;const s=i[1].trim(),r=o.replace(s,"").replace(/^[^\w]+/,"").trim()||void 0;
|
|
1
|
+
function b(e){return e.replace(/\u001b\[[0-9;?]*[a-zA-Z]/g,"").replace(/\u001b\][^\u0007]*\u0007/g,"").replace(/[\u0000-\u0008\u000b-\u001f\u007f]/g,"")}function m(e){const t=new Set,n=[];for(const o of e)!o.id||t.has(o.id)||(t.add(o.id),n.push(o));return n}function y(e){return e&&e[0].toUpperCase()+e.slice(1)}function x(e){return e.split("-").map(t=>t==="gpt"?"GPT":t==="codex"?"Codex":/^\d/.test(t)?t:y(t)).join("-")}function O(e){switch(e){case"low":return"Low";case"medium":return"Medium";case"high":return"High";case"xhigh":return"Extra High";default:return y(e)}}const C=[{id:"gpt-5.6-sol",name:"GPT-5.6 Sol",description:"Latest GPT-5.6 Codex model.",provider:"openai"},{id:"gpt-5.6-terra",name:"GPT-5.6 Terra",description:"Latest GPT-5.6 Codex model.",provider:"openai"},{id:"gpt-5.6-luna",name:"GPT-5.6 Luna",description:"Latest GPT-5.6 Codex model.",provider:"openai"}];function M(e){const t={...e};return e.supportedReasoningEfforts&&(t.supportedReasoningEfforts=e.supportedReasoningEfforts.map(n=>({...n}))),e.additionalSpeedTiers&&(t.additionalSpeedTiers=[...e.additionalSpeedTiers]),t}function k(e,t){const n=t??e.find(i=>i.isDefault)?.id,o=m([...e.map(M),...C.map(i=>M(i))]);return n?o.map(i=>({...i,isDefault:i.id===n})):o}function G(){return C.map((e,t)=>({...M(e),...t===0?{isDefault:!0}:{}}))}function I(){return[{id:"auto",name:"Auto",provider:"workbuddy",isDefault:!0,supportedReasoningEfforts:["minimal","low","medium","high","xhigh","max"].map(e=>({id:e,name:O(e)})),defaultReasoningEffort:"medium"}]}function w(e){return e.split("-").map(t=>/^\d/.test(t)?t:y(t)).join(" ")}function _(e,t,n=!1){const o=t.toLowerCase().replace(/\s+/g,"-");return`gemini-${e}-${o}${n?"-preview":""}`}function N(e){const t=[],n=b(e);for(const o of n.split(`
|
|
2
|
+
`)){const i=o.trim().match(/^(\S+)\s+-\s+(.+?)(?:\s+\(([^)]+)\))?$/);if(!i)continue;const[,s,r,d]=i,l=d?.split(",").map(u=>u.trim().toLowerCase())??[];t.push({id:s,name:r.trim()||w(s),description:d?.trim(),isDefault:l.includes("default")||l.includes("current")})}return m(t)}function H(e){try{const n=(JSON.parse(e).models??[]).filter(o=>o.available).map(o=>({id:o.key,name:o.name?.trim()||o.key,provider:o.key.split("/")[0],description:o.tags?.join(", "),isDefault:o.tags?.includes("default")??!1}));return m(n)}catch{return[]}}function U(e){const t=b(e).split(`
|
|
3
|
+
`).map(n=>n.trim()).filter(Boolean).filter(n=>!n.includes(" ")).map(n=>({id:n,name:n,provider:n.includes("/")?n.split("/")[0]:void 0}));return m(t)}function B(e,t){if(!e||typeof e!="object")return[];const n=e;if(!Array.isArray(n.all)||!Array.isArray(n.connected))return[];const o=new Set(n.connected.filter(u=>typeof u=="string")),i=t&&typeof t=="object"?t:{},s=typeof i.model=="string"?i.model:"",r=i.provider&&typeof i.provider=="object"?i.provider:{},d=new Set;for(const[u,a]of Object.entries(r)){if(!a||typeof a!="object")continue;const p=a.models;if(!(!p||typeof p!="object"))for(const f of Object.keys(p))d.add(`${u}/${f}`)}const l=[];for(const u of n.all){if(!u||typeof u!="object")continue;const a=u;if(!(typeof a.id!="string"||!o.has(a.id))&&!(!a.models||typeof a.models!="object"))for(const[p,f]of Object.entries(a.models)){if(!f||typeof f!="object")continue;const c=f;if(c.status==="deprecated"||c.status==="unavailable"||c.capabilities?.input?.text===!1||c.capabilities?.output?.text===!1||c.capabilities?.toolcall===!1)continue;const g=typeof c.id=="string"&&c.id?c.id:p,h=`${a.id}/${g}`;l.push({id:h,name:typeof c.name=="string"&&c.name.trim()?c.name:h,provider:a.id,...h===s?{isDefault:!0}:{}})}}return m(l).sort((u,a)=>{const p=f=>f.id===s?0:d.has(f.id)?1:f.provider&&Object.hasOwn(r,f.provider)?2:3;return p(u)-p(a)||u.id.localeCompare(a.id)})}function V(e){const t=b(e).replace(/\s+/g," "),n=[[/\d+\.Default\(recommended\).*?(?:Sonnet|currently\s*Sonnet)\s*([\d.]+)/i,"default","Default (recommended)"],[/\d+\.Best.*?Opus\s*([\d.]+)/i,"best","Best","Most capable available model"],[/\d+\.Fable.*?Fable\s*([\d.]+)/i,"fable","Fable","Most capable for the hardest, longest-running tasks"],[/\d+\.Opus\(1Mcontext\).*?Opus\s*([\d.]+)/i,"opus[1m]","Opus (1M context)"],[/\d+\.OpusPlan.*?Opus\s*([\d.]+)/i,"opusplan","Opus Plan","Opus for planning \xB7 Sonnet for execution"],[/\d+\.Opus(?!\(1Mcontext\)).*?Opus\s*([\d.]+)/i,"opus","Opus"],[/\d+\.Sonnet\(1Mcontext\).*?Sonnet\s*([\d.]+)/i,"sonnet[1m]","Sonnet (1M context)"],[/\d+\.Sonnet(?!\(1Mcontext\)).*?Sonnet\s*([\d.]+)/i,"sonnet","Sonnet"],[/\d+\.Haiku.*?Haiku\s*([\d.]+)/i,"haiku","Haiku"]],o=[];for(const[d,l,u,a]of n){const p=t.match(d);p&&o.push(v({id:l,name:u,description:a?`${a} \xB7 v${p[1]}`:`v${p[1]}`,provider:"anthropic",isDefault:l==="default"}))}if(o.length>0)return m(o);const i=[],s=t.match(/currently\s*(Sonnet|Opus|Haiku)\s*([34](?:\.\d)?)/i),r={sonnet:"sonnet",opus:"opus",haiku:"haiku"};for(const d of t.matchAll(/\b(Sonnet|Opus|Haiku)\s*([34](?:\.\d)?)\b/gi)){const l=(d[1]??"").toLowerCase(),u=r[l];if(!u)continue;const a=d[2]??"",p=s&&s[1]?.toLowerCase()===l&&s[2]===a;i.push(v({id:u,name:`${y(l)} ${a}`,provider:"anthropic",isDefault:!!p}))}return m(i)}function R(e,t){const n=Math.max(e.length,t.length);for(let o=0;o<n;o++){const i=e[o]??-1,s=t[o]??-1;if(i!==s)return i-s}return 0}function T(e,t){const n=e.match(new RegExp(`^claude-${t}-([0-9]+(?:-[0-9]+)*)$`,"i"));if(!n?.[1])return null;const o=n[1].split("-").map(i=>Number.parseInt(i,10)).filter(i=>Number.isFinite(i));return o.length===0||o.length>2?null:o}function $(e){if(e?.length)return`v${e.join(".")}`}const A={default:"Default (recommended)",sonnet:"Sonnet",opus:"Opus",haiku:"Haiku"},S={default:"ANTHROPIC_MODEL",sonnet:"ANTHROPIC_DEFAULT_SONNET_MODEL",opus:"ANTHROPIC_DEFAULT_OPUS_MODEL",haiku:"ANTHROPIC_DEFAULT_HAIKU_MODEL"},P=[{id:"max",name:"Max"}],j=[{id:"low",name:"Low"},{id:"medium",name:"Medium"},{id:"high",name:"High"},{id:"xhigh",name:"Extra High"},{id:"max",name:"Max"}];function v(e){return{...e,supportedReasoningEfforts:j,defaultReasoningEffort:"medium"}}function E(e,t){return e[t]?.trim()||null}function D(e,t){const n=E(t,"ANTHROPIC_BASE_URL")?.toLowerCase()??"";return n.includes("deepseek.com")||e.toLowerCase().startsWith("deepseek-")?"deepseek":n?"custom":"anthropic"}function L(e){const t=new Set;for(const o of Object.values(S)){const i=E(e,o);i&&t.add(i)}const n=Array.from(t).map((o,i)=>{const s=D(o,e),r={id:o,name:o,provider:s,isDefault:i===0};return s==="deepseek"?{...r,supportedReasoningEfforts:P,defaultReasoningEffort:E(e,"CLAUDE_CODE_EFFORT_LEVEL")??"max"}:v(r)});return m(n)}function z(e=process.env){return L(e)}function F(e,t=process.env){return e.map(n=>{if(!["default","sonnet","opus","haiku"].includes(n.id))return n;const o=n.id,i=E(t,S[o]);if(!i)return n;const r=`Claude Code alias: ${A[o]}`;return{...n,name:i,description:n.description?`${r} \xB7 ${n.description}`:r,provider:D(i,t)}})}function K(e){const t=b(e),n=new Map;for(const i of["sonnet","opus","haiku"])for(const s of t.matchAll(new RegExp(`\\bclaude-${i}-[0-9.-]+\\b`,"gi"))){const r=s[0].trim().toLowerCase().replace(/\./g,"-").replace(/-+$/g,""),d=T(r,i);if(!d)continue;const l=n.get(i);(!l||R(l,d)<0)&&n.set(i,d)}const o=[];for(const i of["default","sonnet","opus","haiku"]){if(!new RegExp(`\\b${i}\\b`,"i").test(t))continue;const s=(i==="default"?n.get("sonnet"):n.get(i))??null;o.push(v({id:i,name:A[i],description:$(s),provider:"anthropic",isDefault:i==="default"}))}return m(o)}function q(e=process.env){const t=L(e);return t.length>0?t:F([{id:"default",name:"Default (recommended)",description:"Recommended model for your account",provider:"anthropic",isDefault:!0},{id:"sonnet",name:"Sonnet",description:"Latest Sonnet \xB7 everyday coding",provider:"anthropic"},{id:"fable",name:"Fable",description:"Most capable for the hardest, longest-running tasks",provider:"anthropic"},{id:"opus",name:"Opus",description:"Latest Opus \xB7 complex reasoning",provider:"anthropic"},{id:"haiku",name:"Haiku",description:"Fast and efficient \xB7 simple tasks",provider:"anthropic"},{id:"best",name:"Best",description:"Most capable available model",provider:"anthropic"},{id:"opus[1m]",name:"Opus (1M context)",description:"Latest Opus \xB7 long sessions",provider:"anthropic"},{id:"sonnet[1m]",name:"Sonnet (1M context)",description:"Latest Sonnet \xB7 long sessions",provider:"anthropic"},{id:"opusplan",name:"Opus Plan",description:"Opus for planning \xB7 Sonnet for execution",provider:"anthropic"}],e).map(n=>n.id==="haiku"?n:v(n))}function W(e){const t=b(e),n=[];for(const o of t.split(`
|
|
4
|
+
`)){const i=o.match(/\b(gpt-[a-z0-9][a-z0-9.-]*)\b/i);if(!i)continue;const s=i[1].trim(),r=o.replace(s,"").replace(/^[^\w]+/,"").trim()||void 0;n.push({id:s,name:x(s),description:r,provider:"openai",isDefault:/\bcurrent\b/i.test(o)||/\bselected\b/i.test(o)})}return m(n)}function J(e){const t=typeof e=="object"&&e!==null?e:{},n=typeof t.config?.model=="string"?t.config.model:void 0,o=typeof t.config?.model_reasoning_effort=="string"?t.config.model_reasoning_effort:void 0,i=[];for(const s of t.data??[]){if(typeof s!="object"||s===null)continue;const r=s,d=typeof r.id=="string"?r.id:typeof r.model=="string"?r.model:"";if(!d)continue;const l=typeof r.displayName=="string"?r.displayName:typeof r.name=="string"?r.name:void 0,u=typeof r.description=="string"?r.description:void 0,a=typeof r.defaultReasoningEffort=="string"?r.defaultReasoningEffort:void 0,p=Array.isArray(r.supportedReasoningEfforts)?r.supportedReasoningEfforts.map(c=>{if(typeof c!="object"||c===null)return null;const g=c,h=typeof g.reasoningEffort=="string"?g.reasoningEffort:typeof g.id=="string"?g.id:"";return h?{id:h,name:O(h),description:typeof g.description=="string"?g.description:void 0}:null}).filter(c=>c!=null):void 0,f=Array.isArray(r.additionalSpeedTiers)?r.additionalSpeedTiers.filter(c=>typeof c=="string"):void 0;i.push({id:d,name:l||x(d),description:u,provider:"openai",isDefault:n?n===d:r.isDefault===!0,supportedReasoningEfforts:p,defaultReasoningEffort:a,additionalSpeedTiers:f})}return n&&!i.some(s=>s.id===n)&&i.unshift({id:n,name:x(n),provider:"openai",isDefault:!0,defaultReasoningEffort:o}),k(m(i),n)}function X(e){const t=b(e),n=[];for(const o of t.matchAll(/\b(?:auto-)?gemini-[a-z0-9.-]+\b/gi)){const i=o[0].trim();n.push({id:i,name:i,provider:"google",isDefault:/\bcurrent\b/i.test(t)&&t.includes(i)})}for(const o of t.matchAll(/\bGemini\s*(\d(?:\.\d)?)\s*(Pro|Flash(?:[- ]Lite)?)\s*(Preview)?\b/gi)){const i=o[1]??"",s=(o[2]??"").replace(/\s+/g,"-"),r=!!o[3],d=_(i,s,r);n.push({id:d,name:`Gemini ${i} ${s.replace(/-/g," ")}`.trim(),provider:"google",isDefault:/\bcurrent\b/i.test(t)&&t.includes(o[0]??"")})}for(const o of t.matchAll(/\bAuto\s*Gemini\s*(\d(?:\.\d)?)\b/gi)){const i=o[1]??"",s=`auto-gemini-${i}`;n.push({id:s,name:`Auto Gemini ${i}`,provider:"google",isDefault:/\bcurrent\b/i.test(t)&&t.includes(o[0]??"")})}return m(n)}function Z(){return[{id:"gemini-2.5-pro",name:"Gemini 2.5 Pro",provider:"google",isDefault:!0},{id:"gemini-2.5-flash",name:"Gemini 2.5 Flash",provider:"google"},{id:"auto-gemini-2.5",name:"Auto Gemini 2.5",provider:"google"}]}export{F as applyClaudeModelEnvOverrides,z as discoverClaudeAliasModelsFromEnv,q as fallbackClaudeAliasModels,G as fallbackCodexModels,Z as fallbackGeminiModels,I as fallbackWorkBuddyModels,D as inferClaudeOverrideProvider,K as parseClaudeBinaryModels,V as parseClaudeModels,J as parseCodexAppServerModels,W as parseCodexModels,N as parseCursorModels,X as parseGeminiModels,H as parseOpenClawModels,U as parseOpenCodeModels,B as parseOpenCodeProviderModels,E as readEnvValue,b as stripAnsi};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getAgentConfigSummary as m}from"../config-status.js";import{isCacheFresh as
|
|
1
|
+
import{getAgentConfigSummary as m}from"../config-status.js";import{isCacheFresh as g,readCache as l,writeCache as y}from"./cache.js";import{discoverModelsForAgent as A}from"./discovery.js";import{getAgentRuntimeSummary as f}from"../runtime-compatibility.js";import{resolveManagedAgentRuntimeProtection as C}from"../../security/managed-agent-runtime.js";const M={claude:"claude-alias-v2",opencode:"opencode-connected-v1"};function S(o){const s=new Set,e=[];for(const i of o)!i.id||s.has(i.id)||(s.add(i.id),e.push(i));return e}function v(o){const s=o.type!=="pi"&&o.type!=="openclaw",e=s&&!o.type.startsWith("acp:"),i=s?C({agentType:o.type,runtimeVersion:o.version,platform:o.runtimePlatform,isWsl:o.runtimeIsWsl,executableFingerprint:o.executableFingerprint,requireExecutableFingerprint:!0}):null;return{supportsManagedAgent:e&&(i?.level==="hard"||i?.level==="partial"),supportsManagedNativeFull:s,supportsWorker:o.type!=="pi"&&o.type!=="openclaw"&&!o.type.startsWith("acp:"),supportsManagerMode:o.type==="codex"||o.type==="claude"||o.type==="pi-coding-agent",...i?{managedAgentProtection:i}:{}}}function E(o){const s=l();return o.map(e=>{const i=m(e.type),n=f(e);return{type:e.type,models:s.agents[e.type]?.models??e.models??[],...e.integration?{integration:e.integration}:{},...e.display?{display:e.display}:{},...e.acpCapabilities?{acpCapabilities:e.acpCapabilities}:{},...e.authState?{authState:e.authState}:{},...e.acpAuthMethods?{acpAuthMethods:e.acpAuthMethods}:{},...e.catalogRevision?{catalogRevision:e.catalogRevision}:{},...v(e),...i?{config:i}:{},...n?{runtime:n}:{}}})}async function O(o,s){const e=l();for(const i of o)delete e.agents[i.type];return y(e),R(o,s)}async function R(o,s){const e=l();let i=!1;const n=[];for(const t of o){const a=e.agents[t.type],p=M[t.type];let r;if(g(a,t.version,p))r=a.models;else{let c=null;try{c=S(await A(t,s)),r=c.length>0?c:a?.models??t.models??[]}catch{r=a?.models??t.models??[]}if(c&&c.length>0){const h={version:t.version,...p?{sourceRevision:p}:{},refreshedAt:Date.now(),models:r};JSON.stringify(a)!==JSON.stringify(h)&&(e.agents[t.type]=h,i=!0)}}const u=m(t.type),d=f(t);n.push({type:t.type,models:r,...t.integration?{integration:t.integration}:{},...t.display?{display:t.display}:{},...t.acpCapabilities?{acpCapabilities:t.acpCapabilities}:{},...t.authState?{authState:t.authState}:{},...t.acpAuthMethods?{acpAuthMethods:t.acpAuthMethods}:{},...t.catalogRevision?{catalogRevision:t.catalogRevision}:{},...v(t),...u?{config:u}:{},...d?{runtime:d}:{}})}return i&&y(e),n}export{E as getCachedAgentInfos,O as refreshAgentInfos,R as resolveAgentInfos};
|
|
@@ -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
|
|
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{
|
|
2
|
-
`),i||(process.exitCode=1)}export{
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2
|
-
`)}function
|
|
3
|
-
`)}function
|
|
1
|
+
import l from"node:path";function d(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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
|
-
|
|
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
|
-
|
|
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,"&").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
|
|
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,"&").replace(/<
|
|
|
46
46
|
<Enabled>true</Enabled>
|
|
47
47
|
<Hidden>true</Hidden>
|
|
48
48
|
<RunOnlyIfIdle>false</RunOnlyIfIdle>
|
|
49
|
-
<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,"&").replace(/<
|
|
|
60
60
|
<Arguments>${o(n)}</Arguments>
|
|
61
61
|
</Exec>
|
|
62
62
|
</Actions>
|
|
63
|
-
</Task>`}function
|
|
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};
|