shennian 0.3.1 → 0.3.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.
- package/README.md +3 -1
- package/dist/publish-build-manifest.json +273 -343
- package/dist/src/agents/command-spec.js +2 -2
- package/dist/src/agents/detect.js +1 -1
- package/dist/src/agents/model-registry/discovery.js +2 -2
- package/dist/src/agents/model-registry/parsers.d.ts +1 -0
- package/dist/src/agents/model-registry/parsers.js +4 -4
- package/dist/src/agents/native-capabilities.d.ts +10 -0
- package/dist/src/agents/native-capabilities.js +1 -0
- package/dist/src/agents/platform-instructions.js +5 -5
- package/dist/src/agents/workbuddy.d.ts +44 -0
- package/dist/src/agents/workbuddy.js +3 -0
- package/dist/src/commands/daemon.d.ts +1 -0
- package/dist/src/commands/daemon.js +9 -9
- package/dist/src/commands/integration.d.ts +2 -0
- package/dist/src/commands/integration.js +1 -0
- package/dist/src/commands/manager.js +1 -2
- package/dist/src/commands/pair-browser.d.ts +43 -0
- package/dist/src/commands/pair-browser.js +1 -0
- package/dist/src/commands/pair.d.ts +2 -0
- package/dist/src/commands/pair.js +11 -8
- package/dist/src/commands/room.d.ts +13 -0
- package/dist/src/commands/room.js +4 -0
- package/dist/src/commands/upgrade.d.ts +3 -0
- package/dist/src/commands/upgrade.js +1 -1
- package/dist/src/config/index.d.ts +3 -1
- package/dist/src/config/index.js +2 -1
- package/dist/src/daemon-ipc/client.d.ts +8 -0
- package/dist/src/daemon-ipc/client.js +3 -0
- package/dist/src/daemon-ipc/paths.d.ts +7 -0
- package/dist/src/daemon-ipc/paths.js +1 -0
- package/dist/src/daemon-ipc/protocol.d.ts +30 -0
- package/dist/src/daemon-ipc/protocol.js +1 -0
- package/dist/src/daemon-ipc/secret.d.ts +3 -0
- package/dist/src/daemon-ipc/secret.js +3 -0
- package/dist/src/daemon-ipc/server.d.ts +13 -0
- package/dist/src/daemon-ipc/server.js +3 -0
- package/dist/src/index.js +2 -2
- package/dist/src/integrations/claude-room-plugin-lifecycle.d.ts +47 -0
- package/dist/src/integrations/claude-room-plugin-lifecycle.js +1 -0
- package/dist/src/integrations/codex-room-plugin-lifecycle.d.ts +49 -0
- package/dist/src/integrations/codex-room-plugin-lifecycle.js +1 -0
- package/dist/src/integrations/room-plugin-bundles.d.ts +23 -0
- package/dist/src/integrations/room-plugin-bundles.js +1 -0
- package/dist/src/integrations/room-plugin-lifecycle-common.d.ts +17 -0
- package/dist/src/integrations/room-plugin-lifecycle-common.js +1 -0
- package/dist/src/integrations/room-plugin-shared.d.ts +23 -0
- package/dist/src/integrations/room-plugin-shared.js +2 -0
- package/dist/src/integrations/room-session-hook.d.ts +30 -0
- package/dist/src/integrations/room-session-hook.js +2 -0
- package/dist/src/integrations/workbuddy-plugin-bundle.d.ts +15 -0
- package/dist/src/integrations/workbuddy-plugin-bundle.js +1 -0
- package/dist/src/integrations/workbuddy-plugin-lifecycle.d.ts +52 -0
- package/dist/src/integrations/workbuddy-plugin-lifecycle.js +2 -0
- package/dist/src/integrations/workbuddy-session-hook.d.ts +22 -0
- package/dist/src/integrations/workbuddy-session-hook.js +1 -0
- package/dist/src/manager/prompt.d.ts +1 -1
- package/dist/src/manager/prompt.js +1 -1
- package/dist/src/manager/retired-external-channel-compat.d.ts +78 -0
- package/dist/src/manager/retired-external-channel-compat.js +1 -0
- package/dist/src/manager/runtime.d.ts +1 -3
- package/dist/src/manager/runtime.js +7 -7
- package/dist/src/relay/client.d.ts +2 -0
- package/dist/src/relay/client.js +1 -1
- package/dist/src/room/activation-audit.d.ts +15 -0
- package/dist/src/room/activation-audit.js +2 -0
- package/dist/src/room/activation-policy.d.ts +8 -0
- package/dist/src/room/activation-policy.js +1 -0
- package/dist/src/room/activation-service.d.ts +25 -0
- package/dist/src/room/activation-service.js +2 -0
- package/dist/src/room/attachment-cache.d.ts +40 -0
- package/dist/src/room/attachment-cache.js +2 -0
- package/dist/src/room/attachment-upload.d.ts +20 -0
- package/dist/src/room/attachment-upload.js +1 -0
- package/dist/src/room/authorized-action-coordinator.d.ts +40 -0
- package/dist/src/room/authorized-action-coordinator.js +1 -0
- package/dist/src/room/authorized-action-ipc.d.ts +11 -0
- package/dist/src/room/authorized-action-ipc.js +1 -0
- package/dist/src/room/device-authorization-client.d.ts +49 -0
- package/dist/src/room/device-authorization-client.js +1 -0
- package/dist/src/room/host-session-observation-ipc.d.ts +9 -0
- package/dist/src/room/host-session-observation-ipc.js +1 -0
- package/dist/src/room/host-session-observations.d.ts +54 -0
- package/dist/src/room/host-session-observations.js +2 -0
- package/dist/src/room/invite-bootstrap.d.ts +35 -0
- package/dist/src/room/invite-bootstrap.js +1 -0
- package/dist/src/room/invocation-token-ipc.d.ts +9 -0
- package/dist/src/room/invocation-token-ipc.js +1 -0
- package/dist/src/room/invocation-token.d.ts +53 -0
- package/dist/src/room/invocation-token.js +1 -0
- package/dist/src/room/jsonl-mirror.d.ts +73 -0
- package/dist/src/room/jsonl-mirror.js +6 -0
- package/dist/src/room/managed-room-session.d.ts +143 -0
- package/dist/src/room/managed-room-session.js +3 -0
- package/dist/src/room/mirror-sync-service.d.ts +33 -0
- package/dist/src/room/mirror-sync-service.js +1 -0
- package/dist/src/room/operator-ipc.d.ts +11 -0
- package/dist/src/room/operator-ipc.js +1 -0
- package/dist/src/room/pending-authorized-actions.d.ts +69 -0
- package/dist/src/room/pending-authorized-actions.js +3 -0
- package/dist/src/room/room-action-client.d.ts +208 -0
- package/dist/src/room/room-action-client.js +1 -0
- package/dist/src/room/room-action-ipc.d.ts +33 -0
- package/dist/src/room/room-action-ipc.js +1 -0
- package/dist/src/room/room-action-schema.d.ts +3 -0
- package/dist/src/room/room-action-schema.js +1 -0
- package/dist/src/room/room-authorized-action-executor.d.ts +23 -0
- package/dist/src/room/room-authorized-action-executor.js +1 -0
- package/dist/src/room/room-binding-client.d.ts +51 -0
- package/dist/src/room/room-binding-client.js +1 -0
- package/dist/src/room/room-binding-ipc.d.ts +29 -0
- package/dist/src/room/room-binding-ipc.js +1 -0
- package/dist/src/room/session-registry-ipc.d.ts +14 -0
- package/dist/src/room/session-registry-ipc.js +1 -0
- package/dist/src/room/session-registry.d.ts +128 -0
- package/dist/src/room/session-registry.js +2 -0
- package/dist/src/room/tool-schema.d.ts +114 -0
- package/dist/src/room/tool-schema.js +1 -0
- package/dist/src/room/tool-server.d.ts +5 -0
- package/dist/src/room/tool-server.js +3 -0
- package/dist/src/session/handlers/agent-capabilities.d.ts +3 -0
- package/dist/src/session/handlers/agent-capabilities.js +1 -0
- package/dist/src/session/handlers/agent-config.js +1 -1
- package/dist/src/session/handlers/chat.js +2 -2
- package/dist/src/session/handlers/control.js +1 -1
- package/dist/src/session/handlers/fs.d.ts +1 -0
- package/dist/src/session/handlers/fs.js +1 -1
- package/dist/src/session/manager.d.ts +16 -6
- package/dist/src/session/manager.js +1 -1
- package/dist/src/session/types.d.ts +5 -0
- package/dist/src/upgrade/engine.d.ts +14 -1
- package/dist/src/upgrade/engine.js +2 -2
- package/dist/src/upgrade/scheduler.d.ts +45 -0
- package/dist/src/upgrade/scheduler.js +1 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.d.ts +17 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.d.ts.map +1 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.js +2 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.js.map +1 -0
- package/node_modules/@shennian/wire/dist/index.d.ts +2 -1
- package/node_modules/@shennian/wire/dist/index.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/index.js +2 -1
- package/node_modules/@shennian/wire/dist/index.js.map +1 -1
- package/node_modules/@shennian/wire/dist/machine.d.ts +1 -0
- package/node_modules/@shennian/wire/dist/machine.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/room.d.ts +112 -0
- package/node_modules/@shennian/wire/dist/room.d.ts.map +1 -0
- package/node_modules/@shennian/wire/dist/room.js +4 -0
- package/node_modules/@shennian/wire/dist/room.js.map +1 -0
- package/node_modules/@shennian/wire/dist/session.d.ts +2 -2
- package/node_modules/@shennian/wire/dist/session.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/session.js +1 -1
- package/node_modules/@shennian/wire/dist/session.js.map +1 -1
- package/package.json +3 -5
- package/dist/scripts/wechat-rpa-confirmation.mjs +0 -5
- package/dist/src/agents/pi-context.d.ts +0 -42
- package/dist/src/agents/pi-context.js +0 -12
- package/dist/src/agents/pi.d.ts +0 -70
- package/dist/src/agents/pi.js +0 -17
- package/dist/src/channels/base.d.ts +0 -144
- package/dist/src/channels/base.js +0 -1
- package/dist/src/channels/registry.d.ts +0 -8
- package/dist/src/channels/registry.js +0 -1
- package/dist/src/channels/reply-split.d.ts +0 -1
- package/dist/src/channels/reply-split.js +0 -10
- package/dist/src/channels/runtime.d.ts +0 -138
- package/dist/src/channels/runtime.js +0 -5
- package/dist/src/channels/secret-registry.d.ts +0 -35
- package/dist/src/channels/secret-registry.js +0 -1
- package/dist/src/channels/websocket.d.ts +0 -55
- package/dist/src/channels/websocket.js +0 -8
- package/dist/src/channels/wechat-channel/anchor.d.ts +0 -10
- package/dist/src/channels/wechat-channel/anchor.js +0 -1
- package/dist/src/channels/wechat-channel/automation-lane.d.ts +0 -35
- package/dist/src/channels/wechat-channel/automation-lane.js +0 -2
- package/dist/src/channels/wechat-channel/client.d.ts +0 -283
- package/dist/src/channels/wechat-channel/client.js +0 -1
- package/dist/src/channels/wechat-channel/cooldown.d.ts +0 -21
- package/dist/src/channels/wechat-channel/cooldown.js +0 -1
- package/dist/src/channels/wechat-channel/core/fixture-compare.d.ts +0 -52
- package/dist/src/channels/wechat-channel/core/fixture-compare.js +0 -1
- package/dist/src/channels/wechat-channel/core/media-action-plan.d.ts +0 -3
- package/dist/src/channels/wechat-channel/core/media-action-plan.js +0 -1
- package/dist/src/channels/wechat-channel/core/schema.d.ts +0 -67
- package/dist/src/channels/wechat-channel/core/schema.js +0 -1
- package/dist/src/channels/wechat-channel/core/trace-comparator.d.ts +0 -28
- package/dist/src/channels/wechat-channel/core/trace-comparator.js +0 -1
- package/dist/src/channels/wechat-channel/fingerprint.d.ts +0 -31
- package/dist/src/channels/wechat-channel/fingerprint.js +0 -1
- package/dist/src/channels/wechat-channel/helper-assets.d.ts +0 -103
- package/dist/src/channels/wechat-channel/helper-assets.js +0 -1
- package/dist/src/channels/wechat-channel/helper-client.d.ts +0 -87
- package/dist/src/channels/wechat-channel/helper-client.js +0 -3
- package/dist/src/channels/wechat-channel/helper-protocol.d.ts +0 -122
- package/dist/src/channels/wechat-channel/helper-protocol.js +0 -1
- package/dist/src/channels/wechat-channel/human-coordination.d.ts +0 -25
- package/dist/src/channels/wechat-channel/human-coordination.js +0 -1
- package/dist/src/channels/wechat-channel/index.d.ts +0 -21
- package/dist/src/channels/wechat-channel/index.js +0 -1
- package/dist/src/channels/wechat-channel/ledger.d.ts +0 -48
- package/dist/src/channels/wechat-channel/ledger.js +0 -2
- package/dist/src/channels/wechat-channel/media-cache-resolver.d.ts +0 -42
- package/dist/src/channels/wechat-channel/media-cache-resolver.js +0 -1
- package/dist/src/channels/wechat-channel/media-resolver.d.ts +0 -186
- package/dist/src/channels/wechat-channel/media-resolver.js +0 -1
- package/dist/src/channels/wechat-channel/message-key.d.ts +0 -19
- package/dist/src/channels/wechat-channel/message-key.js +0 -1
- package/dist/src/channels/wechat-channel/observer.d.ts +0 -171
- package/dist/src/channels/wechat-channel/observer.js +0 -7
- package/dist/src/channels/wechat-channel/outbound-ledger.d.ts +0 -96
- package/dist/src/channels/wechat-channel/outbound-ledger.js +0 -2
- package/dist/src/channels/wechat-channel/outbound-sender.d.ts +0 -74
- package/dist/src/channels/wechat-channel/outbound-sender.js +0 -1
- package/dist/src/channels/wechat-channel/pacing.d.ts +0 -3
- package/dist/src/channels/wechat-channel/pacing.js +0 -1
- package/dist/src/channels/wechat-channel/preflight.d.ts +0 -46
- package/dist/src/channels/wechat-channel/preflight.js +0 -1
- package/dist/src/channels/wechat-channel/runner.d.ts +0 -43
- package/dist/src/channels/wechat-channel/runner.js +0 -1
- package/dist/src/channels/wechat-channel/runtime.d.ts +0 -50
- package/dist/src/channels/wechat-channel/runtime.js +0 -1
- package/dist/src/channels/wechat-channel/scheduler.d.ts +0 -74
- package/dist/src/channels/wechat-channel/scheduler.js +0 -1
- package/dist/src/channels/wechat-channel/vector-store.d.ts +0 -44
- package/dist/src/channels/wechat-channel/vector-store.js +0 -1
- package/dist/src/channels/wechat-rpa/macos-flow.d.ts +0 -55
- package/dist/src/channels/wechat-rpa/macos-flow.js +0 -1
- package/dist/src/channels/wechat-rpa/macos.d.ts +0 -11
- package/dist/src/channels/wechat-rpa/macos.js +0 -21
- package/dist/src/channels/wechat-rpa/normalizer.d.ts +0 -49
- package/dist/src/channels/wechat-rpa/normalizer.js +0 -7
- package/dist/src/channels/wechat-rpa/product-channel.d.ts +0 -76
- package/dist/src/channels/wechat-rpa/product-channel.js +0 -16
- package/dist/src/channels/wechat-rpa-session-sync.d.ts +0 -26
- package/dist/src/channels/wechat-rpa-session-sync.js +0 -1
- package/dist/src/channels/wechat-rpa.d.ts +0 -104
- package/dist/src/channels/wechat-rpa.js +0 -6
- package/dist/src/channels/wecom.d.ts +0 -51
- package/dist/src/channels/wecom.js +0 -4
- package/dist/src/commands/external-attachments.d.ts +0 -9
- package/dist/src/commands/external-attachments.js +0 -1
- package/dist/src/commands/external.d.ts +0 -2
- package/dist/src/commands/external.js +0 -1
- package/dist/src/commands/helper-runtime-official-download.d.ts +0 -80
- package/dist/src/commands/helper-runtime-official-download.js +0 -1
- package/dist/src/commands/runtime.d.ts +0 -120
- package/dist/src/commands/runtime.js +0 -1
- package/dist/src/commands/wechat/command.d.ts +0 -3
- package/dist/src/commands/wechat/command.js +0 -1
- package/dist/src/commands/wechat/direct.d.ts +0 -14
- package/dist/src/commands/wechat/direct.js +0 -2
- package/dist/src/commands/wechat/doctor.d.ts +0 -2
- package/dist/src/commands/wechat/doctor.js +0 -1
- package/dist/src/commands/wechat/ipc.d.ts +0 -9
- package/dist/src/commands/wechat/ipc.js +0 -1
- package/dist/src/commands/wechat/operations.d.ts +0 -3
- package/dist/src/commands/wechat/operations.js +0 -4
- package/dist/src/commands/wechat/output.d.ts +0 -7
- package/dist/src/commands/wechat/output.js +0 -4
- package/dist/src/commands/wechat/types.d.ts +0 -142
- package/dist/src/commands/wechat/types.js +0 -1
- package/dist/src/commands/wechat/utils.d.ts +0 -16
- package/dist/src/commands/wechat/utils.js +0 -1
- package/dist/src/commands/wechat.d.ts +0 -6
- package/dist/src/commands/wechat.js +0 -1
- package/dist/src/devtools/wechat-channel-action-smoke.d.ts +0 -105
- package/dist/src/devtools/wechat-channel-action-smoke.js +0 -10
- package/dist/src/devtools/wechat-channel-download-report.d.ts +0 -111
- package/dist/src/devtools/wechat-channel-download-report.js +0 -2
- package/dist/src/devtools/wechat-channel-markdown-report.d.ts +0 -6
- package/dist/src/devtools/wechat-channel-markdown-report.js +0 -5
- package/dist/src/devtools/wechat-channel-product-steps.d.ts +0 -9
- package/dist/src/devtools/wechat-channel-product-steps.js +0 -40
- package/dist/src/session/handlers/skills.d.ts +0 -7
- package/dist/src/session/handlers/skills.js +0 -1
- package/dist/src/session/handlers/wechat-helper-runtime.d.ts +0 -33
- package/dist/src/session/handlers/wechat-helper-runtime.js +0 -1
- package/dist/src/skills/registry.d.ts +0 -16
- package/dist/src/skills/registry.js +0 -15
- package/dist/src/skills/setup.d.ts +0 -11
- package/dist/src/skills/setup.js +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{spawn as
|
|
2
|
-
${
|
|
1
|
+
import{spawn as k,spawnSync as g}from"node:child_process";import y from"node:fs";import M from"node:os";import s from"node:path";const E={claude:[{command:"claude",args:[],display:"claude"}],codex:[{command:"codex",args:[],display:"codex"}],workbuddy:[{command:"codebuddy",args:[],display:"WorkBuddy"}],gemini:[{command:"gemini",args:[],display:"gemini"}],cursor:[{command:"agent",args:[],display:"agent"},{command:"cursor",args:["agent"],display:"cursor agent"}],openclaw:[],opencode:[{command:"opencode",args:[],display:"opencode"}],pi:[{command:"shennian",args:[],display:"shennian"}],manager:[{command:"shennian",args:["manager"],display:"shennian manager"}]},p=new Map,m=new Map,f=new Map,u=new Map;function J(){p.clear(),m.clear(),f.clear(),u.clear()}function d(){return process.platform}function F(n){return n.split(/\r?\n/).map(e=>e.trim()).filter(Boolean)}function b(n){if(s.basename(n)!==n)return[n];const e=M.homedir();if(d()==="win32"){const o=s.win32,r=s.extname(n)?[n]:[n,`${n}.cmd`,`${n}.exe`,`${n}.bat`],a=process.env.APPDATA||o.join(e,"AppData","Roaming"),l=process.env.LOCALAPPDATA||o.join(e,"AppData","Local"),v=[o.join(e,".shennian","node"),o.join("C:\\","nvm4w","nodejs"),o.join(l,"npm-global"),o.join(a,"npm"),o.join(l,"pnpm"),o.join(e,"scoop","shims"),o.join("C:\\","Program Files","nodejs")].flatMap(h=>r.map(w=>o.join(h,w)));if(n==="codebuddy"){const h=[o.join(l,"Programs","WorkBuddy"),o.join(l,"WorkBuddy"),o.join("C:\\","Program Files","WorkBuddy")];for(const w of h)for(const T of["codebuddy.exe","codebuddy.cmd","codebuddy"])v.push(o.join(w,"resources","app.asar.unpacked","cli","bin",T))}return v}const i=[s.join(e,".npm-global","bin"),s.join(e,".local","bin"),s.join(e,".bun","bin"),"/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"].map(o=>s.join(o,n));return n==="claude"&&d()==="darwin"&&i.push(...R(e)),n==="codebuddy"&&d()==="darwin"&&i.push("/Applications/WorkBuddy.app/Contents/Resources/app.asar.unpacked/cli/bin/codebuddy",s.join(e,"Applications","WorkBuddy.app","Contents","Resources","app.asar.unpacked","cli","bin","codebuddy")),i}function R(n){const e=[s.join(n,"Library","Application Support","Claude","claude-code")],t=[];for(const i of e){let o;try{o=y.readdirSync(i,{withFileTypes:!0}).filter(r=>r.isDirectory()).map(r=>r.name).sort((r,a)=>a.localeCompare(r,void 0,{numeric:!0}))}catch{continue}for(const r of o)t.push(s.join(i,r,"claude.app","Contents","MacOS","claude"))}return t}function j(n,e){const t=n?.split(s.delimiter).filter(Boolean)??[];if(d()==="win32"){if(e&&s.basename(e)!==e){const i=s.win32.dirname(e);t.includes(i)||t.unshift(i)}for(const i of b("shennian")){const o=s.win32.dirname(i);t.includes(o)||t.push(o)}return t.join(s.delimiter)}if(e&&s.basename(e)!==e){const i=s.dirname(e);t.includes(i)||t.unshift(i)}for(const i of b("shennian")){const o=s.dirname(i);t.includes(o)||t.push(o)}return t.join(s.delimiter)}function c(n){if(f.has(n))return f.get(n)??[];const e=d()==="win32",i=g(e?"where":"which",[n],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3e3,windowsHide:!0,env:{...process.env,PATH:e?process.env.PATH:j(process.env.PATH,n)}}),r=[...i.status===0?F(i.stdout??""):[]];for(const a of b(n))y.existsSync(a)&&!r.includes(a)&&r.push(a);return f.set(n,r),r}function P(){return process.env.ComSpec||"cmd.exe"}function A(n){const e=s.extname(n).toLowerCase();return e===".exe"||e===".com"}function C(n){const e=s.extname(n).toLowerCase();return e===".cmd"||e===".bat"}function W(n){const e=s.extname(n).toLowerCase();return e===".js"||e===".mjs"||e===".cjs"}function $(){return c("node.exe")[0]??c("node")[0]??"node"}function S(n){return`"${n.replace(/"/g,'""')}"`}function x(n){return`'${n.replace(/'/g,"'\\''")}'`}function N(n){if(!n)return;const e=n.replace(/\//g,"\\"),t=e.match(/^([A-Za-z]):\\(.*)$/);if(t){const[,i,o]=t,r=o.replace(/\\/g,"/");return`/mnt/${i.toLowerCase()}/${r}`}if(e.startsWith("\\\\wsl$\\"))return`/${e.replace(/^\\\\wsl\$\\[^\\]+\\?/,"").replace(/\\/g,"/")}`;if(n.startsWith("/"))return n}function B(n){const e=n.trim();if(!e)throw new Error("Command string is empty");if(/[\\/]/.test(e)||/^[A-Za-z]:/.test(e))return C(e)?{kind:"cmd-shim",path:e}:{kind:"direct",path:e};const i=c(e),o=i.find(A);if(o)return{kind:"direct",path:o};const r=i.find(C);return r?{kind:"cmd-shim",path:r}:{kind:"direct",path:e}}function L(n){if(u.has(n))return u.get(n)??!1;const e=c("wsl.exe")[0]??c("wsl")[0];if(!e)return u.set(n,!1),!1;const i=g(e,["-e","sh","-lc",`command -v ${x(n)} >/dev/null 2>&1`],{stdio:"ignore",timeout:5e3,windowsHide:!0}).status===0;return u.set(n,i),i}function K(n){if(p.has(n))return p.get(n)??!1;const e=c(n).length>0||d()==="win32"&&L(n);return p.set(n,e),e}function z(n){const e=c(n.command),t=e.find(A);if(t)return{...n,kind:"native",path:t};const i=e.find(C);if(i)return{...n,kind:"cmd-shim",path:i};if(L(n.command)){const o=c("wsl.exe")[0]??c("wsl")[0];if(o)return{...n,kind:"wsl-bridge",path:o}}return null}function Q(n){if(m.has(n))return m.get(n)??null;const e=E[n].map(t=>{if(d()==="win32")return z(t);const i=c(t.command)[0];return i?{...t,kind:"native",path:i}:null}).find(Boolean)??null;return m.set(n,e),e}function H(n,e,t){if(n.kind==="native")return d()==="win32"&&W(n.path)?{command:$(),args:[n.path,...n.args,...e],cwd:t}:{command:n.path,args:[...n.args,...e],cwd:t};if(n.kind==="cmd-shim"){const r=[n.path,...n.args,...e].map(S).join(" ");return{command:P(),args:["/d","/s","/c",`"${r}"`],cwd:t}}const i=t?N(t):void 0;if(t&&!i)throw new Error(`Cannot map Windows path to WSL workDir: ${t}`);const o=[i?`cd ${x(i)}`:"",`exec ${[n.command,...n.args,...e].map(x).join(" ")}`].filter(Boolean).join(" && ");return{command:n.path,args:["-e","sh","-lc",o],cwd:void 0}}function V(n,e,t={}){const i=H(n,e,t.cwd);return k(i.command,i.args,{...t,cwd:i.cwd,windowsHide:t.windowsHide??!0,...d()==="win32"&&n.kind==="cmd-shim"?{windowsVerbatimArguments:!0}:{}})}function X(n,e,t={}){return V(n,e,t)}function O(n,e,t={}){const i=H(n,e,t.cwd);return g(i.command,i.args,{...t,cwd:i.cwd,windowsHide:t.windowsHide??!0,...d()==="win32"&&n.kind==="cmd-shim"?{windowsVerbatimArguments:!0}:{}})}function D(n){const e=[];let t="",i=!1,o=!1;for(const r of n){if(r==="'"&&!o){i=!i;continue}if(r==='"'&&!i){o=!o;continue}if(r===" "&&!i&&!o){t&&(e.push(t),t="");continue}t+=r}return t&&e.push(t),e}function q(n,e,t){const i=D(n),o=i[0];if(!o)throw new Error("Command string is empty");const r=i.slice(1);if(d()!=="win32")return{command:o,args:[...r,...e],cwd:t};const a=B(o);return a.kind==="cmd-shim"?{command:P(),args:["/d","/s","/c",`"${[a.path,...r,...e].map(S).join(" ")}"`],cwd:t}:W(a.path)?{command:$(),args:[a.path,...r,...e],cwd:t}:{command:a.path,args:[...r,...e],cwd:t}}function Y(n,e,t={}){const i=q(n,e,t.cwd),o=D(n),r=d()==="win32"&&o[0]?B(o[0]):null;return k(i.command,i.args,{...t,cwd:i.cwd,windowsHide:t.windowsHide??!0,env:{...t.env,PATH:j(t.env?.PATH??process.env.PATH,o[0])},...d()==="win32"&&r?.kind==="cmd-shim"?{windowsVerbatimArguments:!0}:{}})}function nn(n,e="--version"){const t=O(n,[e],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:5e3});return t.status!==0?void 0:`${t.stdout??""}
|
|
2
|
+
${t.stderr??""}`.trim().match(/\d+\.\d+[\w.-]*/)?.[0]}export{q as buildCommandStringLaunchSpec,H as buildLaunchSpec,K as commandExists,nn as getCommandVersion,d as getProcessPlatform,D as parseCommandString,J as resetCommandSpecCache,Q as resolveBuiltinCommand,X as spawnAgentCommand,Y as spawnCommandString,V as spawnResolvedCommand,O as spawnResolvedCommandSync,N as windowsPathToWsl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AVAILABLE_BUILTIN_AGENT_TYPES as s}from"@shennian/wire";import{loadConfig as
|
|
1
|
+
import{AVAILABLE_BUILTIN_AGENT_TYPES as s}from"@shennian/wire";import{loadConfig as r}from"../config/index.js";import{getCommandVersion as d,resolveBuiltinCommand as a}from"./command-spec.js";const i=s.filter(e=>e!=="pi"&&e!=="manager");function c(e){const t=e.models?.length?e.models:e.model?[e.model]:[],n=e.defaultModel??e.model;return t.map(o=>({id:o,name:o,isDefault:o===n}))}function g(){const e=[{type:"manager",command:"shennian",args:["manager"],version:void 0,models:[{id:"codex",name:"Codex",provider:"shennian",isDefault:!0},{id:"claude",name:"Claude Code",provider:"shennian"}]}];for(const n of i){const o=a(n);if(!o)continue;const m=d(o);e.push({type:n,command:o.command,args:o.args,version:m})}const t=r();for(const[n,o]of Object.entries(t.customAgents??{}))e.push({type:`custom:${n}`,command:o.command,args:[],version:o.caps.version,models:c(o.caps)});return e}export{g as detectAgents};
|
|
@@ -1,2 +1,2 @@
|
|
|
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
|
|
2
|
-
`,p=>{p&&(clearTimeout(u),r.delete(o),s(p))})}):Promise.reject(new Error("codex app-server stdin unavailable"))}async function
|
|
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,6 +1,7 @@
|
|
|
1
1
|
import type { ModelInfo } from '@shennian/wire';
|
|
2
2
|
export declare function stripAnsi(text: string): string;
|
|
3
3
|
export declare function fallbackCodexModels(): ModelInfo[];
|
|
4
|
+
export declare function fallbackWorkBuddyModels(): ModelInfo[];
|
|
4
5
|
export declare function parseCursorModels(raw: string): ModelInfo[];
|
|
5
6
|
export declare function parseOpenClawModels(raw: string): ModelInfo[];
|
|
6
7
|
export declare function parseOpenCodeModels(raw: string): ModelInfo[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function m(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 h(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:h(n)).join("-")}function
|
|
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()||
|
|
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
|
|
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
|
|
1
|
+
function m(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 h(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:h(n)).join("-")}function A(e){switch(e){case"low":return"Low";case"medium":return"Medium";case"high":return"High";case"xhigh":return"Extra High";default:return h(e)}}const D=[{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 x(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(x),...D.map(i=>x(i))]);return t?o.map(i=>({...i,isDefault:i.id===t})):o}function H(){return D.map((e,n)=>({...x(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:A(e)})),defaultReasoningEffort:"medium"}]}function k(e){return e.split("-").map(n=>/^\d/.test(n)?n:h(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=m(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 j(e){const n=m(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 B(e){const n=m(e).replace(/\s+/g," "),t=[[/\d+\.Default\(recommended\).*?(?:Sonnet|currently\s*Sonnet)\s*([\d.]+)/i,"default","Default (recommended)"],[/\d+\.Sonnet.*?Sonnet\s*([\d.]+)/i,"sonnet","Sonnet"],[/\d+\.Opus.*?Opus\s*([\d.]+)/i,"opus","Opus"],[/\d+\.Haiku.*?Haiku\s*([\d.]+)/i,"haiku","Haiku"]],o=[];for(const[a,u,c]of t){const l=n.match(a);l&&o.push(g({id:u,name:c,description:`v${l[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]??"",C=s&&s[1]?.toLowerCase()===u&&s[2]===l;i.push(g({id:c,name:`${h(u)} ${l}`,provider:"anthropic",isDefault:!!C}))}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"},G=[{id:"max",name:"Max"}],N=[{id:"low",name:"Low"},{id:"medium",name:"Medium"},{id:"high",name:"High"},{id:"xhigh",name:"Extra High"},{id:"max",name:"Max"}];function g(e){return{...e,supportedReasoningEfforts:N,defaultReasoningEffort:"medium"}}function E(e,n){return e[n]?.trim()||null}function M(e,n){const t=E(n,"ANTHROPIC_BASE_URL")?.toLowerCase()??"";return t.includes("deepseek.com")||e.toLowerCase().startsWith("deepseek-")?"deepseek":t?"custom":"anthropic"}function S(e){const n=new Set;for(const o of Object.values(L)){const i=E(e,o);i&&n.add(i)}const t=Array.from(n).map((o,i)=>{const s=M(o,e),r={id:o,name:o,provider:s,isDefault:i===0};return s==="deepseek"?{...r,supportedReasoningEfforts:G,defaultReasoningEffort:E(e,"CLAUDE_CODE_EFFORT_LEVEL")??"max"}:g(r)});return d(t)}function V(e=process.env){return S(e)}function P(e,n=process.env){return e.map(t=>{if(!["default","sonnet","opus","haiku"].includes(t.id))return t;const o=t.id,i=E(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:M(i,n)}})}function z(e){const n=m(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(g({id:i,name:y[i],description:$(s),provider:"anthropic",isDefault:i==="default"}))}return d(o)}function q(e=process.env){const n=S(e);return n.length>0?n:P([{id:"default",name:"Default (recommended)",provider:"anthropic",isDefault:!0},{id:"sonnet",name:"Sonnet",provider:"anthropic"},{id:"opus",name:"Opus",provider:"anthropic"},{id:"haiku",name:"Haiku",provider:"anthropic"}],e).map(g)}function K(e){const n=m(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,C=Array.isArray(r.supportedReasoningEfforts)?r.supportedReasoningEfforts.map(f=>{if(typeof f!="object"||f===null)return null;const p=f,v=typeof p.reasoningEffort=="string"?p.reasoningEffort:typeof p.id=="string"?p.id:"";return v?{id:v,name:A(v),description:typeof p.description=="string"?p.description:void 0}:null}).filter(f=>f!=null):void 0,O=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:C,defaultReasoningEffort:l,additionalSpeedTiers:O})}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=m(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{P as applyClaudeModelEnvOverrides,V as discoverClaudeAliasModelsFromEnv,q as fallbackClaudeAliasModels,H as fallbackCodexModels,X as fallbackGeminiModels,F as fallbackWorkBuddyModels,M as inferClaudeOverrideProvider,z as parseClaudeBinaryModels,B as parseClaudeModels,W as parseCodexAppServerModels,K as parseCodexModels,I as parseCursorModels,J as parseGeminiModels,U as parseOpenClawModels,j as parseOpenCodeModels,E as readEnvValue,m as stripAnsi};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentCapabilityProvider, AgentNativeCapability } from '@shennian/wire';
|
|
2
|
+
type DiscoveryOptions = {
|
|
3
|
+
agentType: string;
|
|
4
|
+
workDir: string;
|
|
5
|
+
homeDir?: string;
|
|
6
|
+
platform?: NodeJS.Platform;
|
|
7
|
+
};
|
|
8
|
+
export declare function isNativeCapabilityProvider(value: string): value is AgentCapabilityProvider;
|
|
9
|
+
export declare function listAgentNativeCapabilities(options: DiscoveryOptions): AgentNativeCapability[];
|
|
10
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import v from"node:crypto";import{execFileSync as g}from"node:child_process";import u from"node:fs";import x from"node:os";import c from"node:path";const S=new Set(["codex","claude","workbuddy"]);function P(t){return S.has(t)}function L(t){if(!P(t.agentType))return[];const i=c.resolve(t.homeDir??x.homedir()),e=c.resolve(t.workDir||i),r=[];if(t.agentType==="codex"){for(const o of y(e))l(r,c.join(o,".agents","skills"),{provider:"codex",source:"project",priority:0,invocationPrefix:"$",maxDepth:2});l(r,c.join(i,".agents","skills"),{provider:"codex",source:"personal",priority:1,invocationPrefix:"$",maxDepth:2}),l(r,c.join(i,".codex","skills"),{provider:"codex",source:"personal",priority:1,invocationPrefix:"$",maxDepth:3,systemSegment:".system"}),l(r,"/etc/codex/skills",{provider:"codex",source:"system",priority:3,invocationPrefix:"$",maxDepth:2}),t.homeDir||$(r)}else{const o=t.agentType==="claude"?".claude":".codebuddy";for(const s of y(e))l(r,c.join(s,o,"skills"),{provider:t.agentType,source:"project",priority:0,invocationPrefix:"/",maxDepth:3});l(r,c.join(i,o,"skills"),{provider:t.agentType,source:"personal",priority:1,invocationPrefix:"/",maxDepth:3}),D(r,{provider:t.agentType,homeDir:i,configFolder:o})}const n=new Map;for(const o of r){const s=n.get(o.invocation);(!s||o.priority<s.priority)&&n.set(o.invocation,o)}return[...n.values()].sort((o,s)=>o.name.localeCompare(s.name)||o.invocation.localeCompare(s.invocation)).map(({priority:o,...s})=>s)}function $(t){try{const i=g("codex",["plugin","list","--json"],{encoding:"utf8",timeout:5e3,maxBuffer:4194304,stdio:["ignore","pipe","ignore"]}),e=JSON.parse(i);for(const r of e.installed??[]){const n=typeof r.name=="string"?r.name.trim():"",o=typeof r.source?.path=="string"?r.source.path:"";!n||!/^[a-zA-Z0-9._-]+$/.test(n)||!o||r.installed!==!0||r.enabled!==!0||l(t,c.resolve(o),{provider:"codex",source:"plugin",priority:2,invocationPrefix:"$",pluginName:n,maxDepth:4})}}catch{}}function y(t){const i=[];let e=t;for(let r=0;r<64;r+=1){i.push(e);const n=c.dirname(e);if(n===e)break;e=n}return i}function l(t,i,e){N(i)&&k(i,e.maxDepth,r=>{const n=b(r);if(!n)return;const o=c.relative(i,r).split(c.sep),s=e.systemSegment&&o.includes(e.systemSegment)?"system":e.source,a=e.pluginName?`${e.invocationPrefix}${e.pluginName}:${n.name}`:`${e.invocationPrefix}${n.name}`;t.push({id:j(e.provider,a,r),name:n.name,description:n.description,kind:e.pluginName?"plugin_skill":"skill",source:s,invocation:a,priority:e.priority})})}function D(t,i){const e=c.join(i.homeDir,i.configFolder,"plugins"),r=c.join(e,"installed_plugins.json");if(_(r))try{const n=JSON.parse(u.readFileSync(r,"utf8"));for(const[o,s]of Object.entries(n.plugins??{})){const a=o.split("@")[0]?.trim();if(!a||!/^[a-zA-Z0-9._-]+$/.test(a))continue;const p=Array.isArray(s)?s:[s];for(const d of p){const f=d&&typeof d=="object"&&"installPath"in d?String(d.installPath??""):"";if(!f)continue;const m=c.resolve(f);w(m,e)&&l(t,m,{provider:i.provider,source:"plugin",priority:2,invocationPrefix:"/",pluginName:a,maxDepth:4})}}}catch{}}function k(t,i,e){const r=[{directory:t,depth:0}];let n=0;for(;r.length>0&&n<2e3;){const o=r.shift();let s;try{s=u.readdirSync(o.directory,{withFileTypes:!0})}catch{continue}for(const a of s){if(n+=1,n>=2e3)break;const p=c.join(o.directory,a.name);a.isFile()&&!a.isSymbolicLink()&&a.name==="SKILL.md"&&e(p),a.isDirectory()&&!a.isSymbolicLink()&&o.depth<i&&r.push({directory:p,depth:o.depth+1})}}}function b(t){try{const e=u.readFileSync(t,"utf8").slice(0,65536).match(/^---\s*\r?\n([\s\S]*?)\r?\n---(?:\s*\r?\n|$)/)?.[1]??"",r=h(e,"name")||c.basename(c.dirname(t));if(!/^[a-zA-Z0-9._-]+$/.test(r))return null;const n=h(e,"description");return{name:r,...n?{description:n}:{}}}catch{return null}}function h(t,i){const e=t.split(/\r?\n/).find(n=>n.startsWith(`${i}:`));return e?e.slice(i.length+1).trim().replace(/^(?:"([\s\S]*)"|'([\s\S]*)')$/,"$1$2").trim():""}function j(t,i,e){return v.createHash("sha256").update(`${t}\0${i}\0${e}`).digest("hex").slice(0,20)}function w(t,i){const e=c.relative(c.resolve(i),t);return e===""||!e.startsWith(`..${c.sep}`)&&e!==".."&&!c.isAbsolute(e)}function N(t){try{const i=u.lstatSync(t);return i.isDirectory()&&!i.isSymbolicLink()}catch{return!1}}function _(t){try{const i=u.lstatSync(t);return i.isFile()&&!i.isSymbolicLink()}catch{return!1}}export{P as isNativeCapabilityProvider,L as listAgentNativeCapabilities};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import s from"node:fs";import i from"node:path";import{createHash as l}from"node:crypto";import{resolveShennianPath as u}from"../config/index.js";import{buildExternalChannelInstructions as c}from"./external-channel-instructions.js";const f=`## Shennian Output Instructions
|
|
2
2
|
|
|
3
3
|
When you mention a local file that the user may want to open in Shennian, format it as a Markdown link using the exact local path:
|
|
4
4
|
|
|
@@ -6,17 +6,17 @@ When you mention a local file that the user may want to open in Shennian, format
|
|
|
6
6
|
- Use [filename.ext](<relative/path/to/filename.ext>) for paths relative to the current working directory.
|
|
7
7
|
- Do not use file:// URLs for local files.
|
|
8
8
|
- Do not put user-openable file paths only inside code blocks.
|
|
9
|
-
- Keep normal http:// and https:// links unchanged.`;function
|
|
9
|
+
- Keep normal http:// and https:// links unchanged.`;function h(n){const t=i.join(n,"AGENTS.md");try{return s.readFileSync(t,"utf8").trim()}catch{return""}}function m(n,t,r){const o=h(n),e=c(t,i.resolve(n),r);return`${["# Shennian Agent Instructions",o?`## Project Instructions
|
|
10
10
|
|
|
11
|
-
${o}`:"",
|
|
11
|
+
${o}`:"",f,e?`## External Message Channel Instructions
|
|
12
12
|
|
|
13
13
|
${e}`:""].filter(Boolean).join(`
|
|
14
14
|
|
|
15
15
|
`)}
|
|
16
|
-
`}function
|
|
16
|
+
`}function I(n,t,r){const o=c(t,i.resolve(n),r);return o?`# \u795E\u5FF5\u5916\u90E8\u6D88\u606F\u901A\u9053\u8BF4\u660E\uFF08\u7CFB\u7EDF\u6307\u4EE4\uFF0C\u975E\u7528\u6237\u8F93\u5165\uFF0C\u8BF7\u9075\u5FAA\u540E\u518D\u56DE\u5E94\u4E0B\u65B9\u7528\u6237\u6D88\u606F\uFF09
|
|
17
17
|
|
|
18
18
|
${o}
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
`:""}function
|
|
22
|
+
`:""}function g(n,t,r){const o=l("sha256").update(`${i.resolve(n)}:${r??""}:${JSON.stringify(t??null)}`).digest("hex").slice(0,16),e=u("runtime","agent-instructions",`${o}.md`),a=m(n,t,r);s.mkdirSync(i.dirname(e),{recursive:!0});try{if(s.readFileSync(e,"utf8")===a)return e}catch{}return s.writeFileSync(e,a),e}export{f as PLATFORM_OUTPUT_INSTRUCTIONS,I as buildInlineChannelPreamble,m as buildPlatformInstructions,g as ensurePlatformInstructionsFile};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ChatAttachmentMeta, ExternalChannelSessionStatus, SessionRunPhase } from '@shennian/wire';
|
|
2
|
+
import { AgentAdapter } from './adapter.js';
|
|
3
|
+
export declare function normalizeWorkBuddyModelId(modelId?: string | null): string;
|
|
4
|
+
export declare function normalizeWorkBuddyReasoningEffort(value?: string | null): string | undefined;
|
|
5
|
+
export declare class WorkBuddyAdapter extends AgentAdapter {
|
|
6
|
+
readonly type: "workbuddy";
|
|
7
|
+
private process;
|
|
8
|
+
private agentSessionId;
|
|
9
|
+
private workDir;
|
|
10
|
+
private seq;
|
|
11
|
+
private runId;
|
|
12
|
+
private terminalState;
|
|
13
|
+
private hasEmittedText;
|
|
14
|
+
private runPhase;
|
|
15
|
+
private externalChannel;
|
|
16
|
+
private shennianSessionId;
|
|
17
|
+
private extraEnv;
|
|
18
|
+
configure(options: {
|
|
19
|
+
sessionId?: string;
|
|
20
|
+
externalChannel?: ExternalChannelSessionStatus | null;
|
|
21
|
+
env?: NodeJS.ProcessEnv;
|
|
22
|
+
}): void;
|
|
23
|
+
start(_sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
|
|
24
|
+
send(text: string, modelId?: string, reasoningEffort?: string, _attachments?: ChatAttachmentMeta[]): Promise<void>;
|
|
25
|
+
resume(agentSessionId: string): Promise<void>;
|
|
26
|
+
stop(): Promise<void>;
|
|
27
|
+
getStatus(): Promise<{
|
|
28
|
+
active: boolean;
|
|
29
|
+
runId?: string | null;
|
|
30
|
+
runPhase?: SessionRunPhase | null;
|
|
31
|
+
canStop?: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
private spawnAndParse;
|
|
34
|
+
private handleStreamEvent;
|
|
35
|
+
private handleContentBlock;
|
|
36
|
+
private emitText;
|
|
37
|
+
private handleProcessClose;
|
|
38
|
+
private emitFinalIfOpen;
|
|
39
|
+
private emitErrorIfOpen;
|
|
40
|
+
private emitEvent;
|
|
41
|
+
private resetRunState;
|
|
42
|
+
private killProcess;
|
|
43
|
+
}
|
|
44
|
+
export declare function sanitizeWorkBuddyError(value: string): string;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{createInterface as h}from"node:readline";import{randomUUID as d}from"node:crypto";import{AgentAdapter as m,registerAgent as p}from"./adapter.js";import{resolveBuiltinCommand as f,spawnAgentCommand as c}from"./command-spec.js";import{buildAgentProcessEnv as g}from"../agent-env.js";import{buildPlatformInstructions as y}from"./platform-instructions.js";import{ensureWorkBuddyRoomPluginBundle as I}from"../integrations/workbuddy-plugin-bundle.js";const S=new Set(["minimal","low","medium","high","xhigh","max"]);function k(i){return i?.trim()||"auto"}function x(i){const t=i?.trim();if(t){if(S.has(t))return t;throw new Error(`Unsupported WorkBuddy reasoning effort "${t}". Supported values: minimal, low, medium, high, xhigh, max.`)}}class E extends m{type="workbuddy";process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="open";hasEmittedText=!1;runPhase=null;externalChannel=null;shennianSessionId=null;extraEnv={};configure(t){this.shennianSessionId=t.sessionId??null,this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{}}async start(t,s,e){this.workDir=s,this.seq=0,e&&(this.agentSessionId=e)}async send(t,s,e,o){await this.killProcess(),this.runId=d(),this.resetRunState();const r=["-p",t,"--output-format","stream-json","--verbose","--permission-mode","auto","--setting-sources","user,project,local","--model",k(s)];r.push("--plugin-dir",I().pluginRoot);const n=y(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0);n&&r.push("--append-system-prompt",n);const a=x(e);a&&r.push("--effort",a),this.agentSessionId&&r.push("--resume",this.agentSessionId),this.spawnAndParse(r)}async resume(t){await this.killProcess(),this.agentSessionId=t,this.resetRunState()}async stop(){await this.killProcess()}async getStatus(){return{active:this.process!=null&&this.terminalState==="open",runId:this.runId||null,runPhase:this.runPhase,canStop:this.process!=null&&this.terminalState==="open"}}spawnAndParse(t){const s=f("workbuddy");if(!s){this.emit("error",new Error("WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry."));return}const e=c(s,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:g(this.extraEnv)});this.process=e,h({input:e.stdout}).on("line",n=>{if(n.trim())try{this.handleStreamEvent(JSON.parse(n))}catch{}});let r="";e.stderr?.on("data",n=>{r=`${r}${n.toString()}`.slice(-8e3)}),e.on("close",n=>{this.process===e&&(this.process=null,this.runPhase=null,this.handleProcessClose(n,r))}),e.on("error",n=>{if(this.process!==e)return;this.process=null,this.runPhase=null;const a=n.code==="ENOENT";this.emitErrorIfOpen({state:"error",message:a?"WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry.":u(n.message)})})}handleStreamEvent(t){if(t.type==="system"&&t.subtype==="init"&&t.session_id){this.agentSessionId=t.session_id,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:t.session_id});return}if(t.type==="control_request"&&t.request?.subtype==="can_use_tool"){this.runPhase="waiting_approval",this.emitEvent({state:"approval-pending",name:t.request.tool_name,args:t.request.input,approval:{title:`WorkBuddy \u8BF7\u6C42\u4F7F\u7528 ${t.request.tool_name||"\u5DE5\u5177"}`,source:"workbuddy",actionHint:"\u8BF7\u5728 WorkBuddy \u6216\u795E\u5FF5\u4E2D\u786E\u8BA4\u540E\u7EE7\u7EED\u3002"}});return}if(t.type==="assistant"){const e=t.message?.content;if(e?.length)for(const o of e)this.handleContentBlock(o);else t.text&&this.emitText(t.text,!!t.thinking);return}if(t.type!=="result")return;if(t.subtype==="tool_result"){this.runPhase="tool_running",this.emitEvent({state:"tool-result",name:t.name,result:l(t.content)});return}if(t.subtype==="error"||t.error){this.emitErrorIfOpen({state:"error",message:u(t.error||t.result||"WorkBuddy failed.")});return}!this.hasEmittedText&&t.result&&this.emitText(t.result,!1),t.session_id&&(this.agentSessionId=t.session_id);const s=t.usage??t.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:s?{inputTokens:s.input_tokens??0,outputTokens:s.output_tokens??0}:void 0})}handleContentBlock(t){t.type==="text"&&t.text?this.emitText(t.text,!1):t.type==="thinking"&&t.thinking?this.emitText(t.thinking,!0):t.type==="tool_use"?(this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:t.name,args:t.input})):t.type==="tool_result"&&this.emitEvent({state:"tool-result",name:t.name,result:l(t.content)})}emitText(t,s){this.runPhase=s?"thinking":"streaming_text";const e=!s&&this.hasEmittedText?`
|
|
2
|
+
|
|
3
|
+
`:"";this.emitEvent({state:"delta",text:e+t,thinking:s||void 0}),s||(this.hasEmittedText=!0)}handleProcessClose(t,s){if(t!==0&&t!==null){this.emitErrorIfOpen({state:"error",message:u(s)||`WorkBuddy exited with code ${t}.`});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(t){this.terminalState==="open"&&(this.terminalState="final",this.runPhase=null,this.emitEvent(t))}emitErrorIfOpen(t){this.terminalState==="open"&&(this.terminalState="error",this.runPhase=null,this.emitEvent(t))}emitEvent(t){this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}resetRunState(){this.seq=0,this.terminalState="open",this.hasEmittedText=!1,this.runPhase=null}async killProcess(){const t=this.process;t&&(this.process=null,this.runPhase=null,t.kill("SIGTERM"),await new Promise(s=>{let e=!1;const o=()=>{e||(e=!0,s())};t.once("close",o),setTimeout(()=>{t.kill("SIGKILL"),o()},3e3).unref?.()}))}}function l(i){if(typeof i=="string")return i;try{return JSON.stringify(i)}catch{return"[unserializable WorkBuddy tool result]"}}function u(i){return i.replace(/(Authorization\s*:\s*)Bearer\s+[A-Za-z0-9._~+\/-]+/gi,"$1Bearer [redacted]").replace(/(api[-_ ]?key|access[-_ ]?token|refresh[-_ ]?token|connector[-_ ]?token)(\s*[:=]\s*)[^\s,;]+/gi,"$1$2[redacted]").trim().slice(0,2e3)}p("workbuddy",()=>new E);export{E as WorkBuddyAdapter,k as normalizeWorkBuddyModelId,x as normalizeWorkBuddyReasoningEffort,u as sanitizeWorkBuddyError};
|
|
@@ -53,6 +53,7 @@ export declare function writeDaemonLauncher(pid: number, launcher?: DaemonLaunch
|
|
|
53
53
|
export declare function clearDaemonLauncher(instanceId?: string): void;
|
|
54
54
|
export declare function recordStartedDaemon(childPid: number | undefined): void;
|
|
55
55
|
export declare function findRunningDaemonProcessIds(excludePid?: number): number[];
|
|
56
|
+
export declare function isIsolatedDaemonE2eInstance(env?: NodeJS.ProcessEnv, shennianDir?: string, tempDir?: string): boolean;
|
|
56
57
|
export declare function getDaemonStatus(opts?: {
|
|
57
58
|
cleanupStale?: boolean;
|
|
58
59
|
}): DaemonStatus;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import s from"chalk";import o from"node:fs";import
|
|
2
|
-
`)}function X(e){const n=e?.trim();if(!n)return;const t=j();t.serverUrl=n,le(t)}function q(e){return e?.trim()||process.env.SHENNIAN_DESKTOP_SERVER_URL?.trim()||void 0}const $="com.shennian.agent",m=
|
|
1
|
+
import s from"chalk";import o from"node:fs";import c from"node:path";import u from"node:os";import{execSync as a,spawn as ae}from"node:child_process";import{randomUUID as ce}from"node:crypto";import{fileURLToPath as ue}from"node:url";import{getShennianDir as de,loadConfig as j,resolveShennianPath as h,saveConfig as le}from"../config/index.js";import{buildAugmentedPath as pe}from"../env-path.js";import{buildWindowsLauncherCommand as me,buildWindowsScheduledTaskXml as fe,buildWindowsStartupVbs as Se,escapeXml as N,isWindowsCmdScript as he,quoteCmdArg as W,quoteSystemdArg as ge}from"./daemon-windows.js";import{waitForDaemonReadyStatus as b}from"./daemon-start-wait.js";import{findRunningWindowsDaemonProcessIds as ye,isShennianRunServiceCommand as we}from"./daemon-process.js";import{buildWindowsLauncherCommand as Sn,buildWindowsScheduledTaskXml as hn,buildWindowsStartupVbs as gn}from"./daemon-windows.js";import{isShennianRunServiceCommand as wn}from"./daemon-process.js";const Ee=c.dirname(ue(import.meta.url)),g=de(),p=h("daemon.pid"),d=h("daemon.log"),L=h("remote-access.disabled"),P=h("daemon-launcher.json"),F=c.resolve(Ee,"../../bin/shennian.js"),B=process.execPath,V=new Set(["PATH","HOME","USERPROFILE","HOMEDRIVE","HOMEPATH","USERNAME","USERDOMAIN","COMPUTERNAME","USER","LOGNAME","SHELL","TMPDIR","LANG","LC_ALL","LC_CTYPE","SSH_AUTH_SOCK","XDG_CONFIG_HOME","XDG_DATA_HOME","TEMP","TMP","APPDATA","LOCALAPPDATA","SHENNIAN_DESKTOP_SERVER_URL","SHENNIAN_WECHAT_CHANNEL_HELPER_DIR","SHENNIAN_HOME","SHENNIAN_NATIVE_FUSION_DISABLED","SHENNIAN_WECHAT_DELIVERABILITY_TRACE"]);function ve(e){return V.has(e)}function l(){const e=u.platform();return e==="darwin"||e==="linux"||e==="win32"?e:"linux"}function R(e){const n=e.replace(/\\/g,"/").toLowerCase(),t=u.tmpdir().replace(/\\/g,"/").toLowerCase();return n.includes("/_npx/")||n.includes("/npm-cache/_npx/")||n.includes("/pnpm/dlx/")||n.startsWith(t.endsWith("/")?t:`${t}/`)}function Ae(e){return o.existsSync(e.scriptPath)&&!R(e.scriptPath)?{command:e.nodeExec,args:[e.scriptPath,"run-service"],mode:"direct"}:e.shennianCommandPath&&!R(e.shennianCommandPath)?{command:e.shennianCommandPath,args:["run-service"],mode:"global-shim"}:e.npxPath?{command:e.npxPath,args:["--yes","shennian","run-service"],mode:"npx"}:{command:e.nodeExec,args:[e.scriptPath,"run-service"],mode:"direct"}}function Ie(e){const n=e.trim();if(!n)return null;if(n.startsWith("{"))try{const r=JSON.parse(n),i=Number(r.pid);return!Number.isInteger(i)||i<=0?null:{pid:i,...typeof r.instanceId=="string"?{instanceId:r.instanceId}:{},...typeof r.version=="string"?{version:r.version}:{},...r.launcher==="desktop-managed"||r.launcher==="global-cli"||r.launcher==="unknown"?{launcher:r.launcher}:{},...typeof r.startedAt=="string"?{startedAt:r.startedAt}:{},...r.adopted===!0?{adopted:!0}:{}}}catch{return null}const t=parseInt(n,10);return isNaN(t)?null:{pid:t}}function O(){try{return Ie(o.readFileSync(p,"utf-8"))}catch{return null}}function ke(){return O()?.pid??null}function w(e){try{return process.kill(e,0),!0}catch{return!1}}function Pe(e,n=3e3){const t=Date.now();for(;Date.now()-t<n;){if(!w(e))return!0;Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,100)}return!w(e)}function De(){return o.existsSync(L)}function Ne(){try{o.unlinkSync(L)}catch{}}function J(){return"global-cli"}function be(){return`${process.pid}-${Date.now()}-${ce()}`}function Le(e,n,t={}){o.mkdirSync(g,{recursive:!0}),o.writeFileSync(p,JSON.stringify({pid:e,instanceId:n,...t.version?{version:t.version}:{},launcher:t.launcher??J(),...t.adopted?{adopted:!0}:{},startedAt:new Date().toISOString()},null,2))}function dn(e,n){const t=O();if(!(t?.pid!==e||t.instanceId!==n))try{o.unlinkSync(p)}catch{}}function G(e,n=J(),t){o.mkdirSync(g,{recursive:!0}),o.writeFileSync(P,JSON.stringify({pid:e,launcher:n,...t?{instanceId:t}:{},updatedAt:new Date().toISOString()},null,2))}function T(e){if(e)try{if(JSON.parse(o.readFileSync(P,"utf-8")).instanceId!==e)return}catch{return}try{o.unlinkSync(P)}catch{}}function Re(e){e&&G(e)}function Oe(e,n){if(!e||!n)return"unknown";try{const t=JSON.parse(o.readFileSync(P,"utf-8"));if(t.pid!==e)return"unknown";if(t.launcher==="desktop-managed"||t.launcher==="global-cli")return t.launcher}catch{}return x(e)}function x(e){if(l()==="win32")return"unknown";try{const n=a(`ps -p ${e} -o command=`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:1e3,windowsHide:!0}).replace(/\\/g,"/");if(n.includes("/node_modules/shennian/")||n.includes("/bin/shennian")||n.includes(" shennian run-service")||n.includes(" shennian.js run-service"))return"global-cli"}catch{}return"unknown"}function K(e=process.pid){if(l()==="win32")return ye(e);try{return a("ps -axo pid=,command=",{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:1e3,windowsHide:!0}).split(/\r?\n/).map(t=>{const r=t.trim().match(/^(\d+)\s+(.+)$/);if(!r)return null;const i=Number(r[1]),S=r[2];return!Number.isInteger(i)||i===e?null:we(S)?i:null}).filter(t=>typeof t=="number")}catch{return[]}}function ln(e=process.env,n=g,t=u.tmpdir()){if(e.SHENNIAN_E2E_ISOLATED_DAEMON!=="1"||!e.SHENNIAN_HOME?.trim())return!1;const r=c.relative(c.resolve(t),c.resolve(n));return r!==""&&r!==".."&&!r.startsWith(`..${c.sep}`)&&!c.isAbsolute(r)}function f(e={}){let n=O(),t=n?.pid??null,r=t!==null&&w(t),i=t!==null&&!r,S=n?.adopted===!0;const E=j();if(i&&e.cleanupStale){try{o.unlinkSync(p)}catch{}n=null,t=null,r=!1,i=!1}if(!r){const y=K()[0];if(y&&(t=y,r=!0,i=!1,S=!0,e.cleanupStale)){const C=be();Le(y,C,{launcher:x(y),adopted:!0}),G(y,x(y)),n={pid:y,instanceId:C,adopted:!0}}}return{running:r,pid:t,stale:i,remoteAccessDisabled:De(),launcher:Oe(t,r),platform:l(),shennianDir:g,pidFile:p,logFile:d,...n?.instanceId?{instanceId:n.instanceId}:{},...S?{adopted:!0}:{},...E.machineId?{machineId:E.machineId}:{},paired:!!(E.machineToken&&E.machineId),...E.serverUrl?{serverUrl:E.serverUrl}:{}}}function v(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
2
|
+
`)}function X(e){const n=e?.trim();if(!n)return;const t=j();t.serverUrl=n,le(t)}function q(e){return e?.trim()||process.env.SHENNIAN_DESKTOP_SERVER_URL?.trim()||void 0}const $="com.shennian.agent",m=c.join(u.homedir(),"Library/LaunchAgents",`${$}.plist`),Te=c.join(u.homedir(),"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup"),H=h("autostart.cmd"),_=h("autostart.vbs"),M=h("autostart.xml"),xe=c.join(Te,"ShennianAgent.vbs");function Y(e){const n=l()==="win32"?`where ${e}`:`command -v ${e}`;try{return a(n,{stdio:["ignore","pipe","pipe"],encoding:"utf-8",windowsHide:!0}).split(/\r?\n/).map(i=>i.trim()).find(Boolean)??null}catch{return null}}function $e(){const e=l()==="win32"?"npx.cmd":"npx",n=c.join(c.dirname(B),e);return o.existsSync(n)?n:Y("npx")}function A(){return Ae({nodeExec:B,scriptPath:F,shennianCommandPath:Y("shennian"),npxPath:$e()})}function z(){try{a(`schtasks /delete /tn "${I}" /f`,{stdio:"pipe",windowsHide:!0})}catch{}}function Q(){try{o.unlinkSync(xe)}catch{}}function He(){const e=process.env.USERDOMAIN?.trim(),n=process.env.COMPUTERNAME?.trim(),t=process.env.USERNAME?.trim()||u.userInfo().username;return e&&e.toUpperCase()!=="WORKGROUP"?`${e}\\${t}`:n?`${n}\\${t}`:t}function _e(e){if(l()==="win32"&&he(e.command)){const n=[e.command,...e.args].map(W).join(" ");return{command:process.env.ComSpec||"cmd.exe",args:["/d","/s","/c",`"${n}"`],windowsVerbatimArguments:!0}}return{command:e.command,args:e.args}}function Me(e,n,t=process.env){return{detached:!0,stdio:["ignore",n,n],env:t,windowsHide:!0,...e.windowsVerbatimArguments?{windowsVerbatimArguments:!0}:{}}}function Ue(){const e=A();o.writeFileSync(H,me(e,d)),o.writeFileSync(_,Se(H)),Q(),z();const n=fe({userId:He(),command:c.join(process.env.SystemRoot||"C:\\Windows","System32","wscript.exe"),arguments:[W(_)]});o.writeFileSync(M,n,"utf8");try{return a(`schtasks /create /tn "${I}" /xml "${M}" /f`,{stdio:"pipe",windowsHide:!0}),a(`schtasks /run /tn "${I}"`,{stdio:"pipe",windowsHide:!0}),!0}catch{return!1}}function Z(){const e={};for(const n of V)process.env[n]&&(e[n]=process.env[n]);if(e.HOME??=u.homedir(),e.PATH=pe({pathValue:e.PATH,env:e}),e.USER??=u.userInfo().username,l()==="win32"){const n=process.env.TEMP||process.env.TMP||u.tmpdir(),t=u.homedir();e.USERPROFILE??=t;const r=c.win32.parse(t);e.HOMEDRIVE??=r.root.replace(/[\\/]$/,"")||process.env.HOMEDRIVE||"",e.HOMEPATH??=t.slice((e.HOMEDRIVE||"").length)||process.env.HOMEPATH||"",e.USERNAME??=process.env.USERNAME||u.userInfo().username,e.COMPUTERNAME??=process.env.COMPUTERNAME||"",e.TMPDIR??=n,e.TEMP??=n,e.TMP??=n}else e.TMPDIR??="/tmp";return e}function Ce(){const e=Z(),n=A(),t=Object.entries(e).map(([i,S])=>` <key>${N(i)}</key>
|
|
3
3
|
<string>${N(S)}</string>`).join(`
|
|
4
4
|
`),r=[n.command,...n.args].map(i=>` <string>${N(i)}</string>`).join(`
|
|
5
5
|
`);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -23,11 +23,11 @@ ${t}
|
|
|
23
23
|
<key>ThrottleInterval</key>
|
|
24
24
|
<integer>5</integer>
|
|
25
25
|
<key>StandardOutPath</key>
|
|
26
|
-
<string>${
|
|
26
|
+
<string>${d}</string>
|
|
27
27
|
<key>StandardErrorPath</key>
|
|
28
|
-
<string>${
|
|
28
|
+
<string>${d}</string>
|
|
29
29
|
</dict>
|
|
30
|
-
</plist>`}const D=
|
|
30
|
+
</plist>`}const D=c.join(u.homedir(),".config/systemd/user/shennian.service");function je(){const e=Z(),n=A(),t=Object.entries(e).map(([i,S])=>`Environment=${i}=${S}`).join(`
|
|
31
31
|
`),r=[n.command,...n.args].map(ge).join(" ");return`[Unit]
|
|
32
32
|
Description=Shennian Agent Daemon
|
|
33
33
|
After=network.target
|
|
@@ -37,10 +37,10 @@ ${t}
|
|
|
37
37
|
ExecStart=${r}
|
|
38
38
|
Restart=always
|
|
39
39
|
RestartSec=10
|
|
40
|
-
StandardOutput=append:${
|
|
41
|
-
StandardError=append:${
|
|
40
|
+
StandardOutput=append:${d}
|
|
41
|
+
StandardError=append:${d}
|
|
42
42
|
|
|
43
43
|
[Install]
|
|
44
|
-
WantedBy=default.target`}const
|
|
44
|
+
WantedBy=default.target`}const I="ShennianAgent";function We(e){a(e,{stdio:"pipe",windowsHide:!0})}function Fe(){const e=process.getuid?.();if(typeof e=="number")return e;const n=u.userInfo();return typeof n.uid=="number"?n.uid:n.username}function ee(e=Fe()){return`gui/${e}/${$}`}function Be(e=We){try{return e(`launchctl unload "${m}" 2>/dev/null; launchctl load -w "${m}"`),e(`launchctl kickstart -k "${ee()}"`),!0}catch{try{return e(`launchctl load -w "${m}"`),e(`launchctl kickstart -k "${ee()}"`),!0}catch{return!1}}}function Ve(){o.mkdirSync(g,{recursive:!0});const e={};for(const[n,t]of Object.entries(process.env))t!==void 0&&ve(n)&&(e[n]=t);o.writeFileSync(h("env.json"),JSON.stringify(e,null,2))}function ne(e={}){o.mkdirSync(g,{recursive:!0});const n=f({cleanupStale:!0});if(n.pid!==null&&n.running&&!n.adopted){e.quiet||console.log(s.green(`\u2713 Background service already running (PID ${n.pid})`));return}te(n);const t=o.openSync(d,"a"),r=_e(A()),i=ae(r.command,r.args,Me(r,t));i.unref(),o.closeSync(t),Re(i.pid),e.quiet||(console.log(s.green(`\u2713 Background service started (PID ${i.pid})`)),console.log(s.gray(` Logs: ${d}`)))}function te(e=f({cleanupStale:!0})){if(!(e.pid===null||!e.running||!e.adopted))try{process.kill(e.pid,"SIGTERM"),Pe(e.pid);try{o.unlinkSync(p)}catch{}}catch{}}function re(){o.mkdirSync(g,{recursive:!0});const e=l();switch(A().mode==="direct"&&R(F)&&console.warn(s.yellow("\u26A0 Warning: Current CLI path is temporary (npx). Auto-start may not work after reboot.\n Run `npm install -g shennian@latest` for reliable auto-start.")),e){case"darwin":{const t=c.dirname(m);return o.mkdirSync(t,{recursive:!0}),o.writeFileSync(m,Ce()),Be()}case"linux":{const t=c.dirname(D);o.mkdirSync(t,{recursive:!0}),o.writeFileSync(D,je());try{a("systemctl --user daemon-reload && systemctl --user enable shennian",{stdio:"pipe",windowsHide:!0})}catch{return!1}try{a(`loginctl enable-linger ${u.userInfo().username}`,{stdio:"pipe",windowsHide:!0})}catch{}try{return a("systemctl --user restart shennian",{stdio:"pipe",windowsHide:!0}),!0}catch{return!1}}case"win32":return Ue()}}function Je(){const n=f({cleanupStale:!0}).pid;if(n===null)return{};if(!w(n)){try{o.unlinkSync(p)}catch{}return{stalePid:n}}try{return process.kill(n,"SIGTERM"),{stoppedPid:n}}catch(t){return{error:t instanceof Error?t.message:String(t)}}}async function Ge(e=5e3){const n=Je();if(!n.stoppedPid)return n;if(!await k(n.stoppedPid,e))try{process.kill(n.stoppedPid,"SIGKILL"),await k(n.stoppedPid,2e3)}catch(r){return{...n,error:r instanceof Error?r.message:String(r)}}try{o.unlinkSync(p)}catch{}T();for(const r of K())if(r!==n.stoppedPid)try{process.kill(r,"SIGTERM"),await k(r,2e3)}catch{}return n}function Ke(e={}){X(q(e.api)),Ne(),te(),re()||ne({quiet:e.json}),e.json?v(b(()=>f({cleanupStale:!0}))):console.log(s.green("\u2713 Background service started"))}async function Xe(e={}){switch(o.mkdirSync(g,{recursive:!0}),o.writeFileSync(L,new Date().toISOString()),l()){case"darwin":{if(o.existsSync(m))try{a(`launchctl unload -w "${m}"`,{stdio:"pipe",windowsHide:!0})}catch{}break}case"linux":{try{a("systemctl --user disable --now shennian",{stdio:"pipe",windowsHide:!0})}catch{}break}case"win32":{try{a(`schtasks /change /tn "${I}" /disable`,{stdio:"pipe",windowsHide:!0})}catch{}try{a(`schtasks /end /tn "${I}"`,{stdio:"pipe",windowsHide:!0})}catch{}break}}const t=await Ge(),r=f({cleanupStale:!0});if(e.json){v(t.error?{...r,error:t.error}:r);return}t.error?console.error(s.red(`\u2717 Failed to stop: ${t.error}`)):console.log(s.green("\u2713 Background service stopped"))}function oe(e){Ve(),Ke(e)}async function U(e={}){await Xe(e)}async function k(e,n=5e3){const t=Date.now();for(;Date.now()-t<n;){if(!w(e))return!0;await new Promise(r=>setTimeout(r,100))}return!w(e)}async function qe(e={}){X(q(e.api));const n=ke();if(n!==null&&w(n))try{process.kill(n,"SIGTERM"),await k(n)||(process.kill(n,"SIGKILL"),await k(n,2e3));try{o.unlinkSync(p)}catch{}T(),e.json||console.log(s.green(`\u2713 Background service stopped (PID ${n})`))}catch(t){const r=t instanceof Error?t.message:String(t);e.json?v({...f(),error:r}):console.error(s.red(`\u2717 Failed to stop: ${r}`));return}else if(n!==null){try{o.unlinkSync(p)}catch{}T(),e.json||console.log(s.yellow(`\u26A0 Service process no longer exists, cleaned up stale PID ${n}`))}else e.json||console.log(s.gray("\u25CF Background service not running, starting it now"));if(l()==="linux"&&re()){e.json&&v(b(()=>f({cleanupStale:!0})));return}ne({quiet:e.json}),e.json&&v(b(()=>f({cleanupStale:!0})))}function ie(e={}){const n=f({cleanupStale:!0});if(e.json){v(n);return}if(n.pid===null){console.log(s.gray("\u25CF Background service not running"));return}n.running?(console.log(s.green(`\u25CF Background service running (PID ${n.pid})`)),console.log(s.gray(` Logs: ${d}`))):console.log(s.yellow(`\u25CF Background service stopped (PID ${n.pid} is stale)`))}function se(e){if(!o.existsSync(d)){console.log(s.gray("No logs yet"));return}try{const n=a(u.platform()==="win32"?`powershell Get-Content -Tail ${e.lines} "${d}"`:`tail -n ${e.lines} "${d}"`,{encoding:"utf-8",windowsHide:!0});process.stdout.write(n)}catch{const n=o.readFileSync(d,"utf-8").split(`
|
|
45
45
|
`).slice(-e.lines);console.log(n.join(`
|
|
46
|
-
`))}}async function Ye(){switch(await
|
|
46
|
+
`))}}async function Ye(){switch(await U(),l()){case"darwin":{if(o.existsSync(m)){try{a(`launchctl unload -w "${m}"`,{stdio:"pipe",windowsHide:!0})}catch{}o.unlinkSync(m),console.log(s.green("\u2713 Auto-start uninstalled (launchd)"))}break}case"linux":{try{a("systemctl --user disable --now shennian",{stdio:"pipe",windowsHide:!0})}catch{}if(o.existsSync(D)){o.unlinkSync(D);try{a("systemctl --user daemon-reload",{stdio:"pipe",windowsHide:!0})}catch{}}console.log(s.green("\u2713 Auto-start uninstalled (systemd)"));break}case"win32":{z();try{o.unlinkSync(H)}catch{}try{o.unlinkSync(_)}catch{}try{o.unlinkSync(M)}catch{}Q(),console.log(s.green("\u2713 Auto-start uninstalled (Task Scheduler)"));break}}}function pn(e){e.command("start").description("Start the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(r=>oe(r)),e.command("stop").description("Stop the background service").option("--json","Print machine-readable status JSON").action(r=>U(r)),e.command("status").description("Show background service status").option("--json","Print machine-readable status JSON").action(r=>ie(r)),e.command("logs").description("Show recent logs").option("-n, --lines <n>","Number of lines","50").action(r=>se({lines:parseInt(r.lines,10)}));const n=e.command("daemon",{hidden:!0}).description("Deprecated: use top-level start/stop/status/logs"),t=(r,i)=>{i||console.error(s.yellow(`\u26A0 Deprecated command. Use \`shennian ${r}\` instead.`))};n.command("start").description("Start the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(r=>{t("start",r.json),oe(r)}),n.command("stop").description("Stop the background service").option("--json","Print machine-readable status JSON").action(async r=>{t("stop",r.json),await U(r)}),n.command("restart").description("Restart the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(r=>{t("stop && shennian start",r.json),qe(r)}),n.command("status").description("Show background service status").option("--json","Print machine-readable status JSON").action(r=>{t("status",r.json),ie(r)}),n.command("logs").description("Show recent logs").option("-n, --lines <n>","Number of lines","50").action(r=>{t("logs"),se({lines:parseInt(r.lines,10)})}),n.command("uninstall").description("Uninstall auto-start service").action(Ye)}export{Me as buildDaemonSpawnOptions,Sn as buildWindowsLauncherCommand,hn as buildWindowsScheduledTaskXml,gn as buildWindowsStartupVbs,Z as captureEnvForService,T as clearDaemonLauncher,dn as clearDaemonPidIfOwner,Ne as clearRemoteAccessDisabled,be as createDaemonInstanceId,K as findRunningDaemonProcessIds,J as getCurrentProcessDaemonLauncher,f as getDaemonStatus,ee as getLaunchdServiceTarget,re as installService,R as isEphemeralCliPath,ln as isIsolatedDaemonE2eInstance,De as isRemoteAccessDisabled,ve as isSafeSnapshotEnvKey,wn as isShennianRunServiceCommand,Re as recordStartedDaemon,pn as registerDaemonCommand,Be as reloadLaunchdAgent,Ae as resolveServiceLaunchSpec,Ve as saveEnvSnapshot,ne as startDaemonProcess,G as writeDaemonLauncher,Le as writeDaemonPid};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{WorkBuddyPluginLifecycle as l,WorkBuddyPluginLifecycleError as f}from"../integrations/workbuddy-plugin-lifecycle.js";import{CodexRoomPluginLifecycle as m}from"../integrations/codex-room-plugin-lifecycle.js";import{ClaudeRoomPluginLifecycle as y}from"../integrations/claude-room-plugin-lifecycle.js";import{RoomPluginLifecycleError as p}from"../integrations/room-plugin-lifecycle-common.js";const d=["The official Shennian Agent connection installs a local Skill, MCP tool, and lifecycle Hooks with your user permissions.","It reports only the current native Session identifier and lifecycle metadata to the local authenticated Shennian daemon.","It does not send prompts, transcript contents, credentials, or native Session identifiers to a Room or remote URL.","You can disable or remove it at any time."].join(" ");function k(t){const o=t.command("integration").description("Manage local Agent integrations");u(o,"codex","Codex",()=>new m),u(o,"claude-code","Claude Code",()=>new y);const e=o.command("workbuddy").description("Manage the official WorkBuddy connection");e.command("status",{isDefault:!0}).option("--json","Print JSON",!1).action(async n=>{await r(()=>new l().status(),!!n.json)});for(const n of["install","enable","disable","update","uninstall"])e.command(n).option("--confirm-user-action","Confirm this action was explicitly requested by the user",!1).option("--json","Print JSON",!1).action(async i=>{if(!i.confirmUserAction){s({ok:!1,errorCode:"user_confirmation_required",disclosure:d},!!i.json),process.exitCode=2;return}await r(()=>new l().apply(n),!!i.json)})}function u(t,o,e,n){const i=t.command(o).description(`Manage the official ${e} connection`);i.command("status",{isDefault:!0}).option("--json","Print JSON",!1).action(async a=>{await r(()=>n().status(),!!a.json)});for(const a of["install","enable","disable","update","uninstall"])i.command(a).option("--confirm-user-action","Confirm this action was explicitly requested by the user",!1).option("--json","Print JSON",!1).action(async c=>{if(!c.confirmUserAction){s({ok:!1,errorCode:"user_confirmation_required",disclosure:d},!!c.json),process.exitCode=2;return}await r(()=>n().apply(a),!!c.json)})}async function r(t,o){try{const e=await t();s({ok:!0,result:e},o)}catch(e){const n=e instanceof f||e instanceof p?e.code:"integration_failed";s({ok:!1,errorCode:n},o),process.exitCode=1}}function s(t,o){console.log(o?JSON.stringify(t):JSON.stringify(t,null,2))}export{k as registerIntegrationCommand};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
`))}function A(n){const o=n.command("manager").description("Manager Agent local tools"),a=o.command("sessions").description("Manage same-project worker sessions");a.command("list").description("List same-project sessions visible to this Manager").option("--json","Print JSON").action(async e=>{const t=await i("/sessions/list",{});if(e.json)s(t);else{const m=t.sessions??[];for(const d of m)console.log(`${d.sessionId} ${d.agentType} ${d.role??""} ${d.status} ${d.title??d.summary??""}`)}}),a.command("start").description("Start a worker session in the same project").requiredOption("--agent <agent>","Worker agent type, e.g. codex, claude, gemini, cursor, opencode, pi, or custom:<name>").requiredOption("--workdir <path>","Worker workdir; must match Manager workdir").option("--model <model>","Worker model id").option("--message <text>","Worker prompt").option("--message-file <path>","Read worker prompt from file").option("--json","Print JSON").action(async e=>{const t=await i("/sessions/start",{agentType:e.agent,workDir:e.workdir,modelId:e.model,message:y(e)});e.json?s(t):console.log(t.session?.sessionId??"ok")}),a.command("send").description("Queue a message for a managed worker; runs immediately if idle").requiredOption("--session-id <id>","Worker session id").option("--message <text>","Message text").option("--message-file <path>","Read message from file").option("--direct","Bypass queue and send immediately").action(async e=>{await i("/sessions/send",{sessionId:e.sessionId,message:y(e),enqueue:!e.direct}),console.log("ok")});const r=a.command("queue").description("Inspect and edit pending worker messages");r.command("list").description("List pending messages for a managed worker").requiredOption("--session-id <id>","Worker session id").option("--json","Print JSON").action(async e=>{const t=await i("/sessions/queue",{sessionId:e.sessionId});if(e.json)s(t);else{const m=t.queue?.pending??[];for(const d of m)console.log(`${d.id} ${d.text.replace(/\s+/g," ").slice(0,120)}`)}}),r.command("edit").description("Edit a pending worker message").requiredOption("--session-id <id>","Worker session id").requiredOption("--message-id <id>","Queued message id").option("--message <text>","Replacement message text").option("--message-file <path>","Read replacement message from file").action(async e=>{await i("/sessions/queue/edit",{sessionId:e.sessionId,queueMessageId:e.messageId,message:y(e)}),console.log("ok")}),r.command("delete").description("Delete a pending worker message").requiredOption("--session-id <id>","Worker session id").requiredOption("--message-id <id>","Queued message id").action(async e=>{await i("/sessions/queue/delete",{sessionId:e.sessionId,queueMessageId:e.messageId}),console.log("ok")});const c=async e=>{await i("/sessions/stop",{sessionId:e.sessionId}),console.log("ok")};a.command("stop").aliases(["terminate","kill"]).description("Stop or terminate a running managed worker").requiredOption("--session-id <id>","Worker session id").action(c),a.command("read").description("Read a managed worker transcript").requiredOption("--session-id <id>","Worker session id").option("--limit <n>","Message limit","200").option("--json","Print JSON").action(async e=>{const t=await i("/sessions/read",{sessionId:e.sessionId,limit:Number(e.limit)});e.json?s(t):s(t.messages??[])}),o.command("memory").description("Manager project memory helpers").command("path").description("Print project memory directory path").action(async()=>{const e=await i("/memory/path",{});console.log(e.path)});const l=o.command("external").description("External channel tools"),p=async e=>{await i("/external/reply",e),console.log("ok")};l.command("send").description("Send a message to the Manager-bound external channel").requiredOption("--text <text>","Message text").option("--reply-target <id>","Daemon-generated reply target; omitted means latest external message for this Manager").option("--idempotency-key <key>","Idempotency key").action(p),l.command("send-image").description("Send an image file to the Manager-bound external channel").requiredOption("--path <path>","Image file path").option("--caption <text>","Optional text to send before the image").option("--reply-target <id>","Daemon-generated reply target; omitted means latest external message for this Manager").option("--idempotency-key <key>","Idempotency key").action(async e=>{await p({text:e.caption,attachment:h(e.path,"image"),replyTarget:e.replyTarget,idempotencyKey:e.idempotencyKey})}),l.command("send-video").description("Send a video file to the Manager-bound external channel").requiredOption("--path <path>","Video file path").option("--caption <text>","Optional text to send before the video").option("--reply-target <id>","Daemon-generated reply target; omitted means latest external message for this Manager").option("--idempotency-key <key>","Idempotency key").action(async e=>{await p({text:e.caption,attachment:h(e.path,"video"),replyTarget:e.replyTarget,idempotencyKey:e.idempotencyKey})}),l.command("send-file").description("Send a file to the Manager-bound external channel").requiredOption("--path <path>","File path").option("--caption <text>","Optional text to send before the file").option("--reply-target <id>","Daemon-generated reply target; omitted means latest external message for this Manager").option("--idempotency-key <key>","Idempotency key").action(async e=>{await p({text:e.caption,attachment:h(e.path,"file"),replyTarget:e.replyTarget,idempotencyKey:e.idempotencyKey})}),l.command("reply").description("Send an explicit reply to an external channel").option("--reply-target <id>","Daemon-generated reply target; omitted means latest external message for this Manager").option("--channel-id <id>","Channel id").option("--conversation-id <id>","Conversation id").requiredOption("--text <text>","Reply text").option("--idempotency-key <key>","Idempotency key").action(p);const w=o.command("channel").description("Manager external channel config");w.command("get").description("Get bound external channel config").option("--json","Print JSON").action(async e=>{const t=await i("/channel/get",{});e.json?s(t):s(t.channel??null)}),w.command("upsert").description("Create or update an external channel binding").option("--id <id>","Channel id").option("--name <name>","Channel display name").requiredOption("--enabled <true|false>","Whether the channel should be enabled").option("--ws-url <url>","External websocket URL").option("--token <token>","Bearer token").option("--can-reply <true|false>","Whether reply should be allowed").option("--json","Print JSON").action(async e=>{const t=await i("/channel/upsert",{id:e.id,name:e.name,enabled:e.enabled==="true",wsUrl:e.wsUrl,token:e.token,canReply:e.canReply===void 0?void 0:e.canReply==="true"});e.json?s(t):s(t.channel??null)});const u=o.command("wechat-rpa").description("Local WeChat RPA channel config");u.command("get").description("Get local WeChat RPA channel config").option("--json","Print JSON").action(async e=>{const t=await i("/wechat-rpa/channel/get",{});e.json?s(t):s(t.channel??null)}),u.command("status").description("Print local WeChat RPA channel runtime status").option("--json","Print JSON").action(async e=>{const t=await i("/wechat-rpa/channel/get",{});e.json?s(t):k(t.channel??null)}),u.command("sync").description("Run one immediate WeChat RPA sync and print the updated runtime status").option("--json","Print JSON").action(async e=>{const t=await i("/wechat-rpa/channel/sync",{});e.json?s(t):k(t.channel??null)}),u.command("upsert").description("Create or update a local WeChat RPA channel binding").option("--id <id>","Channel id").option("--name <name>","Channel display name").requiredOption("--enabled <true|false>","Whether the channel should be enabled").option("--group <name>","Bound WeChat conversation name; pass once per Shennian conversation",I,[]).option("--can-reply <true|false>","Whether reply should be allowed").option("--source <wechat-channel|macos-flow|wechat-rpa-lab|macos-probe|fixture-jsonl>","WeChat RPA implementation source").option("--poll-interval-ms <n>","Polling interval in milliseconds").option("--recent-limit <n>","Recent message limit").option("--idle-seconds <n>","Minimum user idle seconds before foreground automation").option("--force-foreground <true|false>","Force WeChat foreground while syncing").option("--restore-previous <true|false>","Restore previous foreground app after syncing").option("--download-attachments <true|false>","Click and localize inbound attachment candidates").option("--download-attachments-dir <path>","Directory for localized inbound WeChat attachments").option("--privacy-consent <true|false>","Confirm WeChat channel data and privacy consent").option("--flow-script-path <path>","Override macOS flow script path").option("--json","Print JSON").action(async e=>{if(e.enabled==="true"&&e.group.length>1)throw new Error("WeChat RPA \u6BCF\u4E2A\u5BF9\u8BDD\u53EA\u80FD\u7ED1\u5B9A\u4E00\u4E2A\u7FA4");const t=await i("/wechat-rpa/channel/upsert",{id:e.id,name:e.name,enabled:e.enabled==="true",groups:e.group.map(m=>({name:m})),canReply:g(e.canReply),source:e.source,pollIntervalMs:f(e.pollIntervalMs),recentLimit:f(e.recentLimit),idleSeconds:f(e.idleSeconds),forceForeground:g(e.forceForeground),noRestore:e.restorePrevious===void 0?void 0:e.restorePrevious!=="true",downloadAttachments:g(e.downloadAttachments),downloadAttachmentsDir:e.downloadAttachmentsDir,privacyConsentAccepted:g(e.privacyConsent),flowScriptPath:e.flowScriptPath});e.json?s(t):s(t.channel??null)})}export{A as registerManagerCommand};
|
|
1
|
+
import l from"node:fs";import p from"chalk";function u(){const o=process.env.SHENNIAN_MANAGER_IPC_URL,r=process.env.SHENNIAN_MANAGER_IPC_TOKEN,s=process.env.SHENNIAN_MANAGER_SESSION_ID;return(!o||!r||!s)&&(console.error(p.red("\u2717 This command must run inside a Shennian Manager Agent session.")),process.exit(1)),{url:o,token:r,managerSessionId:s}}async function t(o,r){const s=u(),a=await fetch(`${s.url}${o}`,{method:"POST",headers:{authorization:`Bearer ${s.token}`,"content-type":"application/json","x-shennian-manager-session-id":s.managerSessionId},body:JSON.stringify({...r,managerSessionId:s.managerSessionId})}),d=await a.json().catch(()=>({ok:!1,error:a.statusText}));if(!a.ok||!d.ok)throw new Error(d.error||`Manager IPC failed: ${a.status}`);return d}function m(o){console.log(JSON.stringify(o,null,2))}function g(o){return o.messageFile?l.readFileSync(o.messageFile,"utf-8"):o.message??""}function I(o){const r=o.command("manager").description("Manager Agent local tools"),s=r.command("sessions").description("Manage same-project worker sessions");s.command("list").description("List same-project sessions visible to this Manager").option("--json","Print JSON").action(async e=>{const n=await t("/sessions/list",{});if(e.json)m(n);else{const c=n.sessions??[];for(const i of c)console.log(`${i.sessionId} ${i.agentType} ${i.role??""} ${i.status} ${i.title??i.summary??""}`)}}),s.command("start").description("Start a worker session in the same project").requiredOption("--agent <agent>","Worker agent type, e.g. codex, claude, gemini, cursor, opencode, pi, or custom:<name>").requiredOption("--workdir <path>","Worker workdir; must match Manager workdir").option("--model <model>","Worker model id").option("--message <text>","Worker prompt").option("--message-file <path>","Read worker prompt from file").option("--json","Print JSON").action(async e=>{const n=await t("/sessions/start",{agentType:e.agent,workDir:e.workdir,modelId:e.model,message:g(e)});e.json?m(n):console.log(n.session?.sessionId??"ok")}),s.command("send").description("Queue a message for a managed worker; runs immediately if idle").requiredOption("--session-id <id>","Worker session id").option("--message <text>","Message text").option("--message-file <path>","Read message from file").option("--direct","Bypass queue and send immediately").action(async e=>{await t("/sessions/send",{sessionId:e.sessionId,message:g(e),enqueue:!e.direct}),console.log("ok")});const a=s.command("queue").description("Inspect and edit pending worker messages");a.command("list").description("List pending messages for a managed worker").requiredOption("--session-id <id>","Worker session id").option("--json","Print JSON").action(async e=>{const n=await t("/sessions/queue",{sessionId:e.sessionId});if(e.json)m(n);else{const c=n.queue?.pending??[];for(const i of c)console.log(`${i.id} ${i.text.replace(/\s+/g," ").slice(0,120)}`)}}),a.command("edit").description("Edit a pending worker message").requiredOption("--session-id <id>","Worker session id").requiredOption("--message-id <id>","Queued message id").option("--message <text>","Replacement message text").option("--message-file <path>","Read replacement message from file").action(async e=>{await t("/sessions/queue/edit",{sessionId:e.sessionId,queueMessageId:e.messageId,message:g(e)}),console.log("ok")}),a.command("delete").description("Delete a pending worker message").requiredOption("--session-id <id>","Worker session id").requiredOption("--message-id <id>","Queued message id").action(async e=>{await t("/sessions/queue/delete",{sessionId:e.sessionId,queueMessageId:e.messageId}),console.log("ok")});const d=async e=>{await t("/sessions/stop",{sessionId:e.sessionId}),console.log("ok")};s.command("stop").aliases(["terminate","kill"]).description("Stop or terminate a running managed worker").requiredOption("--session-id <id>","Worker session id").action(d),s.command("read").description("Read a managed worker transcript").requiredOption("--session-id <id>","Worker session id").option("--limit <n>","Message limit","200").option("--json","Print JSON").action(async e=>{const n=await t("/sessions/read",{sessionId:e.sessionId,limit:Number(e.limit)});e.json?m(n):m(n.messages??[])}),r.command("memory").description("Manager project memory helpers").command("path").description("Print project memory directory path").action(async()=>{const e=await t("/memory/path",{});console.log(e.path)})}export{I as registerManagerCommand};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type BrowserPairEvent = {
|
|
2
|
+
type: 'pair.browser.created';
|
|
3
|
+
intentId: string;
|
|
4
|
+
url: string;
|
|
5
|
+
expiresAt: string;
|
|
6
|
+
} | {
|
|
7
|
+
type: 'pair.waiting';
|
|
8
|
+
} | {
|
|
9
|
+
type: 'pair.claimed';
|
|
10
|
+
};
|
|
11
|
+
export declare class BrowserPairError extends Error {
|
|
12
|
+
readonly code: string;
|
|
13
|
+
constructor(code: string, message: string);
|
|
14
|
+
}
|
|
15
|
+
export declare function runBrowserPairFlow(input: {
|
|
16
|
+
serverUrl: string;
|
|
17
|
+
machineName: string;
|
|
18
|
+
machineOs: string;
|
|
19
|
+
agentList: string[];
|
|
20
|
+
emit?: (event: BrowserPairEvent) => void;
|
|
21
|
+
openUrl?: (url: string) => Promise<boolean>;
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
pollIntervalMs?: number;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
machineId: string;
|
|
26
|
+
machineToken: string;
|
|
27
|
+
machineName: string;
|
|
28
|
+
publicLoginUrl: string;
|
|
29
|
+
}>;
|
|
30
|
+
export declare function resolvePairMode(input: {
|
|
31
|
+
browser?: boolean;
|
|
32
|
+
token?: boolean;
|
|
33
|
+
json?: boolean;
|
|
34
|
+
stdinIsTty?: boolean;
|
|
35
|
+
stdoutIsTty?: boolean;
|
|
36
|
+
}): 'browser' | 'token' | 'prompt';
|
|
37
|
+
export declare function parsePairModeChoice(value: string): 'browser' | 'token';
|
|
38
|
+
export declare function openExternalUrl(url: string): Promise<boolean>;
|
|
39
|
+
export declare function browserOpenCommand(platform: NodeJS.Platform, url: string): {
|
|
40
|
+
command: string;
|
|
41
|
+
args: string[];
|
|
42
|
+
};
|
|
43
|
+
export declare function normalizePairAuthorizationUrl(value: string, serverUrl: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import I from"node:crypto";import{spawn as u}from"node:child_process";import{HttpDeviceAuthorizationClient as f}from"../room/device-authorization-client.js";import{hashActionPayload as A,hashPendingDeviceSecret as g}from"../room/pending-authorized-actions.js";const p=3e3;class n extends Error{code;constructor(r,t){super(t),this.code=r,this.name="BrowserPairError"}}async function E(e){const r=new f(e.serverUrl),t=I.randomBytes(32).toString("base64url"),a={action:"pair_machine",agentList:[...e.agentList].sort(),machineName:e.machineName,machineOs:e.machineOs},o=A(a),i=await r.create({deviceSecretHash:g(t),machineName:e.machineName,machineOs:e.machineOs,agentList:e.agentList,actionType:"machine.pair",actionSummary:"Pair this machine with your Shennian account",actionPayloadHash:o,returnTo:"/spaces"}),d=_(i.publicLoginUrl,e.serverUrl);e.emit?.({type:"pair.browser.created",intentId:i.loginIntentId,url:d,expiresAt:i.expiresAt}),await(e.openUrl??P)(d).catch(()=>!1);const l=new Date(i.expiresAt).getTime(),h=e.pollIntervalMs??p;let m=!1;for(;Date.now()<l;){if(e.signal?.aborted)throw await r.cancel({loginIntentId:i.loginIntentId,deviceSecret:t}).catch(()=>{}),new n("PAIR_CANCELLED","Pairing was cancelled");let s;try{s=await r.getStatus({loginIntentId:i.loginIntentId,deviceSecret:t})}catch{await w(h,e.signal);continue}if(s.actionPayloadHash!==o)throw new n("PAIR_PAYLOAD_MISMATCH","Authorization request changed unexpectedly");if(s.status==="denied")throw new n("PAIR_DENIED","Pairing request was denied");if(s.status==="expired")throw new n("PAIR_EXPIRED","Pairing request expired");if(s.status==="claimed")throw new n("PAIR_ALREADY_CLAIMED","Pairing credentials were already claimed");if(s.status==="approved"){const c=await r.claim({loginIntentId:i.loginIntentId,deviceSecret:t});if(c.actionPayloadHash!==o||!c.machineId||!c.machineToken)throw new n("PAIR_INVALID_CLAIM","Authorization did not return machine credentials");return e.emit?.({type:"pair.claimed"}),{machineId:c.machineId,machineToken:c.machineToken,machineName:e.machineName,publicLoginUrl:d}}m||(m=!0,e.emit?.({type:"pair.waiting"})),await w(h,e.signal)}throw new n("PAIR_TIMEOUT","Timed out waiting for browser authorization")}function N(e){if(e.browser&&e.token)throw new n("PAIR_MODE_CONFLICT","Choose either --browser or --token, not both");return e.browser?"browser":e.token||e.json||!e.stdinIsTty||!e.stdoutIsTty?"token":"prompt"}function O(e){return e.trim()==="2"?"token":"browser"}async function P(e){if(process.env.SSH_CONNECTION||process.env.SSH_TTY)return!1;const{command:r,args:t}=L(process.platform,e);return new Promise(a=>{const o=u(r,t,{detached:!0,stdio:"ignore",windowsHide:!0});o.once("error",()=>a(!1)),o.once("spawn",()=>{o.unref(),a(!0)})})}function L(e,r){return e==="darwin"?{command:"open",args:[r]}:e==="win32"?{command:"explorer.exe",args:[r]}:{command:"xdg-open",args:[r]}}function _(e,r){let t,a;try{t=new URL(e),a=new URL(r)}catch{throw new n("PAIR_INVALID_AUTHORIZATION_URL","Server returned an invalid authorization URL")}if(!["http:","https:"].includes(t.protocol)||t.hostname!==a.hostname||t.username||t.password||t.search||t.hash||!/^\/authorize\/[A-Za-z0-9_-]{8,128}$/.test(t.pathname))throw new n("PAIR_INVALID_AUTHORIZATION_URL","Server returned an unsafe authorization URL");return t.toString()}function w(e,r){return new Promise(t=>{if(r?.aborted)return t();const a=setTimeout(t,e);r?.addEventListener("abort",()=>{clearTimeout(a),t()},{once:!0})})}export{n as BrowserPairError,L as browserOpenCommand,_ as normalizePairAuthorizationUrl,P as openExternalUrl,O as parsePairModeChoice,N as resolvePairMode,E as runBrowserPairFlow};
|
|
@@ -4,6 +4,8 @@ export declare function runPairFlow(opts: {
|
|
|
4
4
|
machineName: string;
|
|
5
5
|
force?: boolean;
|
|
6
6
|
json?: boolean;
|
|
7
|
+
mode?: 'browser' | 'token';
|
|
8
|
+
openUrl?: (url: string) => Promise<boolean>;
|
|
7
9
|
}): Promise<void>;
|
|
8
10
|
export declare function registerDesktopMachine(opts: {
|
|
9
11
|
serverUrl: string;
|