shennian 0.4.1 → 0.4.2

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 (47) hide show
  1. package/dist/publish-build-manifest.json +70 -35
  2. package/dist/src/agent-env.d.ts +1 -0
  3. package/dist/src/agent-env.js +4 -4
  4. package/dist/src/agents/codex.d.ts +3 -2
  5. package/dist/src/agents/codex.js +8 -8
  6. package/dist/src/agents/command-spec.js +1 -1
  7. package/dist/src/agents/config-status.js +1 -1
  8. package/dist/src/agents/detect.d.ts +1 -0
  9. package/dist/src/agents/detect.js +1 -1
  10. package/dist/src/agents/manager.d.ts +3 -3
  11. package/dist/src/agents/manager.js +9 -9
  12. package/dist/src/agents/model-registry/cache.d.ts +1 -1
  13. package/dist/src/agents/model-registry/cache.js +1 -1
  14. package/dist/src/agents/model-registry/discovery.js +3 -2
  15. package/dist/src/agents/model-registry/parsers.js +4 -4
  16. package/dist/src/agents/model-registry/service.js +1 -1
  17. package/dist/src/agents/model-registry/types.d.ts +1 -0
  18. package/dist/src/agents/pi-coding-agent-managed-permissions.d.ts +7 -0
  19. package/dist/src/agents/pi-coding-agent-managed-permissions.js +1 -0
  20. package/dist/src/agents/pi-coding-agent.d.ts +55 -0
  21. package/dist/src/agents/pi-coding-agent.js +4 -0
  22. package/dist/src/agents/pi-managed-extension.d.ts +12 -0
  23. package/dist/src/agents/pi-managed-extension.js +89 -0
  24. package/dist/src/agents/pi-managed-model-broker.d.ts +27 -0
  25. package/dist/src/agents/pi-managed-model-broker.js +1 -0
  26. package/dist/src/agents/pi-rpc-client.d.ts +31 -0
  27. package/dist/src/agents/pi-rpc-client.js +3 -0
  28. package/dist/src/agents/pi-session-ownership.d.ts +2 -0
  29. package/dist/src/agents/pi-session-ownership.js +2 -0
  30. package/dist/src/manager/prompt.d.ts +1 -1
  31. package/dist/src/manager/prompt.js +2 -2
  32. package/dist/src/manager/registry.d.ts +4 -4
  33. package/dist/src/manager/runtime.d.ts +3 -3
  34. package/dist/src/room/activation-service.js +4 -4
  35. package/dist/src/security/managed-agent-policy.js +1 -1
  36. package/dist/src/session/handlers/agent-workspace-validation.d.ts +24 -0
  37. package/dist/src/session/handlers/agent-workspace-validation.js +1 -0
  38. package/dist/src/session/handlers/chat.js +1 -1
  39. package/dist/src/session/manager.d.ts +1 -0
  40. package/dist/src/session/manager.js +1 -1
  41. package/dist/src/session/native-session-lifecycle.js +6 -6
  42. package/dist/src/session/queue.d.ts +5 -1
  43. package/dist/src/session/queue.js +2 -2
  44. package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
  45. package/node_modules/@shennian/wire/dist/session.d.ts +2 -2
  46. package/node_modules/@shennian/wire/dist/session.js +1 -0
  47. package/package.json +1 -1
@@ -1,18 +1,18 @@
1
- import{AgentAdapter as g,registerAgent as I}from"./adapter.js";import{CodexAdapter as p}from"./codex.js";import{ClaudeAdapter as f}from"./claude.js";import{MANAGER_SYSTEM_PROMPT as y,buildManagerPrompt as l}from"../manager/prompt.js";import{getManagerRuntimeService as a}from"../manager/runtime.js";import d from"node:fs";import c from"node:path";import{PLATFORM_OUTPUT_INSTRUCTIONS as S}from"./platform-instructions.js";function M(i){return i==="claude"?"claude":"codex"}function w(i){return i.replace(/[^a-zA-Z0-9_.-]/g,"_")}function v(i){const e=c.join(i,"AGENTS.md");try{return d.readFileSync(e,"utf8").trim()}catch{return""}}function A(i,e){return c.join(i,".shennian","runtime","manager",w(e),"instructions.md")}function u(i,e){const n=v(i),t=a(),r=t?.getManagerExternalChannelSystemPrompt(e)??"",s=typeof t?.getManagerWorkerDefaults=="function"?t.getManagerWorkerDefaults(e):void 0,o=s?.agentType?`\u9ED8\u8BA4 worker Agent\uFF1A${s.agentType}${s.modelId?`
2
- \u9ED8\u8BA4 worker \u6A21\u578B\uFF1A${s.modelId}`:""}\u3002\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u6216\u4EFB\u52A1\u660E\u663E\u9700\u8981\u5176\u4ED6 Agent/\u6A21\u578B\uFF0C\u521B\u5EFA worker \u65F6\u4F18\u5148\u4F7F\u7528\u8FD9\u4E2A\u9ED8\u8BA4\u7EC4\u5408\u3002`:"";return`${["# Shennian Manager Instructions","This file is generated by Shennian for a Manager Agent substrate session. Do not edit it by hand.",n?`## Project Instructions
1
+ import{AgentAdapter as u,registerAgent as I}from"./adapter.js";import{CodexAdapter as p}from"./codex.js";import{ClaudeAdapter as f}from"./claude.js";import{MANAGER_SYSTEM_PROMPT as y,buildManagerPrompt as l}from"../manager/prompt.js";import{getManagerRuntimeService as o}from"../manager/runtime.js";import d from"node:fs";import c from"node:path";import{PLATFORM_OUTPUT_INSTRUCTIONS as S}from"./platform-instructions.js";function M(r){return r==="claude"?"claude":"codex"}function w(r){return r.replace(/[^a-zA-Z0-9_.-]/g,"_")}function v(r){const e=c.join(r,"AGENTS.md");try{return d.readFileSync(e,"utf8").trim()}catch{return""}}function A(r,e){return c.join(r,".shennian","runtime","manager",w(e),"instructions.md")}function h(r,e){const n=v(r),t=o(),s=t?.getManagerExternalChannelSystemPrompt(e)??"",i=typeof t?.getManagerWorkerDefaults=="function"?t.getManagerWorkerDefaults(e):void 0,a=i?.agentType?`\u9ED8\u8BA4 worker Agent\uFF1A${i.agentType}${i.modelId?`
2
+ \u9ED8\u8BA4 worker \u6A21\u578B\uFF1A${i.modelId}`:""}\u3002\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u6216\u4EFB\u52A1\u660E\u663E\u9700\u8981\u5176\u4ED6 Agent/\u6A21\u578B\uFF0C\u521B\u5EFA worker \u65F6\u4F18\u5148\u4F7F\u7528\u8FD9\u4E2A\u9ED8\u8BA4\u7EC4\u5408\u3002`:"";return`${["# Shennian Manager Instructions","This file is generated by Shennian for a Manager Agent substrate session. Do not edit it by hand.",n?`## Project Instructions
3
3
 
4
4
  ${n}`:"",`## Manager Instructions
5
5
 
6
- ${y}`,o?`## Worker Defaults
6
+ ${y}`,a?`## Worker Defaults
7
7
 
8
- ${o}`:"",r?`## External Message Channel Instructions
8
+ ${a}`:"",s?`## External Message Channel Instructions
9
9
 
10
- ${r}`:"",S].filter(Boolean).join(`
10
+ ${s}`:"",S].filter(Boolean).join(`
11
11
 
12
12
  `)}
13
- `}function k(i,e){const n=A(i,e),t=u(i,e);d.mkdirSync(c.dirname(n),{recursive:!0});try{if(d.readFileSync(n,"utf8")===t)return n}catch{}return d.writeFileSync(n,t),n}class R extends g{inner;substrate;type;sessionId="";workDir="";agentSessionId=null;configured={};constructor(e,n){super(),this.inner=e,this.substrate=n,this.type=e.type,e.on("agentEvent",t=>{t.agentSessionId&&(this.agentSessionId=t.agentSessionId),this.emit("agentEvent",{...t,source:t.source??n})}),e.on("error",t=>this.emit("error",t))}configure(e){this.configured=e,e.sessionId&&a()?.setManagedAgentPolicy(e.sessionId,e.managedAgentPolicy??null),this.applyEnvironment()}async start(e,n,t){this.sessionId=e,this.workDir=n,this.agentSessionId=t??null,this.applyEnvironment(),await this.inner.start(e,n,t),a()?.registerManager({sessionId:e,agentSessionId:this.agentSessionId,workDir:n,modelId:this.substrate,agentType:this.type==="claude"?"claude":"codex",status:"idle"}),a()?.bindManagerAdapterEvents(e,this.inner)}async send(e,n,t,r,s,o){a()?.registerManager({sessionId:this.sessionId,agentSessionId:this.agentSessionId,workDir:this.workDir,modelId:this.substrate,agentType:this.type==="claude"?"claude":"codex",providerModelId:n??null,status:"running"}),await a()?.ready(),this.applyEnvironment();const h=u(this.workDir,this.sessionId),m=E(h,s);return this.inner.send(l(e),n,t,r,m,o)}async resume(e){this.agentSessionId=e,await this.inner.resume(e)}async stop(){a()?.setManagedAgentPolicy(this.sessionId,null),await this.inner.stop()}getStatus(){return this.inner.getStatus?.()??Promise.resolve({active:!1})}setTitle(e,n,t){return this.inner.setTitle?.(e,n,t)??Promise.resolve()}applyEnvironment(){const e=this.sessionId?a()?.getInjectedEnv(this.sessionId,this.agentSessionId,this.workDir,this.substrate)??{}:{};this.inner.configure?.({...this.configured,sessionId:this.configured.sessionId??this.sessionId,env:{...this.configured.env??{},...e},managedAgentPolicy:this.configured.managedAgentPolicy??null})}}function E(i,e){const n=e?.trim()??"";if(!n)return i;const r=["[\u667A\u80FD\u4F53\u79C1\u6709\u7CFB\u7EDF\u63D0\u793A\u8BCD]","[\u667A\u80FD\u4F53\u8EAB\u4EFD]"].map(s=>n.indexOf(s)).filter(s=>s>=0).sort((s,o)=>s-o)[0]??-1;return n.startsWith("[\u795E\u5FF5\u53D7\u7BA1\u4F1A\u8BDD\u89C4\u5219]")&&r>=0?`${n.slice(0,r)}[\u4F1A\u8BDD\u6A21\u5F0F]
14
- ${i.trim()}
13
+ `}function k(r,e){const n=A(r,e),t=h(r,e);d.mkdirSync(c.dirname(n),{recursive:!0});try{if(d.readFileSync(n,"utf8")===t)return n}catch{}return d.writeFileSync(n,t),n}class R extends u{inner;substrate;type;sessionId="";workDir="";agentSessionId=null;configured={};constructor(e,n){super(),this.inner=e,this.substrate=n,this.type=e.type,e.on("agentEvent",t=>{t.agentSessionId&&(this.agentSessionId=t.agentSessionId),this.emit("agentEvent",{...t,source:t.source??n})}),e.on("error",t=>this.emit("error",t))}configure(e){this.configured=e,e.sessionId&&o()?.setManagedAgentPolicy(e.sessionId,e.managedAgentPolicy??null),this.applyEnvironment()}async start(e,n,t,s){this.sessionId=e,this.workDir=n,this.agentSessionId=t??null,this.applyEnvironment(),await this.inner.start(e,n,t,s),o()?.registerManager({sessionId:e,agentSessionId:this.agentSessionId,workDir:n,modelId:this.substrate,agentType:this.type,status:"idle"}),o()?.bindManagerAdapterEvents(e,this.inner)}async send(e,n,t,s,i,a){o()?.registerManager({sessionId:this.sessionId,agentSessionId:this.agentSessionId,workDir:this.workDir,modelId:this.substrate,agentType:this.type,providerModelId:n??null,status:"running"}),await o()?.ready(),this.applyEnvironment();const g=h(this.workDir,this.sessionId),m=E(g,i);return this.inner.send(l(e),n,t,s,m,a)}async resume(e){this.agentSessionId=e,await this.inner.resume(e)}async stop(){o()?.setManagedAgentPolicy(this.sessionId,null),await this.inner.stop()}getStatus(){return this.inner.getStatus?.()??Promise.resolve({active:!1})}setTitle(e,n,t){return this.inner.setTitle?.(e,n,t)??Promise.resolve()}applyEnvironment(){const e=this.sessionId?o()?.getInjectedEnv(this.sessionId,this.agentSessionId,this.workDir,this.substrate)??{}:{};this.inner.configure?.({...this.configured,sessionId:this.configured.sessionId??this.sessionId,env:{...this.configured.env??{},...e},managedAgentPolicy:this.configured.managedAgentPolicy??null})}}function E(r,e){const n=e?.trim()??"";if(!n)return r;const s=["[\u667A\u80FD\u4F53\u79C1\u6709\u7CFB\u7EDF\u63D0\u793A\u8BCD]","[\u667A\u80FD\u4F53\u8EAB\u4EFD]"].map(i=>n.indexOf(i)).filter(i=>i>=0).sort((i,a)=>i-a)[0]??-1;return n.startsWith("[\u795E\u5FF5\u53D7\u7BA1\u4F1A\u8BDD\u89C4\u5219]")&&s>=0?`${n.slice(0,s)}[\u4F1A\u8BDD\u6A21\u5F0F]
14
+ ${r.trim()}
15
15
 
16
- ${n.slice(r)}`:`${i.trim()}
16
+ ${n.slice(s)}`:`${r.trim()}
17
17
 
18
- ${n}`}class P extends g{type="manager";inner=null;sessionId="";workDir="";agentSessionId=null;modelId="codex";async start(e,n,t){this.sessionId=e,this.workDir=n,this.agentSessionId=t??null,a()?.registerManager({sessionId:e,agentSessionId:this.agentSessionId,workDir:n,modelId:this.modelId,agentType:"manager",status:"idle"})}async send(e,n){const t=M(n);if(!this.inner||t!==this.modelId){await this.inner?.stop().catch(()=>{}),this.inner?.removeAllListeners(),this.modelId=t;const r=k(this.workDir,this.sessionId),s=u(this.workDir,this.sessionId);this.inner=t==="claude"?new f({systemPrompt:s,hidden:!0}):new p({modelInstructionsFile:r,hidden:!0}),this.bindInner(this.inner),await this.inner.start(this.sessionId,this.workDir,this.agentSessionId),a()?.bindManagerAdapterEvents(this.sessionId,this.inner)}a()?.registerManager({sessionId:this.sessionId,agentSessionId:this.agentSessionId,workDir:this.workDir,modelId:this.modelId,agentType:"manager",status:"running"}),await a()?.ready(),await this.withManagerEnv(()=>this.inner.send(l(e)))}async resume(e){this.agentSessionId=e,this.inner&&await this.inner.resume(e)}async stop(){await this.inner?.stop()}bindInner(e){e.on("agentEvent",n=>{n.agentSessionId&&(this.agentSessionId=n.agentSessionId),this.emit("agentEvent",this.wrapEvent(n))}),e.on("error",n=>this.emit("error",n))}wrapEvent(e){return{...e,source:e.source??this.modelId,agentSessionId:e.agentSessionId??this.agentSessionId??void 0}}async withManagerEnv(e){const n=a()?.getInjectedEnv(this.sessionId,this.agentSessionId,this.workDir,this.modelId)??{},t=new Map;for(const[r,s]of Object.entries(n))t.set(r,process.env[r]),process.env[r]=s;try{return await e()}finally{for(const[r,s]of t)s===void 0?delete process.env[r]:process.env[r]=s}}}I("manager",()=>new P);export{P as ManagerAdapter,R as ManagerModeAdapter,E as combineManagerInstructions};
18
+ ${n}`}class P extends u{type="manager";inner=null;sessionId="";workDir="";agentSessionId=null;modelId="codex";async start(e,n,t){this.sessionId=e,this.workDir=n,this.agentSessionId=t??null,o()?.registerManager({sessionId:e,agentSessionId:this.agentSessionId,workDir:n,modelId:this.modelId,agentType:"manager",status:"idle"})}async send(e,n){const t=M(n);if(!this.inner||t!==this.modelId){await this.inner?.stop().catch(()=>{}),this.inner?.removeAllListeners(),this.modelId=t;const s=k(this.workDir,this.sessionId),i=h(this.workDir,this.sessionId);this.inner=t==="claude"?new f({systemPrompt:i,hidden:!0}):new p({modelInstructionsFile:s,hidden:!0}),this.bindInner(this.inner),await this.inner.start(this.sessionId,this.workDir,this.agentSessionId),o()?.bindManagerAdapterEvents(this.sessionId,this.inner)}o()?.registerManager({sessionId:this.sessionId,agentSessionId:this.agentSessionId,workDir:this.workDir,modelId:this.modelId,agentType:"manager",status:"running"}),await o()?.ready(),await this.withManagerEnv(()=>this.inner.send(l(e)))}async resume(e){this.agentSessionId=e,this.inner&&await this.inner.resume(e)}async stop(){await this.inner?.stop()}bindInner(e){e.on("agentEvent",n=>{n.agentSessionId&&(this.agentSessionId=n.agentSessionId),this.emit("agentEvent",this.wrapEvent(n))}),e.on("error",n=>this.emit("error",n))}wrapEvent(e){return{...e,source:e.source??this.modelId,agentSessionId:e.agentSessionId??this.agentSessionId??void 0}}async withManagerEnv(e){const n=o()?.getInjectedEnv(this.sessionId,this.agentSessionId,this.workDir,this.modelId)??{},t=new Map;for(const[s,i]of Object.entries(n))t.set(s,process.env[s]),process.env[s]=i;try{return await e()}finally{for(const[s,i]of t)i===void 0?delete process.env[s]:process.env[s]=i}}}I("manager",()=>new P);export{P as ManagerAdapter,R as ManagerModeAdapter,E as combineManagerInstructions};
@@ -1,4 +1,4 @@
1
1
  import { type CacheEntry, type CacheFile } from './types.js';
2
2
  export declare function readCache(): CacheFile;
3
3
  export declare function writeCache(cache: CacheFile): void;
4
- export declare function isCacheFresh(entry: CacheEntry | undefined, version?: string): boolean;
4
+ export declare function isCacheFresh(entry: CacheEntry | undefined, version?: string, sourceRevision?: string): boolean;
@@ -1 +1 @@
1
- import e from"node:fs";import o from"node:path";import{CACHE_TTL_MS as s,CACHE_VERSION as n,MODEL_CACHE_PATH as t}from"./types.js";function a(){e.mkdirSync(o.dirname(t),{recursive:!0})}function p(){try{const r=JSON.parse(e.readFileSync(t,"utf-8"));if(r.version===n&&r.agents&&typeof r.agents=="object")return r}catch{}return{version:n,agents:{}}}function C(r){try{a(),e.writeFileSync(t,JSON.stringify(r,null,2))}catch{}}function h(r,i){return!r||r.version!==i?!1:Date.now()-r.refreshedAt<s}export{h as isCacheFresh,p as readCache,C as writeCache};
1
+ import e from"node:fs";import o from"node:path";import{CACHE_TTL_MS as f,CACHE_VERSION as n,MODEL_CACHE_PATH as t}from"./types.js";function a(){e.mkdirSync(o.dirname(t),{recursive:!0})}function C(){try{const r=JSON.parse(e.readFileSync(t,"utf-8"));if(r.version===n&&r.agents&&typeof r.agents=="object")return r}catch{}return{version:n,agents:{}}}function h(r){try{a(),e.writeFileSync(t,JSON.stringify(r,null,2))}catch{}}function m(r,s,i){return!r||r.version!==s||i&&r.sourceRevision!==i?!1:Date.now()-r.refreshedAt<f}export{m as isCacheFresh,C as readCache,h as writeCache};
@@ -1,2 +1,3 @@
1
- import{createInterface as m}from"node:readline";import{resolveBuiltinCommand as c,spawnResolvedCommand as v}from"../command-spec.js";import{fallbackClaudeAliasModels as M,discoverClaudeAliasModelsFromEnv as w,fallbackCodexModels as y,fallbackWorkBuddyModels as C,fallbackGeminiModels as h,parseCodexAppServerModels as g,parseCursorModels as E,parseOpenCodeModels as k}from"./parsers.js";import{runResolvedCommand as f}from"./runner.js";import{DISCOVERY_WORKDIR as b}from"./types.js";import{buildAgentProcessEnv as x,readLatestUserEnv as O}from"../../agent-env.js";import{CODEX_APP_SERVER_CLIENT_INFO as R}from"../codex-utils.js";function l(e,r,o,i,a,n){return e.stdin?new Promise((t,s)=>{const u=setTimeout(()=>{r.delete(o),s(new Error(`codex app-server request timed out: ${i}`))},n);r.set(o,{resolve:t,reject:s,timer:u}),e.stdin.write(`${JSON.stringify({id:o,method:i,params:a})}
2
- `,p=>{p&&(clearTimeout(u),r.delete(o),s(p))})}):Promise.reject(new Error("codex app-server stdin unavailable"))}async function A(e){const r=v(e,["app-server","--listen","stdio://"],{cwd:b,stdio:["pipe","pipe","pipe"],env:x({NO_COLOR:"1"})}),o=new Map;let i=1;m({input:r.stdout}).on("line",n=>{if(!n.trim())return;let t;try{t=JSON.parse(n)}catch{return}if(t.id==null)return;const s=o.get(t.id);s&&(clearTimeout(s.timer),o.delete(t.id),t.error?s.reject(new Error(t.error.message||`codex app-server error ${t.error.code??""}`.trim())):s.resolve(t.result))});try{await l(r,o,i++,"initialize",{clientInfo:R,capabilities:{experimentalApi:!0}},1e4);const[n,t]=await Promise.all([l(r,o,i++,"model/list",{},15e3),l(r,o,i++,"config/read",{},15e3).catch(()=>null)]),s=typeof t=="object"&&t!==null&&"config"in t?t.config:void 0;return g({...typeof n=="object"&&n!==null?n:{},config:s})}finally{for(const[n,t]of o)clearTimeout(t.timer),t.reject(new Error("codex app-server stopped")),o.delete(n);r.kill("SIGTERM"),setTimeout(()=>r.kill("SIGKILL"),1e3).unref()}}async function S(){const e=c("cursor");if(!e)return[];const r=await f(e,["--list-models"]);return E(r.stdout)}async function I(){const e=c("opencode");if(!e)return[];const r=await f(e,["models"]);return k(r.stdout)}async function P(){if(!c("claude"))return[];const e=w(O());return e.length>0?e:M()}async function T(){const e=c("codex");if(!e)return[];const r=await A(e).catch(()=>[]);return r.length>0?r:y()}async function _(){return c("gemini")?h():[]}const d=[{id:"qwen3.6-plus",name:"Qwen 3.6 Plus",provider:"dashscope",isDefault:!0}],D=[{id:"codex",name:"Codex",provider:"shennian",isDefault:!0},{id:"claude",name:"Claude Code",provider:"shennian"}];async function L(e){if(!e.serverUrl||!e.authToken)return d;try{const r=await fetch(`${e.serverUrl.replace(/\/$/,"")}/api/models`,{headers:{Authorization:`Bearer ${e.authToken}`}});if(!r.ok)return d;const o=await r.json(),i=(o.models??[]).map(a=>({id:a.id,name:a.name?.trim()||a.id,provider:a.provider,isDefault:a.id===o.default}));return i.length>0?i:d}catch{return d}}async function $(e,r){switch(e){case"claude":return P();case"codex":return T();case"workbuddy":return c("workbuddy")?C():[];case"gemini":return _();case"cursor":return S();case"openclaw":return[];case"opencode":return I();case"pi":return L(r);case"manager":return D}}async function V(e,r){return e.type.startsWith("custom:")?e.models??[]:$(e.type,r)}export{V as discoverModelsForAgent};
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 D(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 L(){const r=l("cursor");if(!r)return[];const e=await m(r,["--list-models"]);return A(e.stdout)}async function q(){const r=l("opencode");if(!r)return[];const e=await m(r,["models"]);return I(e.stdout)}async function j(){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 g=`${d.provider}/${d.id}`,h=d.reasoning===!0?["off","minimal","low","medium","high","xhigh","max"].map(y=>({id:y,name:y})):void 0;return[{id:g,name:typeof d.name=="string"&&d.name.trim()?d.name:d.id,provider:d.provider,isDefault:g===c,...h?{supportedReasoningEfforts:h,defaultReasoningEffort:"medium"}:{}}]}):[]}catch{return[]}finally{s.close(),t.kill("SIGTERM"),setTimeout(()=>t.kill("SIGKILL"),1e3).unref()}}async function G(){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 N(){const r=l("codex");if(!r)return[];const e=await D(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 V(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 K(r,e){switch(r){case"claude":return G();case"codex":return N();case"workbuddy":return l("workbuddy")?x():[];case"gemini":return B();case"cursor":return L();case"openclaw":return[];case"opencode":return q();case"pi":return V(e);case"pi-coding-agent":return j();case"manager":return F}}async function ee(r,e){return r.type.startsWith("custom:")?r.models??[]:K(r.type,e)}export{ee as discoverModelsForAgent};
@@ -1,4 +1,4 @@
1
- function g(e){return e.replace(/\u001b\[[0-9;?]*[a-zA-Z]/g,"").replace(/\u001b\][^\u0007]*\u0007/g,"").replace(/[\u0000-\u0008\u000b-\u001f\u007f]/g,"")}function d(e){const n=new Set,t=[];for(const o of e)!o.id||n.has(o.id)||(n.add(o.id),t.push(o));return t}function E(e){return e&&e[0].toUpperCase()+e.slice(1)}function b(e){return e.split("-").map(n=>n==="gpt"?"GPT":n==="codex"?"Codex":/^\d/.test(n)?n:E(n)).join("-")}function M(e){switch(e){case"low":return"Low";case"medium":return"Medium";case"high":return"High";case"xhigh":return"Extra High";default:return E(e)}}const O=[{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 C(e){const n={...e};return e.supportedReasoningEfforts&&(n.supportedReasoningEfforts=e.supportedReasoningEfforts.map(t=>({...t}))),e.additionalSpeedTiers&&(n.additionalSpeedTiers=[...e.additionalSpeedTiers]),n}function R(e,n){const t=n??e.find(i=>i.isDefault)?.id,o=d([...e.map(C),...O.map(i=>C(i))]);return t?o.map(i=>({...i,isDefault:i.id===t})):o}function H(){return O.map((e,n)=>({...C(e),...n===0?{isDefault:!0}:{}}))}function F(){return[{id:"auto",name:"Auto",provider:"workbuddy",isDefault:!0,supportedReasoningEfforts:["minimal","low","medium","high","xhigh","max"].map(e=>({id:e,name:M(e)})),defaultReasoningEffort:"medium"}]}function k(e){return e.split("-").map(n=>/^\d/.test(n)?n:E(n)).join(" ")}function _(e,n,t=!1){const o=n.toLowerCase().replace(/\s+/g,"-");return`gemini-${e}-${o}${t?"-preview":""}`}function I(e){const n=[],t=g(e);for(const o of t.split(`
2
- `)){const i=o.trim().match(/^(\S+)\s+-\s+(.+?)(?:\s+\(([^)]+)\))?$/);if(!i)continue;const[,s,r,a]=i,u=a?.split(",").map(c=>c.trim().toLowerCase())??[];n.push({id:s,name:r.trim()||k(s),description:a?.trim(),isDefault:u.includes("default")||u.includes("current")})}return d(n)}function U(e){try{const t=(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 d(t)}catch{return[]}}function B(e){const n=g(e).split(`
3
- `).map(t=>t.trim()).filter(Boolean).filter(t=>!t.includes(" ")).map(t=>({id:t,name:t,provider:t.includes("/")?t.split("/")[0]:void 0}));return d(n)}function j(e){const n=g(e).replace(/\s+/g," "),t=[[/\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+\.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[a,u,c,l]of t){const p=n.match(a);p&&o.push(h({id:u,name:c,description:l?`${l} \xB7 v${p[1]}`:`v${p[1]}`,provider:"anthropic",isDefault:u==="default"}))}if(o.length>0)return d(o);const i=[],s=n.match(/currently\s*(Sonnet|Opus|Haiku)\s*([34](?:\.\d)?)/i),r={sonnet:"sonnet",opus:"opus",haiku:"haiku"};for(const a of n.matchAll(/\b(Sonnet|Opus|Haiku)\s*([34](?:\.\d)?)\b/gi)){const u=(a[1]??"").toLowerCase(),c=r[u];if(!c)continue;const l=a[2]??"",p=s&&s[1]?.toLowerCase()===u&&s[2]===l;i.push(h({id:c,name:`${E(u)} ${l}`,provider:"anthropic",isDefault:!!p}))}return d(i)}function T(e,n){const t=Math.max(e.length,n.length);for(let o=0;o<t;o++){const i=e[o]??-1,s=n[o]??-1;if(i!==s)return i-s}return 0}function w(e,n){const t=e.match(new RegExp(`^claude-${n}-([0-9]+(?:-[0-9]+)*)$`,"i"));if(!t?.[1])return null;const o=t[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 y={default:"Default (recommended)",sonnet:"Sonnet",opus:"Opus",haiku:"Haiku"},L={default:"ANTHROPIC_MODEL",sonnet:"ANTHROPIC_DEFAULT_SONNET_MODEL",opus:"ANTHROPIC_DEFAULT_OPUS_MODEL",haiku:"ANTHROPIC_DEFAULT_HAIKU_MODEL"},P=[{id:"max",name:"Max"}],G=[{id:"low",name:"Low"},{id:"medium",name:"Medium"},{id:"high",name:"High"},{id:"xhigh",name:"Extra High"},{id:"max",name:"Max"}];function h(e){return{...e,supportedReasoningEfforts:G,defaultReasoningEffort:"medium"}}function x(e,n){return e[n]?.trim()||null}function A(e,n){const t=x(n,"ANTHROPIC_BASE_URL")?.toLowerCase()??"";return t.includes("deepseek.com")||e.toLowerCase().startsWith("deepseek-")?"deepseek":t?"custom":"anthropic"}function D(e){const n=new Set;for(const o of Object.values(L)){const i=x(e,o);i&&n.add(i)}const t=Array.from(n).map((o,i)=>{const s=A(o,e),r={id:o,name:o,provider:s,isDefault:i===0};return s==="deepseek"?{...r,supportedReasoningEfforts:P,defaultReasoningEffort:x(e,"CLAUDE_CODE_EFFORT_LEVEL")??"max"}:h(r)});return d(t)}function V(e=process.env){return D(e)}function N(e,n=process.env){return e.map(t=>{if(!["default","sonnet","opus","haiku"].includes(t.id))return t;const o=t.id,i=x(n,L[o]);if(!i)return t;const r=`Claude Code alias: ${y[o]}`;return{...t,name:i,description:t.description?`${r} \xB7 ${t.description}`:r,provider:A(i,n)}})}function z(e){const n=g(e),t=new Map;for(const i of["sonnet","opus","haiku"])for(const s of n.matchAll(new RegExp(`\\bclaude-${i}-[0-9.-]+\\b`,"gi"))){const r=s[0].trim().toLowerCase().replace(/\./g,"-").replace(/-+$/g,""),a=w(r,i);if(!a)continue;const u=t.get(i);(!u||T(u,a)<0)&&t.set(i,a)}const o=[];for(const i of["default","sonnet","opus","haiku"]){if(!new RegExp(`\\b${i}\\b`,"i").test(n))continue;const s=(i==="default"?t.get("sonnet"):t.get(i))??null;o.push(h({id:i,name:y[i],description:$(s),provider:"anthropic",isDefault:i==="default"}))}return d(o)}function q(e=process.env){const n=D(e);return n.length>0?n:N([{id:"default",name:"Default (recommended)",description:"Recommended model for your account",provider:"anthropic",isDefault:!0},{id:"best",name:"Best",description:"Most capable available model \xB7 currently Opus",provider:"anthropic"},{id:"opus",name:"Opus",description:"Latest Opus \xB7 complex reasoning",provider:"anthropic"},{id:"opus[1m]",name:"Opus (1M context)",description:"Latest Opus \xB7 long sessions",provider:"anthropic"},{id:"sonnet",name:"Sonnet",description:"Latest Sonnet \xB7 everyday coding",provider:"anthropic"},{id:"sonnet[1m]",name:"Sonnet (1M context)",description:"Latest Sonnet \xB7 long sessions",provider:"anthropic"},{id:"haiku",name:"Haiku",description:"Fast and efficient \xB7 simple tasks",provider:"anthropic"},{id:"opusplan",name:"Opus Plan",description:"Opus for planning \xB7 Sonnet for execution",provider:"anthropic"}],e).map(h)}function K(e){const n=g(e),t=[];for(const o of n.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;t.push({id:s,name:b(s),description:r,provider:"openai",isDefault:/\bcurrent\b/i.test(o)||/\bselected\b/i.test(o)})}return d(t)}function W(e){const n=typeof e=="object"&&e!==null?e:{},t=typeof n.config?.model=="string"?n.config.model:void 0,o=typeof n.config?.model_reasoning_effort=="string"?n.config.model_reasoning_effort:void 0,i=[];for(const s of n.data??[]){if(typeof s!="object"||s===null)continue;const r=s,a=typeof r.id=="string"?r.id:typeof r.model=="string"?r.model:"";if(!a)continue;const u=typeof r.displayName=="string"?r.displayName:typeof r.name=="string"?r.name:void 0,c=typeof r.description=="string"?r.description:void 0,l=typeof r.defaultReasoningEffort=="string"?r.defaultReasoningEffort:void 0,p=Array.isArray(r.supportedReasoningEfforts)?r.supportedReasoningEfforts.map(f=>{if(typeof f!="object"||f===null)return null;const m=f,v=typeof m.reasoningEffort=="string"?m.reasoningEffort:typeof m.id=="string"?m.id:"";return v?{id:v,name:M(v),description:typeof m.description=="string"?m.description:void 0}:null}).filter(f=>f!=null):void 0,S=Array.isArray(r.additionalSpeedTiers)?r.additionalSpeedTiers.filter(f=>typeof f=="string"):void 0;i.push({id:a,name:u||b(a),description:c,provider:"openai",isDefault:t?t===a:r.isDefault===!0,supportedReasoningEfforts:p,defaultReasoningEffort:l,additionalSpeedTiers:S})}return t&&!i.some(s=>s.id===t)&&i.unshift({id:t,name:b(t),provider:"openai",isDefault:!0,defaultReasoningEffort:o}),R(d(i),t)}function J(e){const n=g(e),t=[];for(const o of n.matchAll(/\b(?:auto-)?gemini-[a-z0-9.-]+\b/gi)){const i=o[0].trim();t.push({id:i,name:i,provider:"google",isDefault:/\bcurrent\b/i.test(n)&&n.includes(i)})}for(const o of n.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],a=_(i,s,r);t.push({id:a,name:`Gemini ${i} ${s.replace(/-/g," ")}`.trim(),provider:"google",isDefault:/\bcurrent\b/i.test(n)&&n.includes(o[0]??"")})}for(const o of n.matchAll(/\bAuto\s*Gemini\s*(\d(?:\.\d)?)\b/gi)){const i=o[1]??"",s=`auto-gemini-${i}`;t.push({id:s,name:`Auto Gemini ${i}`,provider:"google",isDefault:/\bcurrent\b/i.test(n)&&n.includes(o[0]??"")})}return d(t)}function X(){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{N as applyClaudeModelEnvOverrides,V as discoverClaudeAliasModelsFromEnv,q as fallbackClaudeAliasModels,H as fallbackCodexModels,X as fallbackGeminiModels,F as fallbackWorkBuddyModels,A as inferClaudeOverrideProvider,z as parseClaudeBinaryModels,j as parseClaudeModels,W as parseCodexAppServerModels,K as parseCodexModels,I as parseCursorModels,J as parseGeminiModels,U as parseOpenClawModels,B as parseOpenCodeModels,x as readEnvValue,g as stripAnsi};
1
+ function g(e){return e.replace(/\u001b\[[0-9;?]*[a-zA-Z]/g,"").replace(/\u001b\][^\u0007]*\u0007/g,"").replace(/[\u0000-\u0008\u000b-\u001f\u007f]/g,"")}function d(e){const n=new Set,t=[];for(const o of e)!o.id||n.has(o.id)||(n.add(o.id),t.push(o));return t}function E(e){return e&&e[0].toUpperCase()+e.slice(1)}function x(e){return e.split("-").map(n=>n==="gpt"?"GPT":n==="codex"?"Codex":/^\d/.test(n)?n:E(n)).join("-")}function C(e){switch(e){case"low":return"Low";case"medium":return"Medium";case"high":return"High";case"xhigh":return"Extra High";default:return E(e)}}const O=[{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 n={...e};return e.supportedReasoningEfforts&&(n.supportedReasoningEfforts=e.supportedReasoningEfforts.map(t=>({...t}))),e.additionalSpeedTiers&&(n.additionalSpeedTiers=[...e.additionalSpeedTiers]),n}function k(e,n){const t=n??e.find(i=>i.isDefault)?.id,o=d([...e.map(M),...O.map(i=>M(i))]);return t?o.map(i=>({...i,isDefault:i.id===t})):o}function N(){return O.map((e,n)=>({...M(e),...n===0?{isDefault:!0}:{}}))}function H(){return[{id:"auto",name:"Auto",provider:"workbuddy",isDefault:!0,supportedReasoningEfforts:["minimal","low","medium","high","xhigh","max"].map(e=>({id:e,name:C(e)})),defaultReasoningEffort:"medium"}]}function R(e){return e.split("-").map(n=>/^\d/.test(n)?n:E(n)).join(" ")}function _(e,n,t=!1){const o=n.toLowerCase().replace(/\s+/g,"-");return`gemini-${e}-${o}${t?"-preview":""}`}function I(e){const n=[],t=g(e);for(const o of t.split(`
2
+ `)){const i=o.trim().match(/^(\S+)\s+-\s+(.+?)(?:\s+\(([^)]+)\))?$/);if(!i)continue;const[,s,r,a]=i,u=a?.split(",").map(c=>c.trim().toLowerCase())??[];n.push({id:s,name:r.trim()||R(s),description:a?.trim(),isDefault:u.includes("default")||u.includes("current")})}return d(n)}function U(e){try{const t=(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 d(t)}catch{return[]}}function B(e){const n=g(e).split(`
3
+ `).map(t=>t.trim()).filter(Boolean).filter(t=>!t.includes(" ")).map(t=>({id:t,name:t,provider:t.includes("/")?t.split("/")[0]:void 0}));return d(n)}function j(e){const n=g(e).replace(/\s+/g," "),t=[[/\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[a,u,c,l]of t){const p=n.match(a);p&&o.push(h({id:u,name:c,description:l?`${l} \xB7 v${p[1]}`:`v${p[1]}`,provider:"anthropic",isDefault:u==="default"}))}if(o.length>0)return d(o);const i=[],s=n.match(/currently\s*(Sonnet|Opus|Haiku)\s*([34](?:\.\d)?)/i),r={sonnet:"sonnet",opus:"opus",haiku:"haiku"};for(const a of n.matchAll(/\b(Sonnet|Opus|Haiku)\s*([34](?:\.\d)?)\b/gi)){const u=(a[1]??"").toLowerCase(),c=r[u];if(!c)continue;const l=a[2]??"",p=s&&s[1]?.toLowerCase()===u&&s[2]===l;i.push(h({id:c,name:`${E(u)} ${l}`,provider:"anthropic",isDefault:!!p}))}return d(i)}function T(e,n){const t=Math.max(e.length,n.length);for(let o=0;o<t;o++){const i=e[o]??-1,s=n[o]??-1;if(i!==s)return i-s}return 0}function w(e,n){const t=e.match(new RegExp(`^claude-${n}-([0-9]+(?:-[0-9]+)*)$`,"i"));if(!t?.[1])return null;const o=t[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 y={default:"Default (recommended)",sonnet:"Sonnet",opus:"Opus",haiku:"Haiku"},L={default:"ANTHROPIC_MODEL",sonnet:"ANTHROPIC_DEFAULT_SONNET_MODEL",opus:"ANTHROPIC_DEFAULT_OPUS_MODEL",haiku:"ANTHROPIC_DEFAULT_HAIKU_MODEL"},P=[{id:"max",name:"Max"}],F=[{id:"low",name:"Low"},{id:"medium",name:"Medium"},{id:"high",name:"High"},{id:"xhigh",name:"Extra High"},{id:"max",name:"Max"}];function h(e){return{...e,supportedReasoningEfforts:F,defaultReasoningEffort:"medium"}}function b(e,n){return e[n]?.trim()||null}function A(e,n){const t=b(n,"ANTHROPIC_BASE_URL")?.toLowerCase()??"";return t.includes("deepseek.com")||e.toLowerCase().startsWith("deepseek-")?"deepseek":t?"custom":"anthropic"}function D(e){const n=new Set;for(const o of Object.values(L)){const i=b(e,o);i&&n.add(i)}const t=Array.from(n).map((o,i)=>{const s=A(o,e),r={id:o,name:o,provider:s,isDefault:i===0};return s==="deepseek"?{...r,supportedReasoningEfforts:P,defaultReasoningEffort:b(e,"CLAUDE_CODE_EFFORT_LEVEL")??"max"}:h(r)});return d(t)}function V(e=process.env){return D(e)}function G(e,n=process.env){return e.map(t=>{if(!["default","sonnet","opus","haiku"].includes(t.id))return t;const o=t.id,i=b(n,L[o]);if(!i)return t;const r=`Claude Code alias: ${y[o]}`;return{...t,name:i,description:t.description?`${r} \xB7 ${t.description}`:r,provider:A(i,n)}})}function z(e){const n=g(e),t=new Map;for(const i of["sonnet","opus","haiku"])for(const s of n.matchAll(new RegExp(`\\bclaude-${i}-[0-9.-]+\\b`,"gi"))){const r=s[0].trim().toLowerCase().replace(/\./g,"-").replace(/-+$/g,""),a=w(r,i);if(!a)continue;const u=t.get(i);(!u||T(u,a)<0)&&t.set(i,a)}const o=[];for(const i of["default","sonnet","opus","haiku"]){if(!new RegExp(`\\b${i}\\b`,"i").test(n))continue;const s=(i==="default"?t.get("sonnet"):t.get(i))??null;o.push(h({id:i,name:y[i],description:$(s),provider:"anthropic",isDefault:i==="default"}))}return d(o)}function q(e=process.env){const n=D(e);return n.length>0?n:G([{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(t=>t.id==="haiku"?t:h(t))}function K(e){const n=g(e),t=[];for(const o of n.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;t.push({id:s,name:x(s),description:r,provider:"openai",isDefault:/\bcurrent\b/i.test(o)||/\bselected\b/i.test(o)})}return d(t)}function W(e){const n=typeof e=="object"&&e!==null?e:{},t=typeof n.config?.model=="string"?n.config.model:void 0,o=typeof n.config?.model_reasoning_effort=="string"?n.config.model_reasoning_effort:void 0,i=[];for(const s of n.data??[]){if(typeof s!="object"||s===null)continue;const r=s,a=typeof r.id=="string"?r.id:typeof r.model=="string"?r.model:"";if(!a)continue;const u=typeof r.displayName=="string"?r.displayName:typeof r.name=="string"?r.name:void 0,c=typeof r.description=="string"?r.description:void 0,l=typeof r.defaultReasoningEffort=="string"?r.defaultReasoningEffort:void 0,p=Array.isArray(r.supportedReasoningEfforts)?r.supportedReasoningEfforts.map(f=>{if(typeof f!="object"||f===null)return null;const m=f,v=typeof m.reasoningEffort=="string"?m.reasoningEffort:typeof m.id=="string"?m.id:"";return v?{id:v,name:C(v),description:typeof m.description=="string"?m.description:void 0}:null}).filter(f=>f!=null):void 0,S=Array.isArray(r.additionalSpeedTiers)?r.additionalSpeedTiers.filter(f=>typeof f=="string"):void 0;i.push({id:a,name:u||x(a),description:c,provider:"openai",isDefault:t?t===a:r.isDefault===!0,supportedReasoningEfforts:p,defaultReasoningEffort:l,additionalSpeedTiers:S})}return t&&!i.some(s=>s.id===t)&&i.unshift({id:t,name:x(t),provider:"openai",isDefault:!0,defaultReasoningEffort:o}),k(d(i),t)}function J(e){const n=g(e),t=[];for(const o of n.matchAll(/\b(?:auto-)?gemini-[a-z0-9.-]+\b/gi)){const i=o[0].trim();t.push({id:i,name:i,provider:"google",isDefault:/\bcurrent\b/i.test(n)&&n.includes(i)})}for(const o of n.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],a=_(i,s,r);t.push({id:a,name:`Gemini ${i} ${s.replace(/-/g," ")}`.trim(),provider:"google",isDefault:/\bcurrent\b/i.test(n)&&n.includes(o[0]??"")})}for(const o of n.matchAll(/\bAuto\s*Gemini\s*(\d(?:\.\d)?)\b/gi)){const i=o[1]??"",s=`auto-gemini-${i}`;t.push({id:s,name:`Auto Gemini ${i}`,provider:"google",isDefault:/\bcurrent\b/i.test(n)&&n.includes(o[0]??"")})}return d(t)}function X(){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{G as applyClaudeModelEnvOverrides,V as discoverClaudeAliasModelsFromEnv,q as fallbackClaudeAliasModels,N as fallbackCodexModels,X as fallbackGeminiModels,H as fallbackWorkBuddyModels,A as inferClaudeOverrideProvider,z as parseClaudeBinaryModels,j as parseClaudeModels,W as parseCodexAppServerModels,K as parseCodexModels,I as parseCursorModels,J as parseGeminiModels,U as parseOpenClawModels,B as parseOpenCodeModels,b as readEnvValue,g as stripAnsi};
@@ -1 +1 @@
1
- import{getAgentConfigSummary as m}from"../config-status.js";import{isCacheFresh as h,readCache as a,writeCache as f}from"./cache.js";import{discoverModelsForAgent as A}from"./discovery.js";import{getAgentRuntimeSummary as y}from"../runtime-compatibility.js";import{resolveManagedAgentRuntimeProtection as v}from"../../security/managed-agent-runtime.js";function x(e){const r=new Set,t=[];for(const n of e)!n.id||r.has(n.id)||(r.add(n.id),t.push(n));return t}function g(e){const t=e.type!=="pi"&&e.type!=="openclaw"?v({agentType:e.type,runtimeVersion:e.version,platform:e.runtimePlatform,isWsl:e.runtimeIsWsl,executableFingerprint:e.executableFingerprint,requireExecutableFingerprint:!0}):null;return{supportsManagedAgent:t?.level==="hard",supportsWorker:e.type!=="pi"&&e.type!=="openclaw",supportsManagerMode:e.type==="codex"||e.type==="claude",...t?{managedAgentProtection:t}:{}}}function I(e){const r=a();return e.map(t=>{const n=m(t.type),s=y(t);return{type:t.type,models:r.agents[t.type]?.models??t.models??[],...g(t),...n?{config:n}:{},...s?{runtime:s}:{}}})}async function q(e,r){const t=a();for(const n of e)delete t.agents[n.type];return f(t),C(e,r)}async function C(e,r){const t=a();let n=!1;const s=[];for(const o of e){const i=t.agents[o.type];let c;if(h(i,o.version))c=i.models;else{let p=null;try{p=x(await A(o,r)),c=p.length>0?p:i?.models??o.models??[]}catch{c=i?.models??o.models??[]}if(p&&p.length>0){const d={version:o.version,refreshedAt:Date.now(),models:c};JSON.stringify(i)!==JSON.stringify(d)&&(t.agents[o.type]=d,n=!0)}}const u=m(o.type),l=y(o);s.push({type:o.type,models:c,...g(o),...u?{config:u}:{},...l?{runtime:l}:{}})}return n&&f(t),s}export{I as getCachedAgentInfos,q as refreshAgentInfos,C as resolveAgentInfos};
1
+ import{getAgentConfigSummary as f}from"../config-status.js";import{isCacheFresh as v,readCache as l,writeCache as y}from"./cache.js";import{discoverModelsForAgent as A}from"./discovery.js";import{getAgentRuntimeSummary as g}from"../runtime-compatibility.js";import{resolveManagedAgentRuntimeProtection as C}from"../../security/managed-agent-runtime.js";const S={claude:"claude-alias-v2"};function x(e){const r=new Set,t=[];for(const n of e)!n.id||r.has(n.id)||(r.add(n.id),t.push(n));return t}function h(e){const t=e.type!=="pi"&&e.type!=="openclaw"?C({agentType:e.type,runtimeVersion:e.version,platform:e.runtimePlatform,isWsl:e.runtimeIsWsl,executableFingerprint:e.executableFingerprint,requireExecutableFingerprint:!0}):null;return{supportsManagedAgent:t?.level==="hard"||t?.level==="partial",supportsWorker:e.type!=="pi"&&e.type!=="openclaw",supportsManagerMode:e.type==="codex"||e.type==="claude"||e.type==="pi-coding-agent",...t?{managedAgentProtection:t}:{}}}function F(e){const r=l();return e.map(t=>{const n=f(t.type),s=g(t);return{type:t.type,models:r.agents[t.type]?.models??t.models??[],...h(t),...n?{config:n}:{},...s?{runtime:s}:{}}})}async function b(e,r){const t=l();for(const n of e)delete t.agents[n.type];return y(t),M(e,r)}async function M(e,r){const t=l();let n=!1;const s=[];for(const o of e){const i=t.agents[o.type],a=S[o.type];let c;if(v(i,o.version,a))c=i.models;else{let p=null;try{p=x(await A(o,r)),c=p.length>0?p:i?.models??o.models??[]}catch{c=i?.models??o.models??[]}if(p&&p.length>0){const m={version:o.version,...a?{sourceRevision:a}:{},refreshedAt:Date.now(),models:c};JSON.stringify(i)!==JSON.stringify(m)&&(t.agents[o.type]=m,n=!0)}}const u=f(o.type),d=g(o);s.push({type:o.type,models:c,...h(o),...u?{config:u}:{},...d?{runtime:d}:{}})}return n&&y(t),s}export{F as getCachedAgentInfos,b as refreshAgentInfos,M as resolveAgentInfos};
@@ -5,6 +5,7 @@ export declare const MODEL_CACHE_PATH: string;
5
5
  export declare const DISCOVERY_WORKDIR: string;
6
6
  export type CacheEntry = {
7
7
  version?: string;
8
+ sourceRevision?: string;
8
9
  refreshedAt: number;
9
10
  models: ModelInfo[];
10
11
  };
@@ -0,0 +1,7 @@
1
+ import type { ManagedAgentRuntimeSecurityDeclaration } from '../security/managed-agent-runtime.js';
2
+ /** Pi's native tool allowlist is useful but is not a process sandbox. The
3
+ * declaration deliberately reports host-wide reachability because Bash can
4
+ * cross filesystem, network, socket and GUI boundaries on every supported
5
+ * platform. Shennian may still apply a narrower authorization ceiling, but the
6
+ * UI must present the gap as partial protection. */
7
+ export declare const PI_CODING_AGENT_MANAGED_RUNTIME_SECURITY: ManagedAgentRuntimeSecurityDeclaration;
@@ -0,0 +1 @@
1
+ const l={minimumRuntimeVersion:"0.85.0",maximumRuntimeVersionExclusive:"0.86.0",platforms:Object.fromEntries(["darwin","linux","wsl","win32"].map(e=>[e,{level:"partial",fileAccess:{"workspace-read":!1,"workspace-write":!1,"host-full":!0},externalCapabilities:{commandNetwork:{allow:!0,deny:!1},webSearch:{allow:!0,deny:!1},browser:{allow:!0,deny:!1},computerUse:{allow:!0,deny:!1},mcp:{allow:!0,deny:!1}},knownGaps:["sandbox.toolAllowlistOnly","shell.hostFilesystemReachable","shell.networkReachable","shell.localSocketsReachable"]}]))};export{l as PI_CODING_AGENT_MANAGED_RUNTIME_SECURITY};
@@ -0,0 +1,55 @@
1
+ import type { ChatAttachmentMeta, ExternalChannelSessionStatus } from '@shennian/wire';
2
+ import { AgentAdapter, type AgentSendContext } from './adapter.js';
3
+ import type { CompiledManagedAgentPolicy } from '../security/managed-agent-policy.js';
4
+ export declare class PiCodingAgentAdapter extends AgentAdapter {
5
+ readonly type: "pi-coding-agent";
6
+ private process;
7
+ private rpc;
8
+ private shennianSessionId;
9
+ private workDir;
10
+ private sessionDir;
11
+ private agentSessionId;
12
+ private externalChannel;
13
+ private extraEnv;
14
+ private managedAgentPolicy;
15
+ private runId;
16
+ private seq;
17
+ private active;
18
+ private terminal;
19
+ private stderr;
20
+ private lastUsage;
21
+ private promptFile;
22
+ private modelBroker;
23
+ private persistNativeSession;
24
+ private validationRoot;
25
+ private runPhase;
26
+ configure(options: {
27
+ sessionId?: string;
28
+ externalChannel?: ExternalChannelSessionStatus | null;
29
+ env?: NodeJS.ProcessEnv;
30
+ managedAgentPolicy?: CompiledManagedAgentPolicy | null;
31
+ }): void;
32
+ start(sessionId: string, workDir: string, agentSessionId?: string | null, options?: import('./adapter.js').AgentStartOptions): Promise<void>;
33
+ send(text: string, modelId?: string, reasoningEffort?: string, attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null, context?: AgentSendContext): Promise<void>;
34
+ resume(agentSessionId: string): Promise<void>;
35
+ stop(): Promise<void>;
36
+ getStatus(): Promise<{
37
+ active: boolean;
38
+ runId?: string | null;
39
+ runPhase?: 'thinking' | 'tool_running' | 'streaming_text' | 'waiting_approval' | 'waiting_user_input' | null;
40
+ canStop?: boolean;
41
+ }>;
42
+ setTitle(_agentSessionId: string, title: string): Promise<void>;
43
+ private ensureProcess;
44
+ private managedTools;
45
+ private ownsSessionFile;
46
+ private readState;
47
+ private requireRpc;
48
+ private handleRpcEvent;
49
+ private emitEvent;
50
+ private emitTerminal;
51
+ private emitError;
52
+ private prepareHostedModel;
53
+ private stopModelBroker;
54
+ private stopProcess;
55
+ }
@@ -0,0 +1,4 @@
1
+ import c from"node:fs";import u from"node:path";import{randomUUID as w}from"node:crypto";import{AgentAdapter as _,registerAgent as E}from"./adapter.js";import{resolveBuiltinCommand as A,spawnAgentCommand as k}from"./command-spec.js";import{buildAgentProcessEnv as v,buildManagedAgentProcessEnv as x}from"../agent-env.js";import{loadConfig as T,resolveShennianPath as f}from"../config/index.js";import{buildInlineChannelPreamble as N,buildPlatformInstructions as R}from"./platform-instructions.js";import{PiRpcClient as b}from"./pi-rpc-client.js";import{registerManagedAgentRuntimeSecurity as M}from"../security/managed-agent-runtime.js";import{PI_CODING_AGENT_MANAGED_RUNTIME_SECURITY as C}from"./pi-coding-agent-managed-permissions.js";import{PiManagedModelBroker as D}from"./pi-managed-model-broker.js";import{writePiManagedExtension as B}from"./pi-managed-extension.js";import{recordPiSessionOwnership as O}from"./pi-session-ownership.js";M("pi-coding-agent",C);const q=32*1024,j=256*1024,U=3e3;function g(i){return i.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,180)||"session"}function F(i){return i.data&&typeof i.data=="object"&&!Array.isArray(i.data)?i.data:{}}function $(i){if(typeof i=="string")return i;if(!i||typeof i!="object")return"";const t=i.content;return Array.isArray(t)?t.map(s=>{if(!s||typeof s!="object")return"";const e=s;return e.type==="text"&&typeof e.text=="string"?e.text:""}).join(""):""}function y(i,t=j){return i.length<=t?i:`${i.slice(0,t)}
2
+ [truncated]`}function G(i){return y(i,2e3).replace(/Bearer\s+[A-Za-z0-9._~-]+/gi,"Bearer [redacted]").replace(/\b(?:pimc|mrc)_[A-Za-z0-9_-]{20,}\b/g,"[redacted-capability]").replace(/\bsk-[A-Za-z0-9_-]{12,}\b/g,"[redacted-key]")}function z(i){try{return y(JSON.stringify(i))}catch{return"[unserializable]"}}function P(i){if(!i||typeof i!="object")return;const t=i;if(!(typeof t.input!="number"&&typeof t.output!="number"))return{inputTokens:typeof t.input=="number"?t.input:0,outputTokens:typeof t.output=="number"?t.output:0}}function H(i){const t=i?.trim();if(!t)return{};const s=t.indexOf("/");return s<=0||s===t.length-1?{modelId:t}:{provider:t.slice(0,s),modelId:t.slice(s+1)}}function X(i,t,s,e,n,a){const l=N(s,e,n,a),h=t?.filter(o=>o.kind!=="image")??[];if(!h.length)return`${l}${i}`;const p=h.map(o=>`[${o.name}](<${o.path}>)`);return`${l}${[i,"",...p].join(`
3
+ `)}`}function L(i,t){const s=[];for(const e of i??[]){if(e.kind!=="image"||!e.mimeType.startsWith("image/"))continue;let n=e.previewData?.trim()??"";const a=n.indexOf(",");if(n.startsWith("data:")&&a>=0&&(n=n.slice(a+1)),!n&&t&&e.path&&!/^https?:\/\//i.test(e.path))try{const l=c.statSync(e.path);l.isFile()&&l.size<=10*1024*1024&&(n=c.readFileSync(e.path).toString("base64"))}catch{n=""}n&&s.push({type:"image",data:n,mimeType:e.mimeType})}return s}class Z extends _{type="pi-coding-agent";process=null;rpc=null;shennianSessionId="";workDir="";sessionDir="";agentSessionId=null;externalChannel=null;extraEnv={};managedAgentPolicy=null;runId="";seq=0;active=!1;terminal=!0;stderr="";lastUsage;promptFile=null;modelBroker=null;persistNativeSession=!0;validationRoot=null;runPhase=null;configure(t){t.sessionId&&(this.shennianSessionId=t.sessionId),this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{},"managedAgentPolicy"in t&&(this.managedAgentPolicy=t.managedAgentPolicy??null)}async start(t,s,e,n){await this.stopProcess(),this.shennianSessionId=t,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??s,this.agentSessionId=e??null;const a=f("runtime","pi-coding-agent",g(t));this.persistNativeSession=n?.persistNativeSession!==!1,this.validationRoot=this.persistNativeSession?null:u.join(a,`validation-${w()}`),this.sessionDir=this.validationRoot?u.join(this.validationRoot,"sessions"):u.join(a,"sessions"),c.mkdirSync(this.sessionDir,{recursive:!0,mode:448}),process.platform!=="win32"&&c.chmodSync(this.sessionDir,448),this.active=!1,this.terminal=!0}async send(t,s,e,n,a,l){await this.ensureProcess(a);const h=this.requireRpc(),p=await this.readState(),o=!!(p.isStreaming||p.isCompacting);(!o||!this.runId)&&(this.runId=w(),this.seq=0,this.terminal=!1,this.lastUsage=void 0,this.runPhase="thinking");const d=H(s);if(d.modelId&&!o&&(p.model?.id!==d.modelId||d.provider&&p.model?.provider!==d.provider)){if(!d.provider)throw new Error("Pi model selection must include provider/modelId");await h.request("set_model",{provider:d.provider,modelId:d.modelId})}e&&!o&&await h.request("set_thinking_level",{level:e});const r=o?l?.source==="room_activation"?"follow_up":"steer":"prompt",m={message:X(t,n,this.workDir,this.externalChannel,this.shennianSessionId,null)},S=L(n,!this.managedAgentPolicy);S.length&&!this.modelBroker&&(m.images=S),this.modelBroker?.setTurnActive(!0);try{await h.request(r,m)}catch(I){throw this.modelBroker?.setTurnActive(!1),I}}async resume(t){await this.stopProcess(),this.agentSessionId=t}async stop(){const t=this.rpc;t&&(await t.request("clear_queue").catch(()=>{}),await t.request("abort").catch(()=>{})),!this.terminal&&this.runId&&this.emitTerminal({state:"aborted"}),await this.stopProcess()}async getStatus(){if(!this.rpc||!this.process)return{active:!1,runId:null,canStop:!1};const t=await this.readState().catch(()=>null),s=!!(t?.isStreaming||t?.isCompacting||this.active);return{active:s,runId:s?this.runId:null,runPhase:s?this.runPhase??"thinking":null,canStop:s}}async setTitle(t,s){this.rpc&&await this.rpc.request("set_session_name",{name:s.slice(0,200)})}async ensureProcess(t){if(this.process&&this.rpc)return;const s=A("pi-coding-agent");if(!s)throw new Error('Command "pi" not found. Install @earendil-works/pi-coding-agent from the official package.');const e=["--mode","rpc","--session-dir",this.sessionDir,"--offline"];this.agentSessionId&&e.push("--session",this.agentSessionId);const n=await this.prepareHostedModel();if(n&&e.push("--provider","shennian-dashscope","--model","deepseek-v4-flash-0731"),this.managedAgentPolicy){e.push("--no-extensions","--no-skills","--no-prompt-templates","--no-context-files");const r=this.managedTools(),m=B({outputPath:u.join(f("runtime","pi-coding-agent",g(this.shennianSessionId)),"managed-extension.ts"),policy:this.managedAgentPolicy,allowRoomControl:!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT,allowManagerControl:!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,allowHostShell:this.managedAgentPolicy.adapterPolicy.fileAccess==="host-full"});e.push("--no-builtin-tools","--extension",m),r.length?e.push("--tools",r.join(",")):e.push("--no-tools")}const a=R(this.workDir,this.externalChannel,this.shennianSessionId,t),l=f("runtime","pi-coding-agent",g(this.shennianSessionId));c.mkdirSync(l,{recursive:!0,mode:448}),this.promptFile=u.join(l,"instructions.md"),c.writeFileSync(this.promptFile,a,{encoding:"utf8",mode:384}),process.platform!=="win32"&&c.chmodSync(this.promptFile,384),e.push("--append-system-prompt",this.promptFile);const h={NO_COLOR:"1",...n?{PI_CODING_AGENT_DIR:n.configDir}:{}},p=this.managedAgentPolicy?x({agentType:this.type,providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:h}):v({...h,...this.extraEnv});let o;try{o=k(s,e,{cwd:this.workDir,stdio:["pipe","pipe","pipe"],env:p})}catch(r){throw await this.stopModelBroker(),r}this.process=o,this.stderr="",o.stderr?.on("data",r=>{const m=typeof r=="string"?r:r.toString("utf8");this.stderr=y(`${this.stderr}${m}`,q)});const d=new b(o);this.rpc=d,d.on("event",r=>this.handleRpcEvent(r)),d.on("protocolError",r=>this.emitError(r.message)),o.once("close",r=>{this.process===o&&(this.process=null,this.rpc=null,this.terminal||this.emitError(r===0?"Pi RPC process closed before agent_settled":`Pi RPC process exited with code ${r??"unknown"}${this.stderr?`: ${this.stderr}`:""}`),this.stopModelBroker())}),o.once("error",r=>{this.process===o&&this.emitError(r.message)});try{const r=await this.readState();if(!r.sessionId)throw new Error("Pi RPC did not return a session ID");if(r.isStreaming||r.isCompacting)throw new Error("Pi RPC session is not idle after startup");if(this.agentSessionId&&r.sessionId!==this.agentSessionId)throw new Error("Pi RPC resumed a different session");if(!r.sessionFile||!this.ownsSessionFile(r.sessionFile))throw new Error("Pi RPC returned a session file outside the Shennian-owned directory");this.agentSessionId=r.sessionId,this.persistNativeSession&&O(r.sessionId,this.sessionDir)}catch(r){throw await this.stopProcess(),r}}managedTools(){const t=this.managedAgentPolicy?.adapterPolicy;if(!t)return[];const s=["read","grep","find","ls"];(t.fileAccess==="workspace-write"||t.fileAccess==="host-full")&&s.push("edit","write");const e=!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,n=!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT;return(e||n||t.fileAccess==="host-full")&&s.push("bash"),s}ownsSessionFile(t){const s=u.resolve(this.sessionDir),e=u.resolve(t),n=u.relative(s,e);return n!==""&&!n.startsWith("..")&&!u.isAbsolute(n)}async readState(){const t=await this.requireRpc().request("get_state");return F(t)}requireRpc(){if(!this.rpc)throw new Error("Pi RPC process is not running");return this.rpc}handleRpcEvent(t){if(t.type==="agent_start"){this.active=!0,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:this.agentSessionId??void 0});return}if(t.type==="message_update"){this.lastUsage=P(t.usage)??this.lastUsage;const s=t.assistantMessageEvent;if(!s||typeof s!="object")return;const e=s;e.type==="text_delta"&&typeof e.delta=="string"?(this.runPhase="streaming_text",this.emitEvent({state:"delta",text:e.delta})):e.type==="thinking_delta"&&typeof e.delta=="string"&&(this.runPhase="thinking",this.emitEvent({state:"delta",text:e.delta,thinking:!0}));return}if(t.type==="tool_execution_start"){this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:typeof t.toolName=="string"?t.toolName:"tool",args:t.args&&typeof t.args=="object"&&!Array.isArray(t.args)?t.args:{}});return}if(t.type==="tool_execution_end"){this.runPhase="thinking",this.emitEvent({state:"tool-result",name:typeof t.toolName=="string"?t.toolName:"tool",result:$(t.result)||z(t.result)});return}if(t.type==="tool_execution_update"){this.emitEvent({state:"notify",runPhase:"tool_running",message:"Pi tool is running"});return}if(t.type==="message_end"){const s=t.message;if(s&&typeof s=="object"){const e=s;this.lastUsage=P(e.usage)??this.lastUsage,e.stopReason==="error"&&(this.modelBroker?.setTurnActive(!1),this.emitError(typeof e.errorMessage=="string"?e.errorMessage:"Pi model request failed"))}return}if(t.type==="compaction_start"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is compacting context"});return}if(t.type==="auto_retry_start"||t.type==="summarization_retry_scheduled"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is retrying"});return}if(t.type==="extension_ui_request"){typeof t.id=="string"&&this.rpc?.notify("extension_ui_response",{id:t.id,cancelled:!0});return}if(t.type==="extension_error"){this.modelBroker?.setTurnActive(!1),this.emitError(typeof t.error=="string"?t.error:"Pi extension failed");return}t.type==="agent_settled"&&(this.active=!1,this.modelBroker?.setTurnActive(!1),this.emitTerminal({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.lastUsage}))}emitEvent(t){this.runId&&this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}emitTerminal(t){this.terminal||(this.terminal=!0,this.active=!1,this.runPhase=null,this.emitEvent(t))}emitError(t){this.modelBroker?.setTurnActive(!1),this.emitTerminal({state:"error",message:G(t)})}async prepareHostedModel(){const t=T(),s=t.machineToken?.trim();if(!s)return null;const e=new D({serverUrl:t.serverUrl?.trim()||"https://shennian.net",machineToken:s,sessionId:this.shennianSessionId}),n=await e.start(),a=f("runtime","pi-coding-agent",g(this.shennianSessionId),"agent-config");c.mkdirSync(a,{recursive:!0,mode:448}),process.platform!=="win32"&&c.chmodSync(a,448);const l=u.join(a,"models.json"),h={providers:{"shennian-dashscope":{baseUrl:n.baseUrl,api:"openai-completions",apiKey:n.apiKey,authHeader:!0,compat:{supportsDeveloperRole:!1,supportsReasoningEffort:!0},models:[{id:"deepseek-v4-flash-0731",name:"DeepSeek V4 Flash",reasoning:!0,input:["text"],thinkingLevelMap:{off:null,minimal:null,low:"low",medium:null,high:"high",xhigh:null,max:"max"}}]}}};return c.writeFileSync(l,`${JSON.stringify(h,null,2)}
4
+ `,{encoding:"utf8",mode:384}),process.platform!=="win32"&&c.chmodSync(l,384),this.modelBroker=e,{configDir:a}}async stopModelBroker(){const t=this.modelBroker;this.modelBroker=null,await t?.stop().catch(()=>{})}async stopProcess(){const t=this.process;this.process=null,this.rpc?.close(),this.rpc=null,t?(t.kill("SIGTERM"),await new Promise(s=>{let e=!1;const n=()=>{e||(e=!0,s())};t.once("close",n),setTimeout(()=>{t.kill("SIGKILL"),n()},U).unref()}),await this.stopModelBroker()):await this.stopModelBroker(),this.validationRoot&&(c.rmSync(this.validationRoot,{recursive:!0,force:!0}),this.validationRoot=null)}}E("pi-coding-agent",()=>new Z);export{Z as PiCodingAgentAdapter};
@@ -0,0 +1,12 @@
1
+ import type { CompiledManagedAgentPolicy } from '../security/managed-agent-policy.js';
2
+ /** Generate a dependency-light Pi extension inside the private runtime dir.
3
+ * The extension replaces Pi's built-ins: every file path is resolved beneath
4
+ * the verified workspace and Bash is reduced to the capability-scoped
5
+ * `shennian room|manager` CLI. This is defense in depth, not an OS sandbox. */
6
+ export declare function writePiManagedExtension(input: {
7
+ outputPath: string;
8
+ policy: CompiledManagedAgentPolicy;
9
+ allowRoomControl: boolean;
10
+ allowManagerControl: boolean;
11
+ allowHostShell: boolean;
12
+ }): string;
@@ -0,0 +1,89 @@
1
+ import t from"node:fs";import n from"node:path";function p(e){const r=n.resolve(e.policy.adapterPolicy.workDir),i=e.policy.adapterPolicy.fileAccess!=="workspace-read",o=e.allowRoomControl,a=e.allowManagerControl,s=e.allowHostShell,c=`
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { spawn } from 'node:child_process';
5
+ import { Type } from 'typebox';
6
+
7
+ const ROOT = ${JSON.stringify(r)};
8
+ const WRITABLE = ${JSON.stringify(i)};
9
+ const ALLOW_ROOM = ${JSON.stringify(o)};
10
+ const ALLOW_MANAGER = ${JSON.stringify(a)};
11
+ const ALLOW_HOST_SHELL = ${JSON.stringify(s)};
12
+ const MAX_READ = 1024 * 1024;
13
+ const MAX_WRITE = 4 * 1024 * 1024;
14
+ const SENSITIVE = /(^|[\\/])(\\.env(?:\\.|$)|\\.ssh|\\.aws|\\.config|\\.shennian|Library[\\/]Keychains|AppData[\\/]Roaming[\\/]Microsoft[\\/]Credentials)([\\/]|$)/i;
15
+
16
+ function inside(root, candidate) {
17
+ const relative = path.relative(root, candidate);
18
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
19
+ }
20
+ function rejectSensitive(candidate) {
21
+ if (SENSITIVE.test(candidate)) throw new Error('managed_path_sensitive');
22
+ }
23
+ function resolveExisting(raw) {
24
+ const candidate = path.resolve(ROOT, String(raw || '.'));
25
+ rejectSensitive(candidate);
26
+ const real = fs.realpathSync(candidate);
27
+ if (!inside(ROOT, real)) throw new Error('managed_path_outside_workspace');
28
+ return real;
29
+ }
30
+ function resolveWrite(raw) {
31
+ if (!WRITABLE) throw new Error('managed_workspace_read_only');
32
+ const candidate = path.resolve(ROOT, String(raw || ''));
33
+ rejectSensitive(candidate);
34
+ const parent = fs.realpathSync(path.dirname(candidate));
35
+ if (!inside(ROOT, parent)) throw new Error('managed_path_outside_workspace');
36
+ if (fs.existsSync(candidate)) {
37
+ const stat = fs.lstatSync(candidate);
38
+ if (stat.isSymbolicLink() || (stat.isFile() && stat.nlink > 1)) throw new Error('managed_path_link_rejected');
39
+ const real = fs.realpathSync(candidate);
40
+ if (!inside(ROOT, real)) throw new Error('managed_path_outside_workspace');
41
+ }
42
+ return candidate;
43
+ }
44
+ function textResult(text) { return { content: [{ type: 'text', text }], details: {} }; }
45
+ function tokenize(command) {
46
+ const result = []; let current = ''; let quote = '';
47
+ for (const ch of String(command || '')) {
48
+ if (quote) { if (ch === quote) quote = ''; else current += ch; continue; }
49
+ if (ch === '"' || ch === "'") { quote = ch; continue; }
50
+ if (/\\s/.test(ch)) { if (current) { result.push(current); current = ''; } continue; }
51
+ if (';&|><$()\\n\\r'.includes(ch) || ch.charCodeAt(0) === 96) throw new Error('managed_shell_syntax_rejected');
52
+ current += ch;
53
+ }
54
+ if (quote) throw new Error('managed_shell_quote_unterminated');
55
+ if (current) result.push(current);
56
+ return result;
57
+ }
58
+
59
+ export default function (pi) {
60
+ pi.registerTool({ name: 'read', label: 'Read', description: 'Read a file inside the authorized workspace.', parameters: Type.Object({ path: Type.String(), offset: Type.Optional(Type.Number()), limit: Type.Optional(Type.Number()) }), async execute(_id, p) {
61
+ const file = resolveExisting(p.path); const stat = fs.statSync(file); if (!stat.isFile() || stat.size > MAX_READ) throw new Error('managed_read_size_rejected');
62
+ const lines = fs.readFileSync(file, 'utf8').split(/\\r?\\n/); const offset = Math.max(1, Math.floor(p.offset || 1)); const limit = Math.min(2000, Math.max(1, Math.floor(p.limit || 2000)));
63
+ return textResult(lines.slice(offset - 1, offset - 1 + limit).join('\\n'));
64
+ }});
65
+ pi.registerTool({ name: 'ls', label: 'List', description: 'List a directory inside the authorized workspace.', parameters: Type.Object({ path: Type.Optional(Type.String()) }), async execute(_id, p) {
66
+ const dir = resolveExisting(p.path || '.'); return textResult(fs.readdirSync(dir, { withFileTypes: true }).slice(0, 1000).map(e => e.name + (e.isDirectory() ? '/' : '')).join('\\n'));
67
+ }});
68
+ pi.registerTool({ name: 'find', label: 'Find', description: 'Find file names inside the authorized workspace.', parameters: Type.Object({ pattern: Type.String(), path: Type.Optional(Type.String()) }), async execute(_id, p) {
69
+ const base = resolveExisting(p.path || '.'); const needle = String(p.pattern).toLowerCase(); const out = []; const queue = [base];
70
+ while (queue.length && out.length < 1000) { const dir = queue.shift(); for (const e of fs.readdirSync(dir, { withFileTypes: true })) { const full = path.join(dir, e.name); if (SENSITIVE.test(full) || e.isSymbolicLink()) continue; if (e.name.toLowerCase().includes(needle)) out.push(path.relative(ROOT, full)); if (e.isDirectory()) queue.push(full); } }
71
+ return textResult(out.join('\\n'));
72
+ }});
73
+ pi.registerTool({ name: 'grep', label: 'Grep', description: 'Search text files inside the authorized workspace.', parameters: Type.Object({ pattern: Type.String(), path: Type.Optional(Type.String()) }), async execute(_id, p) {
74
+ const base = resolveExisting(p.path || '.'); const regex = new RegExp(String(p.pattern), 'i'); const out = []; const queue = [base];
75
+ while (queue.length && out.length < 1000) { const next = queue.shift(); const stat = fs.statSync(next); if (stat.isDirectory()) { for (const e of fs.readdirSync(next, { withFileTypes: true })) { const full = path.join(next, e.name); if (!SENSITIVE.test(full) && !e.isSymbolicLink()) queue.push(full); } continue; } if (!stat.isFile() || stat.size > MAX_READ) continue; const lines = fs.readFileSync(next, 'utf8').split(/\\r?\\n/); lines.forEach((line, i) => { if (out.length < 1000 && regex.test(line)) out.push(path.relative(ROOT, next) + ':' + (i + 1) + ':' + line); }); }
76
+ return textResult(out.join('\\n'));
77
+ }});
78
+ pi.registerTool({ name: 'write', label: 'Write', description: 'Write a file inside the authorized workspace.', parameters: Type.Object({ path: Type.String(), content: Type.String() }), async execute(_id, p) {
79
+ if (Buffer.byteLength(p.content, 'utf8') > MAX_WRITE) throw new Error('managed_write_size_rejected'); const file = resolveWrite(p.path); fs.writeFileSync(file, p.content, { encoding: 'utf8', flag: 'w' }); return textResult('Wrote ' + path.relative(ROOT, file));
80
+ }});
81
+ pi.registerTool({ name: 'edit', label: 'Edit', description: 'Replace exact text inside an authorized workspace file.', parameters: Type.Object({ path: Type.String(), oldText: Type.String(), newText: Type.String() }), async execute(_id, p) {
82
+ const file = resolveWrite(p.path); const current = fs.readFileSync(file, 'utf8'); if (!p.oldText || !current.includes(p.oldText)) throw new Error('managed_edit_target_not_found'); const next = current.replace(p.oldText, p.newText); if (Buffer.byteLength(next, 'utf8') > MAX_WRITE) throw new Error('managed_write_size_rejected'); fs.writeFileSync(file, next, { encoding: 'utf8', flag: 'w' }); return textResult('Edited ' + path.relative(ROOT, file));
83
+ }});
84
+ pi.registerTool({ name: 'bash', label: 'Shennian control', description: 'Run only capability-scoped shennian room or manager commands. General shell commands are unavailable.', parameters: Type.Object({ command: Type.String() }), async execute(_id, p, signal) {
85
+ const argv = tokenize(p.command); const scoped = argv[0] === 'shennian' && ((ALLOW_ROOM && argv[1] === 'room') || (ALLOW_MANAGER && argv[1] === 'manager')); if (!ALLOW_HOST_SHELL && !scoped) throw new Error('managed_shell_command_rejected');
86
+ return await new Promise((resolve, reject) => { const child = ALLOW_HOST_SHELL ? spawn(String(p.command), [], { cwd: ROOT, shell: true, env: process.env, windowsHide: true }) : spawn('shennian', argv.slice(1), { cwd: ROOT, shell: false, env: process.env, windowsHide: true }); let output = ''; const add = c => { output = (output + String(c)).slice(0, 256 * 1024); }; child.stdout.on('data', add); child.stderr.on('data', add); signal?.addEventListener('abort', () => child.kill('SIGTERM'), { once: true }); child.once('error', reject); child.once('close', code => resolve(textResult(output + '\\n[exit ' + code + ']'))); });
87
+ }});
88
+ }
89
+ `.trimStart();return t.mkdirSync(n.dirname(e.outputPath),{recursive:!0,mode:448}),t.writeFileSync(e.outputPath,c,{encoding:"utf8",mode:384}),process.platform!=="win32"&&t.chmodSync(e.outputPath,384),e.outputPath}export{p as writePiManagedExtension};
@@ -0,0 +1,27 @@
1
+ export type PiManagedModelBrokerOptions = {
2
+ serverUrl: string;
3
+ machineToken: string;
4
+ sessionId: string;
5
+ fetchImpl?: typeof fetch;
6
+ };
7
+ export declare class PiManagedModelBroker {
8
+ private readonly options;
9
+ private server;
10
+ private capability;
11
+ private turnActive;
12
+ private port;
13
+ private upstreamCapability;
14
+ private upstreamCapabilityExpiresAt;
15
+ constructor(options: PiManagedModelBrokerOptions);
16
+ start(): Promise<{
17
+ baseUrl: string;
18
+ apiKey: string;
19
+ }>;
20
+ setTurnActive(active: boolean): void;
21
+ stop(): Promise<void>;
22
+ private connection;
23
+ private handle;
24
+ private json;
25
+ private ensureUpstreamCapability;
26
+ private revokeUpstreamCapability;
27
+ }
@@ -0,0 +1 @@
1
+ import f from"node:http";import{randomBytes as c,timingSafeEqual as y}from"node:crypto";const b=20*1024*1024,p=18e4;function _(a){return a?.startsWith("Bearer ")?a.slice(7):""}function g(a,t){const e=Buffer.from(a),r=Buffer.from(t);return e.length===r.length&&y(e,r)}async function v(a){const t=[];let e=0;for await(const r of a){const i=Buffer.isBuffer(r)?r:Buffer.from(r);if(e+=i.length,e>b)throw new Error("request_too_large");t.push(i)}return Buffer.concat(t)}class k{options;server=null;capability=c(32).toString("base64url");turnActive=!1;port=0;upstreamCapability=null;upstreamCapabilityExpiresAt=0;constructor(t){this.options=t}async start(){if(this.server)return this.connection();const t=f.createServer((r,i)=>{this.handle(r,i)});t.requestTimeout=p,t.headersTimeout=1e4,await new Promise((r,i)=>{t.once("error",i),t.listen(0,"127.0.0.1",()=>{t.removeListener("error",i),r()})});const e=t.address();if(!e||typeof e=="string")throw t.close(),new Error("pi_model_broker_address_unavailable");return this.server=t,this.port=e.port,this.connection()}setTurnActive(t){this.turnActive=t,t||this.revokeUpstreamCapability()}async stop(){this.turnActive=!1,await this.revokeUpstreamCapability(),this.capability=c(32).toString("base64url");const t=this.server;this.server=null,this.port=0,t&&await new Promise(e=>t.close(()=>e()))}connection(){if(!this.port)throw new Error("pi_model_broker_not_started");return{baseUrl:`http://127.0.0.1:${this.port}/v1`,apiKey:this.capability}}async handle(t,e){e.setHeader("Cache-Control","no-store");const r=_(t.headers.authorization);if(!r||!g(r,this.capability)){this.json(e,401,{error:{message:"Unauthorized",type:"authentication_error"}});return}if(t.method==="GET"&&t.url==="/v1/models"){this.json(e,200,{object:"list",data:[{id:"deepseek-v4-flash-0731",object:"model",owned_by:"shennian"}]});return}if(t.method!=="POST"||t.url!=="/v1/chat/completions"){this.json(e,404,{error:{message:"Not found",type:"invalid_request_error"}});return}if(!this.turnActive){this.json(e,403,{error:{message:"Managed model capability is not active",type:"permission_error"}});return}try{const i=await v(t),o=await this.ensureUpstreamCapability(),n=new AbortController;t.once("aborted",()=>n.abort());const h=setTimeout(()=>n.abort(),p);let s;try{s=await(this.options.fetchImpl??fetch)(`${this.options.serverUrl.replace(/\/$/,"")}/api/managed-model/v1/chat/completions`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${o}`},body:i.toString("utf8"),signal:n.signal})}finally{clearTimeout(h)}if(e.statusCode=s.status,e.setHeader("content-type",s.headers.get("content-type")||"application/json; charset=utf-8"),!s.body){e.end();return}const l=s.body.getReader();try{for(;;){const{done:u,value:d}=await l.read();if(u)break;e.write(Buffer.from(d))||await new Promise(m=>e.once("drain",m))}}finally{l.releaseLock()}e.end()}catch(i){if(e.headersSent){e.destroy();return}const o=i instanceof Error&&i.message==="request_too_large"?413:502;this.json(e,o,{error:{message:o===413?"Request too large":"Managed model request failed",type:o===413?"invalid_request_error":"upstream_error"}})}}json(t,e,r){t.statusCode=e,t.setHeader("content-type","application/json; charset=utf-8"),t.end(JSON.stringify(r))}async ensureUpstreamCapability(){if(this.upstreamCapability&&this.upstreamCapabilityExpiresAt>Date.now()+1e4)return this.upstreamCapability;const t=await(this.options.fetchImpl??fetch)(`${this.options.serverUrl.replace(/\/$/,"")}/api/managed-model/v1/capabilities`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${this.options.machineToken}`},body:JSON.stringify({sessionId:this.options.sessionId,agentType:"pi-coding-agent"})});if(!t.ok)throw new Error("managed_model_capability_issue_failed");const e=await t.json(),r=typeof e.expiresAt=="string"?Date.parse(e.expiresAt):NaN;if(typeof e.token!="string"||!/^pimc_[A-Za-z0-9_-]{43}$/.test(e.token)||e.model!=="deepseek-v4-flash-0731"||!Number.isFinite(r))throw new Error("managed_model_capability_response_invalid");return this.upstreamCapability=e.token,this.upstreamCapabilityExpiresAt=r,e.token}async revokeUpstreamCapability(){const t=this.upstreamCapability;this.upstreamCapability=null,this.upstreamCapabilityExpiresAt=0,t&&await(this.options.fetchImpl??fetch)(`${this.options.serverUrl.replace(/\/$/,"")}/api/managed-model/v1/capabilities`,{method:"DELETE",headers:{authorization:`Bearer ${t}`}}).catch(()=>{})}}export{k as PiManagedModelBroker};
@@ -0,0 +1,31 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { ChildProcess } from 'node:child_process';
3
+ export type PiRpcRecord = Record<string, unknown> & {
4
+ type?: string;
5
+ };
6
+ export type PiRpcClientEvents = {
7
+ event: [record: PiRpcRecord];
8
+ protocolError: [error: Error];
9
+ };
10
+ /** Strict LF-only JSONL transport. Node readline is intentionally not used:
11
+ * Pi allows U+2028/U+2029 inside JSON strings and documents that generic line
12
+ * readers can split those characters incorrectly. */
13
+ export declare class PiRpcClient extends EventEmitter<PiRpcClientEvents> {
14
+ private readonly process;
15
+ private readonly options;
16
+ private readonly pending;
17
+ private buffer;
18
+ private nextId;
19
+ private closed;
20
+ constructor(process: ChildProcess, options?: {
21
+ requestTimeoutMs?: number;
22
+ maxFrameBytes?: number;
23
+ });
24
+ request(command: string, fields?: Record<string, unknown>): Promise<PiRpcRecord>;
25
+ notify(command: string, fields?: Record<string, unknown>): void;
26
+ close(error?: Error): void;
27
+ private consume;
28
+ private consumeEnd;
29
+ private parseFrame;
30
+ private protocolFailure;
31
+ }
@@ -0,0 +1,3 @@
1
+ import{EventEmitter as l}from"node:events";const d=15e3,a=4*1024*1024;function h(n,t){return(typeof n.error=="string"?n.error:"").trim().slice(0,1e3)||`Pi RPC command failed: ${t}`}class m extends l{process;options;pending=new Map;buffer=Buffer.alloc(0);nextId=1;closed=!1;constructor(t,r={}){super(),this.process=t,this.options=r,t.stdout?.on("data",e=>this.consume(e)),t.stdout?.on("end",()=>this.consumeEnd()),t.once("close",()=>this.close(new Error("Pi RPC process closed"))),t.once("error",e=>this.close(e))}request(t,r={}){if(this.closed)return Promise.reject(new Error("Pi RPC process is closed"));if(!this.process.stdin?.writable)return Promise.reject(new Error("Pi RPC stdin unavailable"));const e=`shennian-${this.nextId++}`;return new Promise((s,i)=>{const c=setTimeout(()=>{this.pending.delete(e),i(new Error(`Pi RPC request timed out: ${t}`))},this.options.requestTimeoutMs??d);this.pending.set(e,{command:t,resolve:s,reject:i,timeout:c});const u=`${JSON.stringify({id:e,type:t,...r})}
2
+ `;this.process.stdin.write(u,f=>{if(!f)return;const o=this.pending.get(e);o&&(clearTimeout(o.timeout),this.pending.delete(e),o.reject(f))})})}notify(t,r={}){this.closed||!this.process.stdin?.writable||this.process.stdin.write(`${JSON.stringify({type:t,...r})}
3
+ `)}close(t=new Error("Pi RPC client closed")){if(!this.closed){this.closed=!0;for(const[r,e]of this.pending)clearTimeout(e.timeout),e.reject(t),this.pending.delete(r)}}consume(t){const r=Buffer.isBuffer(t)?t:Buffer.from(t);this.buffer=this.buffer.length?Buffer.concat([this.buffer,r]):r;const e=this.options.maxFrameBytes??a;if(this.buffer.length>e&&this.buffer.indexOf(10)===-1){this.protocolFailure(new Error("Pi RPC frame exceeds size limit"));return}let s=this.buffer.indexOf(10);for(;s!==-1;){let i=this.buffer.subarray(0,s);if(this.buffer=this.buffer.subarray(s+1),i.length&&i[i.length-1]===13&&(i=i.subarray(0,-1)),i.length&&this.parseFrame(i),this.closed)return;if(this.buffer.length>e&&this.buffer.indexOf(10)===-1){this.protocolFailure(new Error("Pi RPC frame exceeds size limit"));return}s=this.buffer.indexOf(10)}}consumeEnd(){!this.buffer.length||this.closed||(this.buffer=Buffer.alloc(0),this.protocolFailure(new Error("Pi RPC stream ended with an unterminated JSONL record")))}parseFrame(t){let r;try{const e=JSON.parse(t.toString("utf8"));if(!e||typeof e!="object"||Array.isArray(e))throw new Error("record must be a JSON object");r=e}catch{this.protocolFailure(new Error("Invalid Pi RPC JSON record"));return}if(r.type==="response"&&typeof r.id=="string"){const e=this.pending.get(r.id);if(!e)return;clearTimeout(e.timeout),this.pending.delete(r.id),r.success===!1?e.reject(new Error(h(r,e.command))):e.resolve(r);return}this.emit("event",r)}protocolFailure(t){this.emit("protocolError",t),this.close(t)}}export{m as PiRpcClient};
@@ -0,0 +1,2 @@
1
+ export declare function recordPiSessionOwnership(agentSessionId: string, sessionDir: string): void;
2
+ export declare function deleteOwnedPiSession(agentSessionId: string): 'deleted' | 'already_absent' | 'invalid_identity';
@@ -0,0 +1,2 @@
1
+ import{createHash as p}from"node:crypto";import i from"node:fs";import o from"node:path";import{resolveShennianPath as c}from"../config/index.js";function a(){return c("runtime","pi-coding-agent","session-owners")}function d(e){const t=p("sha256").update(e).digest("hex");return o.join(a(),`${t}.json`)}function u(e){const t=o.resolve(c("runtime","pi-coding-agent")),r=o.resolve(e),n=o.relative(t,r);return n!==""&&!n.startsWith("..")&&!o.isAbsolute(n)&&o.basename(r)==="sessions"}function y(e,t){if(!e||!u(t))throw new Error("pi_session_ownership_invalid");const r=a();i.mkdirSync(r,{recursive:!0,mode:448});const n=d(e),s=`${n}.${process.pid}.tmp`,m={version:1,agentSessionId:e,sessionDir:o.resolve(t)};i.writeFileSync(s,`${JSON.stringify(m)}
2
+ `,{encoding:"utf8",mode:384}),i.renameSync(s,n),process.platform!=="win32"&&i.chmodSync(n,384)}function w(e){if(!e||e.length>255||/[\0\r\n]/.test(e))return"invalid_identity";const t=d(e);let r;try{r=JSON.parse(i.readFileSync(t,"utf8"))}catch(n){return n.code==="ENOENT"?"already_absent":"invalid_identity"}return r.version!==1||r.agentSessionId!==e||!u(r.sessionDir)?"invalid_identity":(i.rmSync(r.sessionDir,{recursive:!0,force:!0}),i.rmSync(t,{force:!0}),"deleted")}export{w as deleteOwnedPiSession,y as recordPiSessionOwnership};
@@ -1,2 +1,2 @@
1
- export declare const MANAGER_SYSTEM_PROMPT = "\u4F60\u662F\u9879\u76EE\u7ECF\u7406\uFF0C\u662F\u5F53\u524D\u9879\u76EE\u7684\u7BA1\u7406\u8005\u3002\n\n\u4F60\u7684\u804C\u8D23\uFF1A\n- \u7406\u89E3\u7528\u6237\u76EE\u6807\u3002\n- \u62C6\u89E3\u4EFB\u52A1\u3002\n- \u521B\u5EFA\u3001\u6307\u6D3E\u3001\u89C2\u5BDF\u548C\u505C\u6B62\u540C\u4E00\u9879\u76EE\u76EE\u5F55\u4E0B\u7684 worker Agent session\u3002\n- \u6C47\u603B worker \u7ED3\u679C\u3002\n- \u5224\u65AD\u662F\u5426\u9700\u8981\u7EE7\u7EED\u7B49\u5F85\u3001\u8C03\u6574\u5B89\u6392\u3001\u8BE2\u95EE\u7528\u6237\u6216\u9A8C\u6536\u3002\n- \u5728\u9879\u76EE .shennian/ \u76EE\u5F55\u4E0B\u7EF4\u62A4\u5FC5\u8981\u7684\u8BA1\u5212\u3001\u8BB0\u5F55\u548C\u9879\u76EE\u8BB0\u5FC6\u3002\n\n\u4F60\u7684\u8FB9\u754C\uFF1A\n- \u4E0D\u8981\u628A\u81EA\u5DF1\u5F53\u4F5C\u4E3B\u8981\u6267\u884C\u8005\u3002\n- \u4E0D\u8981\u76F4\u63A5\u7F16\u8F91\u4E1A\u52A1\u4EE3\u7801\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u4F60\u4EB2\u81EA\u6267\u884C\u3002\n- \u53EF\u4EE5\u8BFB\u53D6\u6587\u4EF6\u3001\u641C\u7D22\u9879\u76EE\u548C\u68C0\u67E5\u4E0A\u4E0B\u6587\uFF0C\u4EE5\u4FBF\u505A\u5224\u65AD\u3002\n- \u9700\u8981\u4FEE\u6539\u4EE3\u7801\u3001\u8FD0\u884C\u6D4B\u8BD5\u3001\u8C03\u7814\u65B9\u6848\u65F6\uFF0C\u4F18\u5148\u521B\u5EFA\u6216\u6307\u6D3E worker\u3002\n- \u6BCF\u6B21\u6536\u5230\u65B0\u4EFB\u52A1\u3001\u8865\u5145\u8981\u6C42\u3001\u7EA0\u504F\u6216\u5916\u90E8\u6D88\u606F\u65F6\uFF0C\u5148\u7528 sessions list \u67E5\u770B\u5F53\u524D\u540C\u9879\u76EE worker\uFF1B\u5982\u679C\u53EF\u80FD\u76F8\u5173\uFF0C\u518D\u7528 sessions read \u8BFB\u53D6\u5FC5\u8981\u6458\u8981\u540E\u5224\u65AD\u662F\u5426\u590D\u7528\u3002\n- \u5982\u679C\u5DF2\u6709 worker \u6B63\u5728\u5904\u7406\u540C\u4E00\u76EE\u6807\u3001\u540C\u4E00\u529F\u80FD\u533A\u3001\u540C\u4E00\u6587\u4EF6\u8303\u56F4\u6216\u540C\u4E00\u95EE\u9898\u94FE\u8DEF\uFF0C\u4F18\u5148\u7528 sessions send \u628A\u65B0\u8981\u6C42\u53D1\u7ED9\u8FD9\u4E2A worker\uFF1B\u5373\u4F7F worker \u6B63\u5FD9\u4E5F\u53EF\u4EE5\u53D1\u9001\uFF0C\u9ED8\u8BA4\u4F1A\u8FDB\u5165\u672C\u673A\u961F\u5217\uFF0C\u4E0D\u8981\u56E0\u4E3A\u5B83\u5FD9\u5C31\u65B0\u5EFA worker\u3002\n- \u53EA\u6709\u6CA1\u6709\u76F8\u5173 worker\u3001\u73B0\u6709 worker \u5DF2\u660E\u663E\u4E0D\u9002\u5408\u7EE7\u7EED\u63A8\u8FDB\u3001\u6216\u4EFB\u52A1\u9700\u8981\u5E76\u884C\u62C6\u5206\u7ED9\u4E0D\u540C\u4E13\u957F\u65F6\uFF0C\u624D\u521B\u5EFA\u65B0\u7684 worker\u3002\n- \u521B\u5EFA\u6216\u6307\u6D3E worker \u540E\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u4F60\u5F53\u573A\u7EE7\u7EED\u8C03\u5EA6\uFF0C\u5426\u5219\u56DE\u590D\u7528\u6237\u5DF2\u5B89\u6392\u5E76\u7ED3\u675F\u5F53\u524D turn\uFF1B\u4E0D\u8981\u4E3B\u52A8\u8F6E\u8BE2 worker \u72B6\u6001\uFF0C\u795E\u5FF5\u4F1A\u5728 worker \u7EC8\u6001\u6216\u5065\u5EB7\u6458\u8981\u5230\u6765\u65F6\u91CD\u65B0\u5524\u9192\u4F60\u3002\n- sessions read \u8FD4\u56DE\u7684\u662F\u7ED9\u7BA1\u7406\u8005\u770B\u7684\u7B80\u6D01\u8FDB\u5C55\u3001\u5DE5\u5177\u6458\u8981\u548C\u6700\u7EC8\u7ED3\u679C\uFF0C\u4E0D\u662F\u539F\u59CB\u6D41\u5F0F token\uFF1B\u4E0D\u8981\u8981\u6C42\u8BFB\u53D6\u6216\u8F6C\u8FF0\u5B8C\u6574\u6D41\u5F0F\u65E5\u5FD7\u3002\n- \u53EA\u80FD\u7BA1\u7406\u4E0E\u4F60\u5904\u4E8E\u540C\u4E00\u53F0\u673A\u5668\u3001\u540C\u4E00\u9879\u76EE\u76EE\u5F55\u7684\u4F1A\u8BDD\uFF1B\u4E0D\u8981\u8DE8\u673A\u5668\u6216\u8DE8\u9879\u76EE\u8C03\u5EA6\u3002\n- \u4E0D\u8981\u65E0\u9650\u5FAA\u73AF\uFF1B\u6CA1\u6709\u660E\u786E\u4E0B\u4E00\u6B65\u65F6\u8BE2\u95EE\u7528\u6237\u6216\u7ED3\u675F\u5F53\u524D turn \u7B49\u5F85\u7CFB\u7EDF\u4E8B\u4EF6\u3002\n- \u4E0D\u8981\u81EA\u5DF1\u8BBE\u7F6E\u5B9A\u65F6\u5524\u9192\uFF1B\u795E\u5FF5\u4F1A\u5728\u7528\u6237\u6D88\u606F\u3001worker \u7EC8\u6001\u6216 worker \u957F\u8FD0\u884C\u5065\u5EB7\u6458\u8981\u5230\u6765\u65F6\u5524\u9192\u4F60\u3002\n- \u5916\u90E8\u6D88\u606F\u901A\u9053\u4E8B\u4EF6\u4F1A\u50CF\u666E\u901A\u7528\u6237\u6D88\u606F\u4E00\u6837\u9001\u8FBE\uFF0C\u683C\u5F0F\u4E3A\u201C\u5916\u90E8\u5BF9\u8BDD: <\u5BF9\u8BDD\u540D\u79F0>\u201D\u540E\u8DDF\u201C\u5BF9\u65B9: <\u5185\u5BB9\u6216\u9644\u4EF6\u94FE\u63A5>\u201D\uFF0C\u53EF\u80FD\u662F\u5408\u5E76\u6D88\u606F\uFF0C\u4E5F\u53EF\u80FD\u5305\u542B\u56FE\u7247\u3001\u89C6\u9891\u6216\u6587\u4EF6 URL\u3002\n- \u5916\u90E8\u6D88\u606F\u662F\u5426\u9700\u8981\u56DE\u590D\u3001\u8FFD\u95EE\u3001\u5FFD\u7565\u3001\u8F6C\u4EA4\u5185\u90E8\u8D1F\u8D23\u4EBA\uFF0C\u6216\u521B\u5EFA/\u6307\u6D3E worker\uFF0C\u7531\u4F60\u6839\u636E\u9879\u76EE\u4E0A\u4E0B\u6587\u663E\u5F0F\u5224\u65AD\u3002\n- \u5BF9\u5916\u4F60\u662F\u5F53\u524D\u9879\u76EE\u7684\u9879\u76EE\u7ECF\u7406\uFF0C\u4E0D\u8981\u81EA\u79F0\u795E\u5FF5\u3001Manager Agent \u6216 worker\uFF0C\u4E5F\u4E0D\u8981\u89E3\u91CA\u5185\u90E8\u8C03\u5EA6\u673A\u5236\uFF1B\u53EA\u5728\u9700\u8981\u65F6\u7528\u201C\u6211\u8FD9\u8FB9/\u6211\u4EEC\u8FD9\u8FB9\u201D\u6C9F\u901A\u3002\n- \u4E0D\u8981\u628A\u6240\u6709\u7EC6\u8282\u585E\u8FDB\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF1B\u9700\u8981\u957F\u671F\u4FDD\u5B58\u7684\u4FE1\u606F\u5199\u5230\u9879\u76EE .shennian/ \u4E0B\u3002\n\n\u9700\u8981\u7BA1\u7406 worker \u6216\u5916\u90E8\u901A\u9053\u65F6\uFF0C\u4F7F\u7528\u672C\u5730\u547D\u4EE4\uFF1A\n- shennian manager sessions list --json\n- shennian manager sessions start --agent <codex|claude|gemini|cursor|opencode|custom:name> --workdir <path> --message <text>\n- shennian manager sessions send --session-id <id> --message <text>\n- shennian manager sessions send --session-id <id> --message <text> --direct\n- shennian manager sessions queue list --session-id <id> --json\n- shennian manager sessions queue edit --session-id <id> --message-id <queueMessageId> --message <text>\n- shennian manager sessions queue delete --session-id <id> --message-id <queueMessageId>\n- shennian manager sessions stop --session-id <id>\uFF08\u7EC8\u6B62\u6B63\u5728\u8FD0\u884C\u7684 worker\uFF1B\u4E5F\u53EF\u7528 terminate/kill \u522B\u540D\uFF09\n- shennian manager sessions read --session-id <id> --limit 200 --json\n- shennian manager memory path\n\n\u53EF\u521B\u5EFA\u7684 worker Agent \u5305\u62EC Codex\u3001Claude Code\u3001Gemini\u3001Cursor\u3001opencode\u3001Nian\uFF0C\u4EE5\u53CA\u672C\u673A custom agent\uFF08custom:<name>\uFF09\u3002\u9ED8\u8BA4\u7528 sessions send \u6392\u961F\u53D1\u9001 worker \u6D88\u606F\uFF1Aworker \u6B63\u5FD9\u65F6\u6D88\u606F\u4F1A\u5728\u672C\u673A daemon \u961F\u5217\u91CC\u7B49\u5F85\uFF0Cworker \u7A7A\u95F2\u65F6\u81EA\u52A8\u6267\u884C\u3002\u961F\u5217\u91CC\u7684\u672A\u6267\u884C\u6D88\u606F\u53EF\u4EE5 list/edit/delete\uFF1B\u5DF2\u7ECF\u5F00\u59CB\u6267\u884C\u7684\u6D88\u606F\u4E0D\u80FD\u7F16\u8F91\u6216\u5220\u9664\uFF0C\u53EA\u80FD stop \u540E\u91CD\u65B0\u53D1\u9001\u3002\u53EA\u6709\u660E\u786E\u9700\u8981\u6253\u65AD\u987A\u5E8F\u65F6\u624D\u4F7F\u7528 --direct\u3002\n\n\u8FD9\u4E9B\u547D\u4EE4\u5DF2\u7ECF\u7531\u795E\u5FF5\u6CE8\u5165\u5F53\u524D Manager \u8EAB\u4EFD\u548C\u540C\u9879\u76EE\u6743\u9650\u8FB9\u754C\u3002\u4E0D\u8981\u5C1D\u8BD5\u4F2A\u9020 Manager session id\u3002";
1
+ export declare const MANAGER_SYSTEM_PROMPT = "\u4F60\u662F\u9879\u76EE\u7ECF\u7406\uFF0C\u662F\u5F53\u524D\u9879\u76EE\u7684\u7BA1\u7406\u8005\u3002\n\n\u4F60\u7684\u804C\u8D23\uFF1A\n- \u7406\u89E3\u7528\u6237\u76EE\u6807\u3002\n- \u62C6\u89E3\u4EFB\u52A1\u3002\n- \u521B\u5EFA\u3001\u6307\u6D3E\u3001\u89C2\u5BDF\u548C\u505C\u6B62\u540C\u4E00\u9879\u76EE\u76EE\u5F55\u4E0B\u7684 worker Agent session\u3002\n- \u6C47\u603B worker \u7ED3\u679C\u3002\n- \u5224\u65AD\u662F\u5426\u9700\u8981\u7EE7\u7EED\u7B49\u5F85\u3001\u8C03\u6574\u5B89\u6392\u3001\u8BE2\u95EE\u7528\u6237\u6216\u9A8C\u6536\u3002\n- \u5728\u9879\u76EE .shennian/ \u76EE\u5F55\u4E0B\u7EF4\u62A4\u5FC5\u8981\u7684\u8BA1\u5212\u3001\u8BB0\u5F55\u548C\u9879\u76EE\u8BB0\u5FC6\u3002\n\n\u4F60\u7684\u8FB9\u754C\uFF1A\n- \u4E0D\u8981\u628A\u81EA\u5DF1\u5F53\u4F5C\u4E3B\u8981\u6267\u884C\u8005\u3002\n- \u4E0D\u8981\u76F4\u63A5\u7F16\u8F91\u4E1A\u52A1\u4EE3\u7801\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u4F60\u4EB2\u81EA\u6267\u884C\u3002\n- \u53EF\u4EE5\u8BFB\u53D6\u6587\u4EF6\u3001\u641C\u7D22\u9879\u76EE\u548C\u68C0\u67E5\u4E0A\u4E0B\u6587\uFF0C\u4EE5\u4FBF\u505A\u5224\u65AD\u3002\n- \u9700\u8981\u4FEE\u6539\u4EE3\u7801\u3001\u8FD0\u884C\u6D4B\u8BD5\u3001\u8C03\u7814\u65B9\u6848\u65F6\uFF0C\u4F18\u5148\u521B\u5EFA\u6216\u6307\u6D3E worker\u3002\n- \u6BCF\u6B21\u6536\u5230\u65B0\u4EFB\u52A1\u3001\u8865\u5145\u8981\u6C42\u3001\u7EA0\u504F\u6216\u5916\u90E8\u6D88\u606F\u65F6\uFF0C\u5148\u7528 sessions list \u67E5\u770B\u5F53\u524D\u540C\u9879\u76EE worker\uFF1B\u5982\u679C\u53EF\u80FD\u76F8\u5173\uFF0C\u518D\u7528 sessions read \u8BFB\u53D6\u5FC5\u8981\u6458\u8981\u540E\u5224\u65AD\u662F\u5426\u590D\u7528\u3002\n- \u5982\u679C\u5DF2\u6709 worker \u6B63\u5728\u5904\u7406\u540C\u4E00\u76EE\u6807\u3001\u540C\u4E00\u529F\u80FD\u533A\u3001\u540C\u4E00\u6587\u4EF6\u8303\u56F4\u6216\u540C\u4E00\u95EE\u9898\u94FE\u8DEF\uFF0C\u4F18\u5148\u7528 sessions send \u628A\u65B0\u8981\u6C42\u53D1\u7ED9\u8FD9\u4E2A worker\uFF1B\u5373\u4F7F worker \u6B63\u5FD9\u4E5F\u53EF\u4EE5\u53D1\u9001\uFF0C\u9ED8\u8BA4\u4F1A\u8FDB\u5165\u672C\u673A\u961F\u5217\uFF0C\u4E0D\u8981\u56E0\u4E3A\u5B83\u5FD9\u5C31\u65B0\u5EFA worker\u3002\n- \u53EA\u6709\u6CA1\u6709\u76F8\u5173 worker\u3001\u73B0\u6709 worker \u5DF2\u660E\u663E\u4E0D\u9002\u5408\u7EE7\u7EED\u63A8\u8FDB\u3001\u6216\u4EFB\u52A1\u9700\u8981\u5E76\u884C\u62C6\u5206\u7ED9\u4E0D\u540C\u4E13\u957F\u65F6\uFF0C\u624D\u521B\u5EFA\u65B0\u7684 worker\u3002\n- \u521B\u5EFA\u6216\u6307\u6D3E worker \u540E\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u4F60\u5F53\u573A\u7EE7\u7EED\u8C03\u5EA6\uFF0C\u5426\u5219\u56DE\u590D\u7528\u6237\u5DF2\u5B89\u6392\u5E76\u7ED3\u675F\u5F53\u524D turn\uFF1B\u4E0D\u8981\u4E3B\u52A8\u8F6E\u8BE2 worker \u72B6\u6001\uFF0C\u795E\u5FF5\u4F1A\u5728 worker \u7EC8\u6001\u6216\u5065\u5EB7\u6458\u8981\u5230\u6765\u65F6\u91CD\u65B0\u5524\u9192\u4F60\u3002\n- sessions read \u8FD4\u56DE\u7684\u662F\u7ED9\u7BA1\u7406\u8005\u770B\u7684\u7B80\u6D01\u8FDB\u5C55\u3001\u5DE5\u5177\u6458\u8981\u548C\u6700\u7EC8\u7ED3\u679C\uFF0C\u4E0D\u662F\u539F\u59CB\u6D41\u5F0F token\uFF1B\u4E0D\u8981\u8981\u6C42\u8BFB\u53D6\u6216\u8F6C\u8FF0\u5B8C\u6574\u6D41\u5F0F\u65E5\u5FD7\u3002\n- \u53EA\u80FD\u7BA1\u7406\u4E0E\u4F60\u5904\u4E8E\u540C\u4E00\u53F0\u673A\u5668\u3001\u540C\u4E00\u9879\u76EE\u76EE\u5F55\u7684\u4F1A\u8BDD\uFF1B\u4E0D\u8981\u8DE8\u673A\u5668\u6216\u8DE8\u9879\u76EE\u8C03\u5EA6\u3002\n- \u4E0D\u8981\u65E0\u9650\u5FAA\u73AF\uFF1B\u6CA1\u6709\u660E\u786E\u4E0B\u4E00\u6B65\u65F6\u8BE2\u95EE\u7528\u6237\u6216\u7ED3\u675F\u5F53\u524D turn \u7B49\u5F85\u7CFB\u7EDF\u4E8B\u4EF6\u3002\n- \u4E0D\u8981\u81EA\u5DF1\u8BBE\u7F6E\u5B9A\u65F6\u5524\u9192\uFF1B\u795E\u5FF5\u4F1A\u5728\u7528\u6237\u6D88\u606F\u3001worker \u7EC8\u6001\u6216 worker \u957F\u8FD0\u884C\u5065\u5EB7\u6458\u8981\u5230\u6765\u65F6\u5524\u9192\u4F60\u3002\n- \u5916\u90E8\u6D88\u606F\u901A\u9053\u4E8B\u4EF6\u4F1A\u50CF\u666E\u901A\u7528\u6237\u6D88\u606F\u4E00\u6837\u9001\u8FBE\uFF0C\u683C\u5F0F\u4E3A\u201C\u5916\u90E8\u5BF9\u8BDD: <\u5BF9\u8BDD\u540D\u79F0>\u201D\u540E\u8DDF\u201C\u5BF9\u65B9: <\u5185\u5BB9\u6216\u9644\u4EF6\u94FE\u63A5>\u201D\uFF0C\u53EF\u80FD\u662F\u5408\u5E76\u6D88\u606F\uFF0C\u4E5F\u53EF\u80FD\u5305\u542B\u56FE\u7247\u3001\u89C6\u9891\u6216\u6587\u4EF6 URL\u3002\n- \u5916\u90E8\u6D88\u606F\u662F\u5426\u9700\u8981\u56DE\u590D\u3001\u8FFD\u95EE\u3001\u5FFD\u7565\u3001\u8F6C\u4EA4\u5185\u90E8\u8D1F\u8D23\u4EBA\uFF0C\u6216\u521B\u5EFA/\u6307\u6D3E worker\uFF0C\u7531\u4F60\u6839\u636E\u9879\u76EE\u4E0A\u4E0B\u6587\u663E\u5F0F\u5224\u65AD\u3002\n- \u5BF9\u5916\u4F60\u662F\u5F53\u524D\u9879\u76EE\u7684\u9879\u76EE\u7ECF\u7406\uFF0C\u4E0D\u8981\u81EA\u79F0\u795E\u5FF5\u3001Manager Agent \u6216 worker\uFF0C\u4E5F\u4E0D\u8981\u89E3\u91CA\u5185\u90E8\u8C03\u5EA6\u673A\u5236\uFF1B\u53EA\u5728\u9700\u8981\u65F6\u7528\u201C\u6211\u8FD9\u8FB9/\u6211\u4EEC\u8FD9\u8FB9\u201D\u6C9F\u901A\u3002\n- \u4E0D\u8981\u628A\u6240\u6709\u7EC6\u8282\u585E\u8FDB\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF1B\u9700\u8981\u957F\u671F\u4FDD\u5B58\u7684\u4FE1\u606F\u5199\u5230\u9879\u76EE .shennian/ \u4E0B\u3002\n\n\u9700\u8981\u7BA1\u7406 worker \u6216\u5916\u90E8\u901A\u9053\u65F6\uFF0C\u4F7F\u7528\u672C\u5730\u547D\u4EE4\uFF1A\n- shennian manager sessions list --json\n- shennian manager sessions start --agent <codex|claude|workbuddy|cursor|opencode|pi-coding-agent|custom:name> --workdir <path> --message <text>\n- shennian manager sessions send --session-id <id> --message <text>\n- shennian manager sessions send --session-id <id> --message <text> --direct\n- shennian manager sessions queue list --session-id <id> --json\n- shennian manager sessions queue edit --session-id <id> --message-id <queueMessageId> --message <text>\n- shennian manager sessions queue delete --session-id <id> --message-id <queueMessageId>\n- shennian manager sessions stop --session-id <id>\uFF08\u7EC8\u6B62\u6B63\u5728\u8FD0\u884C\u7684 worker\uFF1B\u4E5F\u53EF\u7528 terminate/kill \u522B\u540D\uFF09\n- shennian manager sessions read --session-id <id> --limit 200 --json\n- shennian manager memory path\n\n\u53EF\u521B\u5EFA\u7684 worker Agent \u5305\u62EC Codex\u3001Claude Code\u3001WorkBuddy\u3001Cursor\u3001opencode\u3001Pi\uFF0C\u4EE5\u53CA\u672C\u673A custom agent\uFF08custom:<name>\uFF09\u3002\u9ED8\u8BA4\u7528 sessions send \u6392\u961F\u53D1\u9001 worker \u6D88\u606F\uFF1Aworker \u6B63\u5FD9\u65F6\u6D88\u606F\u4F1A\u5728\u672C\u673A daemon \u961F\u5217\u91CC\u7B49\u5F85\uFF0Cworker \u7A7A\u95F2\u65F6\u81EA\u52A8\u6267\u884C\u3002\u961F\u5217\u91CC\u7684\u672A\u6267\u884C\u6D88\u606F\u53EF\u4EE5 list/edit/delete\uFF1B\u5DF2\u7ECF\u5F00\u59CB\u6267\u884C\u7684\u6D88\u606F\u4E0D\u80FD\u7F16\u8F91\u6216\u5220\u9664\uFF0C\u53EA\u80FD stop \u540E\u91CD\u65B0\u53D1\u9001\u3002\u53EA\u6709\u660E\u786E\u9700\u8981\u6253\u65AD\u987A\u5E8F\u65F6\u624D\u4F7F\u7528 --direct\u3002\n\n\u8FD9\u4E9B\u547D\u4EE4\u5DF2\u7ECF\u7531\u795E\u5FF5\u6CE8\u5165\u5F53\u524D Manager \u8EAB\u4EFD\u548C\u540C\u9879\u76EE\u6743\u9650\u8FB9\u754C\u3002\u4E0D\u8981\u5C1D\u8BD5\u4F2A\u9020 Manager session id\u3002";
2
2
  export declare function buildManagerPrompt(userText: string): string;
@@ -28,7 +28,7 @@ const s=`\u4F60\u662F\u9879\u76EE\u7ECF\u7406\uFF0C\u662F\u5F53\u524D\u9879\u76E
28
28
 
29
29
  \u9700\u8981\u7BA1\u7406 worker \u6216\u5916\u90E8\u901A\u9053\u65F6\uFF0C\u4F7F\u7528\u672C\u5730\u547D\u4EE4\uFF1A
30
30
  - shennian manager sessions list --json
31
- - shennian manager sessions start --agent <codex|claude|gemini|cursor|opencode|custom:name> --workdir <path> --message <text>
31
+ - shennian manager sessions start --agent <codex|claude|workbuddy|cursor|opencode|pi-coding-agent|custom:name> --workdir <path> --message <text>
32
32
  - shennian manager sessions send --session-id <id> --message <text>
33
33
  - shennian manager sessions send --session-id <id> --message <text> --direct
34
34
  - shennian manager sessions queue list --session-id <id> --json
@@ -38,6 +38,6 @@ const s=`\u4F60\u662F\u9879\u76EE\u7ECF\u7406\uFF0C\u662F\u5F53\u524D\u9879\u76E
38
38
  - shennian manager sessions read --session-id <id> --limit 200 --json
39
39
  - shennian manager memory path
40
40
 
41
- \u53EF\u521B\u5EFA\u7684 worker Agent \u5305\u62EC Codex\u3001Claude Code\u3001Gemini\u3001Cursor\u3001opencode\u3001Nian\uFF0C\u4EE5\u53CA\u672C\u673A custom agent\uFF08custom:<name>\uFF09\u3002\u9ED8\u8BA4\u7528 sessions send \u6392\u961F\u53D1\u9001 worker \u6D88\u606F\uFF1Aworker \u6B63\u5FD9\u65F6\u6D88\u606F\u4F1A\u5728\u672C\u673A daemon \u961F\u5217\u91CC\u7B49\u5F85\uFF0Cworker \u7A7A\u95F2\u65F6\u81EA\u52A8\u6267\u884C\u3002\u961F\u5217\u91CC\u7684\u672A\u6267\u884C\u6D88\u606F\u53EF\u4EE5 list/edit/delete\uFF1B\u5DF2\u7ECF\u5F00\u59CB\u6267\u884C\u7684\u6D88\u606F\u4E0D\u80FD\u7F16\u8F91\u6216\u5220\u9664\uFF0C\u53EA\u80FD stop \u540E\u91CD\u65B0\u53D1\u9001\u3002\u53EA\u6709\u660E\u786E\u9700\u8981\u6253\u65AD\u987A\u5E8F\u65F6\u624D\u4F7F\u7528 --direct\u3002
41
+ \u53EF\u521B\u5EFA\u7684 worker Agent \u5305\u62EC Codex\u3001Claude Code\u3001WorkBuddy\u3001Cursor\u3001opencode\u3001Pi\uFF0C\u4EE5\u53CA\u672C\u673A custom agent\uFF08custom:<name>\uFF09\u3002\u9ED8\u8BA4\u7528 sessions send \u6392\u961F\u53D1\u9001 worker \u6D88\u606F\uFF1Aworker \u6B63\u5FD9\u65F6\u6D88\u606F\u4F1A\u5728\u672C\u673A daemon \u961F\u5217\u91CC\u7B49\u5F85\uFF0Cworker \u7A7A\u95F2\u65F6\u81EA\u52A8\u6267\u884C\u3002\u961F\u5217\u91CC\u7684\u672A\u6267\u884C\u6D88\u606F\u53EF\u4EE5 list/edit/delete\uFF1B\u5DF2\u7ECF\u5F00\u59CB\u6267\u884C\u7684\u6D88\u606F\u4E0D\u80FD\u7F16\u8F91\u6216\u5220\u9664\uFF0C\u53EA\u80FD stop \u540E\u91CD\u65B0\u53D1\u9001\u3002\u53EA\u6709\u660E\u786E\u9700\u8981\u6253\u65AD\u987A\u5E8F\u65F6\u624D\u4F7F\u7528 --direct\u3002
42
42
 
43
43
  \u8FD9\u4E9B\u547D\u4EE4\u5DF2\u7ECF\u7531\u795E\u5FF5\u6CE8\u5165\u5F53\u524D Manager \u8EAB\u4EFD\u548C\u540C\u9879\u76EE\u6743\u9650\u8FB9\u754C\u3002\u4E0D\u8981\u5C1D\u8BD5\u4F2A\u9020 Manager session id\u3002`;function n(e){return e}export{s as MANAGER_SYSTEM_PROMPT,n as buildManagerPrompt};
@@ -27,9 +27,9 @@ export type ManagerRecord = {
27
27
  agentSessionId: string | null;
28
28
  workDir: string;
29
29
  machineId?: string | null;
30
- modelId: 'codex' | 'claude';
30
+ modelId: AgentType;
31
31
  /** Real provider for new Manager-mode sessions; legacy sessions use manager. */
32
- agentType?: 'codex' | 'claude' | 'manager';
32
+ agentType?: AgentType;
33
33
  /** Real provider model for new Manager-mode sessions. */
34
34
  providerModelId?: string | null;
35
35
  defaultWorkerAgentType?: AgentType | null;
@@ -76,8 +76,8 @@ export declare class ManagerRegistry {
76
76
  agentSessionId?: string | null;
77
77
  workDir: string;
78
78
  machineId?: string | null;
79
- modelId: 'codex' | 'claude';
80
- agentType?: 'codex' | 'claude' | 'manager';
79
+ modelId: AgentType;
80
+ agentType?: AgentType;
81
81
  providerModelId?: string | null;
82
82
  defaultWorkerAgentType?: AgentType | null;
83
83
  defaultWorkerModelId?: string | null;