shennian 0.4.17 → 0.4.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/publish-build-manifest.json +14 -14
- package/dist/src/agents/claude.js +4 -4
- package/dist/src/agents/cursor.d.ts +1 -0
- package/dist/src/agents/cursor.js +1 -1
- package/dist/src/daemon-ipc/client.js +3 -3
- package/dist/src/daemon-ipc/protocol.d.ts +1 -0
- package/dist/src/daemon-ipc/protocol.js +1 -1
- package/dist/src/daemon-ipc/secret.js +3 -3
- package/dist/src/daemon-ipc/server.d.ts +6 -0
- package/dist/src/daemon-ipc/server.js +4 -3
- package/dist/src/log-redaction.js +1 -1
- package/package.json +1 -1
|
@@ -101,8 +101,8 @@
|
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
"file": "src/agents/claude.js",
|
|
104
|
-
"beforeBytes":
|
|
105
|
-
"afterBytes":
|
|
104
|
+
"beforeBytes": 17218,
|
|
105
|
+
"afterBytes": 8552
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
108
|
"file": "src/agents/codex-managed-permissions.js",
|
|
@@ -141,8 +141,8 @@
|
|
|
141
141
|
},
|
|
142
142
|
{
|
|
143
143
|
"file": "src/agents/cursor.js",
|
|
144
|
-
"beforeBytes":
|
|
145
|
-
"afterBytes":
|
|
144
|
+
"beforeBytes": 12436,
|
|
145
|
+
"afterBytes": 5960
|
|
146
146
|
},
|
|
147
147
|
{
|
|
148
148
|
"file": "src/agents/custom-managed-runtime.js",
|
|
@@ -371,8 +371,8 @@
|
|
|
371
371
|
},
|
|
372
372
|
{
|
|
373
373
|
"file": "src/daemon-ipc/client.js",
|
|
374
|
-
"beforeBytes":
|
|
375
|
-
"afterBytes":
|
|
374
|
+
"beforeBytes": 2786,
|
|
375
|
+
"afterBytes": 1428
|
|
376
376
|
},
|
|
377
377
|
{
|
|
378
378
|
"file": "src/daemon-ipc/control.js",
|
|
@@ -391,18 +391,18 @@
|
|
|
391
391
|
},
|
|
392
392
|
{
|
|
393
393
|
"file": "src/daemon-ipc/protocol.js",
|
|
394
|
-
"beforeBytes":
|
|
395
|
-
"afterBytes":
|
|
394
|
+
"beforeBytes": 484,
|
|
395
|
+
"afterBytes": 245
|
|
396
396
|
},
|
|
397
397
|
{
|
|
398
398
|
"file": "src/daemon-ipc/secret.js",
|
|
399
|
-
"beforeBytes":
|
|
400
|
-
"afterBytes":
|
|
399
|
+
"beforeBytes": 3455,
|
|
400
|
+
"afterBytes": 1873
|
|
401
401
|
},
|
|
402
402
|
{
|
|
403
403
|
"file": "src/daemon-ipc/server.js",
|
|
404
|
-
"beforeBytes":
|
|
405
|
-
"afterBytes":
|
|
404
|
+
"beforeBytes": 7345,
|
|
405
|
+
"afterBytes": 3824
|
|
406
406
|
},
|
|
407
407
|
{
|
|
408
408
|
"file": "src/daemon-log.js",
|
|
@@ -441,8 +441,8 @@
|
|
|
441
441
|
},
|
|
442
442
|
{
|
|
443
443
|
"file": "src/log-redaction.js",
|
|
444
|
-
"beforeBytes":
|
|
445
|
-
"afterBytes":
|
|
444
|
+
"beforeBytes": 5266,
|
|
445
|
+
"afterBytes": 2866
|
|
446
446
|
},
|
|
447
447
|
{
|
|
448
448
|
"file": "src/log-reporter.js",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
${t.stderr??""}`,a=/(?:^|\s)--effort(?:\s|,|<)/.test(s);return h.set(e,a),a}catch{return h.set(e,!1),!1}}class N extends
|
|
1
|
+
import m from"node:fs";import o from"node:path";import{createInterface as g}from"node:readline";import{randomUUID as p}from"node:crypto";import{AgentAdapter as y,registerAgent as S}from"./adapter.js";import{resolveBuiltinCommand as c,spawnAgentCommand as E,spawnResolvedCommandSync as x}from"./command-spec.js";import{buildAgentProcessEnv as v,buildManagedAgentProcessEnv as P}from"../agent-env.js";import{buildPlatformInstructions as f}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as I}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as C}from"../security/managed-agent-runtime.js";import{resolveManagedRoomIpcPaths as k}from"../daemon-ipc/paths.js";import{CLAUDE_MANAGED_RUNTIME_SECURITY as w,compileClaudeManagedPermissions as A}from"./claude-managed-permissions.js";C("claude",w);function _(n){return n?.trim()||"default"}const R=new Set(["low","medium","high","xhigh","max"]),h=new Map;function T(n){const e=n?.trim();if(e){if(R.has(e))return e;throw new Error(`Unsupported Claude reasoning effort "${e}". Supported values: low, medium, high, xhigh, max.`)}}function Q(){h.clear()}function M(n){const e=n.trim();return e?!e.includes("claude.ai connectors are disabled because"):!1}function O(){const n=c("claude");if(!n)return!1;const e=`${n.kind}:${n.path}:${n.command}:${n.args.join("\0")}`;if(h.has(e))return h.get(e)??!1;try{const t=x(n,["--help"],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3e3,env:process.env}),s=`${t.stdout??""}
|
|
2
|
+
${t.stderr??""}`,a=/(?:^|\s)--effort(?:\s|,|<)/.test(s);return h.set(e,a),a}catch{return h.set(e,!1),!1}}class N extends y{options;type="claude";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;agentSessionId=null;sessionId=null;workDir=null;seq=0;runId="";hasEmittedText=!1;terminalState="open";persistNativeSession=!0;managedAgentPolicy=null;constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir)}async start(e,t,s,a){this.sessionId=e,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,this.seq=0,this.persistNativeSession=a?.persistNativeSession!==!1,s&&(this.agentSessionId=s)}async send(e,t,s,a,l,r){if(r?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=p(),this.resetRunState();const i=["-p",e,"--output-format","stream-json","--verbose",...this.buildManagedPermissionConfig()?.args??[]];this.persistNativeSession||i.push("--no-session-persistence");const u=this.options.systemPrompt??f(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,l);u&&i.push("--append-system-prompt",u),this.options.hidden&&i.push("--name","Shennian Manager Substrate"),!this.managedAgentPolicy&&process.getuid?.()!==0&&i.push("--dangerously-skip-permissions"),i.push("--model",_(t));const d=T(s);d&&O()&&i.push("--effort",d),this.agentSessionId&&i.push("--resume",this.agentSessionId),this.spawnAndParse(i)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=p(),this.resetRunState();const t=["--resume",e,"--output-format","stream-json","--verbose",...this.buildManagedPermissionConfig()?.args??[]],s=this.options.systemPrompt??f(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0);s&&t.push("--append-system-prompt",s),this.options.hidden&&t.push("--name","Shennian Manager Substrate"),!this.managedAgentPolicy&&process.getuid?.()!==0&&t.push("--dangerously-skip-permissions"),this.spawnAndParse(t)}async stop(){await this.killProcess()}spawnAndParse(e){const t=c("claude");if(!t){this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?'));return}const s=E(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=s,g({input:s.stdout}).on("line",r=>{if(r.trim())try{const i=JSON.parse(r);this.handleStreamEvent(i)}catch{}});let l="";s.stderr?.on("data",r=>{const i=r.toString();if(l+=i,this.terminalState==="open")for(const u of i.split(`
|
|
3
3
|
`)){const d=u.trim();M(d)&&this.emitEvent({state:"delta",text:d+`
|
|
4
|
-
`})}}),s.on("close",r=>{this.process===s&&(this.process=null,this.handleProcessClose(r,l))}),s.on("error",r=>{this.process===s&&(this.process=null,r.code==="ENOENT"?this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?')):this.emit("error",r))})}buildManagedPermissionConfig(){const e=this.managedAgentPolicy;if(!e)return null;const t=D();return A(I(e),e.adapterPolicy.workDir,{internalReadPaths:t.readPaths,internalUnixSockets:t.unixSockets,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}buildProcessEnv(){return this.managedAgentPolicy?
|
|
4
|
+
`})}}),s.on("close",r=>{this.process===s&&(this.process=null,this.handleProcessClose(r,l))}),s.on("error",r=>{this.process===s&&(this.process=null,r.code==="ENOENT"?this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?')):this.emit("error",r))})}buildManagedPermissionConfig(){const e=this.managedAgentPolicy;if(!e)return null;const t=D();return A(I(e),e.adapterPolicy.workDir,{internalReadPaths:t.readPaths,internalUnixSockets:t.unixSockets,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}buildProcessEnv(){return this.managedAgentPolicy?P({agentType:"claude",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}}):v(this.extraEnv)}handleStreamEvent(e){if(e.type==="system"&&e.subtype==="init"&&e.session_id){this.agentSessionId=e.session_id,this.emitEvent({state:"start",agentSessionId:this.agentSessionId});return}if(e.type==="system"&&e.subtype==="api_retry"&&e.error==="authentication_failed"){this.emitErrorIfOpen({state:"error",message:'Claude authentication failed. Run "claude auth login" and retry.'});return}if(e.type==="assistant"){if(e.message?.content){for(const t of e.message.content)if(t.type==="text"&&t.text){const s=this.hasEmittedText?`
|
|
5
5
|
|
|
6
6
|
`:"";this.emitEvent({state:"delta",text:s+t.text}),this.hasEmittedText=!0}else t.type==="thinking"&&t.thinking?this.emitEvent({state:"delta",text:t.thinking,thinking:!0}):t.type==="tool_use"&&this.emitEvent({state:"tool-call",name:t.name,args:t.input});return}if(e.subtype==="text"&&e.text){const t=this.hasEmittedText?`
|
|
7
7
|
|
|
8
|
-
`:"";this.emitEvent({state:"delta",text:t+e.text}),this.hasEmittedText=!0}else e.subtype==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.subtype==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});return}if(e.type==="result")if(e.subtype==="tool_result"){const t=typeof e.content=="string"?e.content:JSON.stringify(e.content);this.emitEvent({state:"tool-result",name:e.name,result:t})}else if(e.subtype==="success"){e.session_id&&(this.agentSessionId=e.session_id);const t=e.usage??e.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:t?{inputTokens:t.input_tokens,outputTokens:t.output_tokens}:void 0})}else e.subtype==="error"&&this.emitErrorIfOpen({state:"error",message:e.error??e.result??"unknown error"})}handleProcessClose(e,t){if(e!==0&&e!==null){const s=t.trim()||`claude exited with code ${e}`;this.emitErrorIfOpen({state:"error",message:s});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="final",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.emitEvent(e))}resetRunState(){this.seq=0,this.hasEmittedText=!1,this.terminalState="open"}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}async killProcess(){const e=this.process;e&&(this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}))}}function D(){const n=k(),e=[n.secretFile],t=n.transport==="unix_socket"?[n.endpoint]:[];n.transport==="unix_socket"&&e.push(n.endpoint);const s=
|
|
8
|
+
`:"";this.emitEvent({state:"delta",text:t+e.text}),this.hasEmittedText=!0}else e.subtype==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.subtype==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});return}if(e.type==="result")if(e.subtype==="tool_result"){const t=typeof e.content=="string"?e.content:JSON.stringify(e.content);this.emitEvent({state:"tool-result",name:e.name,result:t})}else if(e.subtype==="success"){e.session_id&&(this.agentSessionId=e.session_id);const t=e.usage??e.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:t?{inputTokens:t.input_tokens,outputTokens:t.output_tokens}:void 0})}else e.subtype==="error"&&this.emitErrorIfOpen({state:"error",message:e.error??e.result??"unknown error"})}handleProcessClose(e,t){if(e!==0&&e!==null){const s=t.trim()||`claude exited with code ${e}`;this.emitErrorIfOpen({state:"error",message:s});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="final",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.emitEvent(e))}resetRunState(){this.seq=0,this.hasEmittedText=!1,this.terminalState="open"}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}async killProcess(){const e=this.process;e&&(this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}))}}function D(){const n=k(),e=[n.secretFile],t=n.transport==="unix_socket"?[n.endpoint]:[];n.transport==="unix_socket"&&e.push(n.endpoint);const s=c("pi");return s?.path&&e.push(...F(s.path)),{readPaths:[...new Set(e)].sort(),unixSockets:[...new Set(t)].sort()}}function F(n){const e=o.normalize(n.trim());if(!e||!o.isAbsolute(e))return[];const t=[e];try{const s=m.realpathSync(e);t.push(s,o.dirname(s),o.dirname(o.dirname(s)));let a=o.dirname(s);for(let l=0;l<8;l+=1){const r=o.join(a,"package.json");try{if(JSON.parse(m.readFileSync(r,"utf8")).name==="shennian"){t.push(a);break}}catch{}const i=o.dirname(a);if(i===a)break;a=i}}catch{}return[...new Set(t)].sort()}S("claude",()=>new N);export{N as ClaudeAdapter,_ as normalizeClaudeModelId,T as normalizeClaudeReasoningEffort,Q as resetClaudeCapabilityCacheForTests,D as resolveClaudeManagedInternalAccess,F as resolveClaudeShennianCliReadPaths,M as shouldForwardClaudeStderrLine,O as supportsClaudeReasoningEffort};
|
|
@@ -30,6 +30,7 @@ export declare class CursorAdapter extends AgentAdapter {
|
|
|
30
30
|
send(text: string, modelId?: string, _reasoningEffort?: string, _attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null, context?: AgentSendContext): Promise<void>;
|
|
31
31
|
resume(agentSessionId: string): Promise<void>;
|
|
32
32
|
stop(): Promise<void>;
|
|
33
|
+
private buildSendArgs;
|
|
33
34
|
private spawnAndParse;
|
|
34
35
|
private prepareManagedLaunch;
|
|
35
36
|
private disposeManagedConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createInterface as d}from"node:readline";import{randomUUID as l}from"node:crypto";import{AgentAdapter as c,registerAgent as h}from"./adapter.js";import{resolveBuiltinCommand as u,spawnResolvedCommand as m}from"./command-spec.js";import{buildAgentProcessEnv as g,buildManagedAgentProcessEnv as f}from"../agent-env.js";import{buildInlineChannelPreamble as p}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as v}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as E}from"../security/managed-agent-runtime.js";import{compileCursorManagedPermissions as w,createCursorManagedConfigDirectory as y,CURSOR_MANAGED_RUNTIME_SECURITY as C,disposeCursorManagedConfigDirectory as k}from"./cursor-managed-permissions.js";E("cursor",C);class x extends c{type="cursor";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;chatId=null;workDir=null;seq=0;runId="";emittedText="";externalChannel=null;shennianSessionId=null;extraEnv={};managedAgentPolicy=null;managedConfigDir=null;configure(t){this.shennianSessionId=t.sessionId??null,this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{},"managedAgentPolicy"in t&&(this.managedAgentPolicy=t.managedAgentPolicy??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir)}async start(t,s,e){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??s,this.seq=0,e&&(this.chatId=e)}async send(t,s,e,n,o,r){if(r?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=l(),this.resetRunState();const
|
|
1
|
+
import{createInterface as d}from"node:readline";import{randomUUID as l}from"node:crypto";import{AgentAdapter as c,registerAgent as h}from"./adapter.js";import{resolveBuiltinCommand as u,spawnResolvedCommand as m}from"./command-spec.js";import{buildAgentProcessEnv as g,buildManagedAgentProcessEnv as f}from"../agent-env.js";import{buildInlineChannelPreamble as p}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as v}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as E}from"../security/managed-agent-runtime.js";import{compileCursorManagedPermissions as w,createCursorManagedConfigDirectory as y,CURSOR_MANAGED_RUNTIME_SECURITY as C,disposeCursorManagedConfigDirectory as k}from"./cursor-managed-permissions.js";E("cursor",C);class x extends c{type="cursor";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;chatId=null;workDir=null;seq=0;runId="";emittedText="";externalChannel=null;shennianSessionId=null;extraEnv={};managedAgentPolicy=null;managedConfigDir=null;configure(t){this.shennianSessionId=t.sessionId??null,this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{},"managedAgentPolicy"in t&&(this.managedAgentPolicy=t.managedAgentPolicy??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir)}async start(t,s,e){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??s,this.seq=0,e&&(this.chatId=e)}async send(t,s,e,n,o,r){if(r?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=l(),this.resetRunState();const i=`${p(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,o)}${t}`;await this.spawnAndParse(this.buildSendArgs(i,s))}async resume(t){await this.killProcess(),this.chatId=t,this.runId=l(),this.resetRunState(),await this.spawnAndParse(["--resume",t,"--output-format","stream-json","--stream-partial-output"])}async stop(){await this.killProcess()}buildSendArgs(t,s){const e=["-p",t,"--output-format","stream-json","--stream-partial-output"];return s&&e.push("--model",s),this.chatId&&e.push("--resume",this.chatId),e}async spawnAndParse(t){const s=u("cursor");if(!s){this.emit("error",new Error('Cursor Agent CLI not found. Expected "agent" or "cursor agent".'));return}const e=await this.prepareManagedLaunch();let n;try{n=m(s,[...t,...e.args],{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:e.env})}catch(i){throw await this.disposeManagedConfig(e.configDir),i}this.process=n,this.managedConfigDir=e.configDir,d({input:n.stdout}).on("line",i=>{if(i.trim())try{const a=JSON.parse(i);this.handleStreamEvent(a)}catch{this.emitEvent({state:"delta",text:i})}});let r="";n.stderr?.on("data",i=>{r+=i.toString()}),n.on("close",i=>{if(this.process===n&&(this.process=null,this.disposeManagedConfig(e.configDir),i!==0&&i!==null)){const a=r.trim()||`cursor agent exited with code ${i}`;this.emitEvent({state:"error",message:a})}}),n.on("error",i=>{this.process===n&&(this.process=null,this.disposeManagedConfig(e.configDir),i.code==="ENOENT"?this.emit("error",new Error('Command "cursor" not found. Is Cursor CLI installed?')):this.emit("error",i))})}async prepareManagedLaunch(){const t=this.managedAgentPolicy;if(!t)return{args:["--trust"],env:g(this.extraEnv),configDir:null};const s=w(v(t),t.adapterPolicy.workDir),e=await y(s),n=f({agentType:"cursor",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}});return n.CURSOR_CONFIG_DIR=e,{args:s.args,env:n,configDir:e}}async disposeManagedConfig(t){t&&(this.managedConfigDir===t&&(this.managedConfigDir=null),await k(t).catch(()=>{}))}handleStreamEvent(t){switch(t.session_id&&!this.chatId&&(this.chatId=t.session_id),t.chat_id&&!this.chatId&&(this.chatId=t.chat_id),t.type??t.event){case"system":break;case"assistant":{if(t.message?.content){if(!this.isLiveAssistantDelta(t))break;for(const e of t.message.content)e.type==="text"&&e.text?this.emitTextDelta(e.text):e.type==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.type==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});break}(t.delta??t.text)&&this.emitEvent({state:"delta",text:t.delta??t.text});break}case"user":break;case"result":{if(t.subtype==="success"||!t.is_error){this.emitFinalResultDelta(t.result);const e=t.usage;this.emitEvent({state:"final",agentSessionId:this.chatId??void 0,usage:e?{inputTokens:e.inputTokens??e.input_tokens??0,outputTokens:e.outputTokens??e.output_tokens??0}:void 0})}else this.emitEvent({state:"error",message:t.result??t.error??"unknown error"});break}case"error":{this.emitEvent({state:"error",message:t.error??"unknown error"});break}case"text":case"delta":case"content":{const e=t.delta??t.text;e&&this.emitEvent({state:"delta",text:e});break}case"done":{this.emitEvent({state:"final",agentSessionId:this.chatId??void 0});break}default:t.done?this.emitEvent({state:"final",agentSessionId:this.chatId??void 0}):(t.delta??t.text)&&this.emitEvent({state:"delta",text:t.delta??t.text})}}emitEvent(t){const s={...t,runId:this.runId,seq:this.seq++};this.emit("agentEvent",s)}async killProcess(){const t=this.process;if(!t){await this.disposeManagedConfig(this.managedConfigDir);return}this.process=null,t.kill("SIGTERM"),await new Promise(s=>{t.on("close",s),setTimeout(()=>{t.kill("SIGKILL"),s()},3e3)}),await this.disposeManagedConfig(this.managedConfigDir)}resetRunState(){this.seq=0,this.emittedText=""}isLiveAssistantDelta(t){return t.timestamp_ms!=null&&!t.model_call_id}emitTextDelta(t){t&&(this.emittedText+=t,this.emitEvent({state:"delta",text:t}))}emitFinalResultDelta(t){if(!t)return;if(!this.emittedText){this.emitTextDelta(t);return}if(!t.startsWith(this.emittedText))return;const s=t.slice(this.emittedText.length);s&&this.emitTextDelta(s)}}h("cursor",()=>new x);export{x as CursorAdapter};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
`;if(Buffer.byteLength(d,"utf8")>
|
|
3
|
-
`);p<0||a(()=>{try{
|
|
1
|
+
import l from"node:crypto";import I from"node:net";import{resolveDaemonIpcPaths as w}from"./paths.js";import{DAEMON_IPC_MAX_REQUEST_BYTES as D,DAEMON_IPC_MAX_RESPONSE_BYTES as E,DAEMON_IPC_VERSION as f,DaemonIpcError as o}from"./protocol.js";import{readDaemonIpcSecret as S}from"./secret.js";async function v(t){const m=t.paths??w(),u=S(m.secretFile),c=l.randomUUID(),d=`${JSON.stringify({version:f,requestId:c,auth:u,method:t.method,params:t.params})}
|
|
2
|
+
`;if(Buffer.byteLength(d,"utf8")>D)throw new o("request_too_large","Daemon IPC request is too large.");const n=await new Promise((_,r)=>{const e=I.createConnection(m.endpoint);let s="";const h=setTimeout(()=>{e.destroy(),r(new o("ipc_timeout","Shennian daemon did not respond."))},t.timeoutMs??5e3),a=i=>{clearTimeout(h),e.destroy(),i()};e.setEncoding("utf8"),e.once("connect",()=>e.write(d)),e.on("data",i=>{if(s+=i,Buffer.byteLength(s,"utf8")>E){a(()=>r(new o("response_too_large","Daemon IPC response is too large.")));return}const p=s.indexOf(`
|
|
3
|
+
`);p<0||a(()=>{try{_(JSON.parse(s.slice(0,p)))}catch{r(new o("invalid_response","Daemon IPC response is invalid."))}})}),e.once("error",()=>a(()=>r(new o("daemon_unavailable","Shennian daemon is not running."))))});if(n.requestId!==c||n.version!==f)throw new o("response_mismatch","Daemon IPC response did not match the request.");if(!n.ok)throw new o(n.error.code,n.error.message);return n.result}export{v as callDaemonIpc};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { JsonValue } from './json.js';
|
|
2
2
|
export declare const DAEMON_IPC_VERSION: 1;
|
|
3
3
|
export declare const DAEMON_IPC_MAX_REQUEST_BYTES: number;
|
|
4
|
+
export declare const DAEMON_IPC_MAX_RESPONSE_BYTES: number;
|
|
4
5
|
export type DaemonIpcRequest = {
|
|
5
6
|
version: typeof DAEMON_IPC_VERSION;
|
|
6
7
|
requestId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const e=1,t=1048576,c=1048576;class s extends Error{code;constructor(o,r){super(r),this.code=o,this.name="DaemonIpcError"}}export{t as DAEMON_IPC_MAX_REQUEST_BYTES,c as DAEMON_IPC_MAX_RESPONSE_BYTES,e as DAEMON_IPC_VERSION,s as DaemonIpcError};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import a from"node:crypto";import o from"node:fs";import{DaemonIpcError as
|
|
2
|
-
`,{encoding:"utf8",mode:384,flag:"wx"})}catch(e){if(!m(e))throw e}return f(t,n)}const
|
|
3
|
-
`,{encoding:"utf8",mode:384,flag:"wx"}),o.chmodSync(
|
|
1
|
+
import a from"node:crypto";import o from"node:fs";import{DaemonIpcError as r}from"./protocol.js";function f(t,n){l(t);try{const e=o.lstatSync(n);if(!e.isFile()||e.isSymbolicLink())throw new r("unsafe_ipc_secret","Daemon IPC secret is not a regular file.");process.platform!=="win32"&&(e.mode&63)!==0&&o.chmodSync(n,384);const s=o.readFileSync(n,"utf8").trim();if(s.length<40||s.length>128)throw new r("invalid_ipc_secret","Daemon IPC secret is invalid.");return s}catch(e){if(!p(e))throw e}const i=a.randomBytes(32).toString("base64url");if(process.platform==="win32"){try{o.writeFileSync(n,`${i}
|
|
2
|
+
`,{encoding:"utf8",mode:384,flag:"wx"})}catch(e){if(!m(e))throw e}return f(t,n)}const c=`${n}.tmp-${process.pid}-${a.randomBytes(6).toString("hex")}`;try{o.writeFileSync(c,`${i}
|
|
3
|
+
`,{encoding:"utf8",mode:384,flag:"wx"}),o.chmodSync(c,384);try{o.linkSync(c,n)}catch(e){if(!m(e))throw e}}finally{try{o.unlinkSync(c)}catch{}}return f(t,n)}function w(t){const n=o.lstatSync(t);if(!n.isFile()||n.isSymbolicLink())throw new r("unsafe_ipc_secret","Daemon IPC secret is not a regular file.");if(process.platform!=="win32"&&(n.mode&63)!==0)throw new r("unsafe_ipc_secret_permissions","Daemon IPC secret permissions are not private.");const i=o.readFileSync(t,"utf8").trim();if(i.length<40||i.length>128)throw new r("invalid_ipc_secret","Daemon IPC secret is invalid.");return i}function l(t){o.mkdirSync(t,{recursive:!0,mode:448});const n=o.lstatSync(t);if(!n.isDirectory()||n.isSymbolicLink())throw new r("unsafe_runtime_directory","Daemon runtime path is not a directory.");process.platform!=="win32"&&o.chmodSync(t,448)}function p(t){return typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT"}function m(t){return typeof t=="object"&&t!==null&&"code"in t&&t.code==="EEXIST"}export{l as ensurePrivateRuntimeDirectory,f as loadOrCreateDaemonIpcSecret,w as readDaemonIpcSecret};
|
|
@@ -12,3 +12,9 @@ export declare function startDaemonIpcServer(options: {
|
|
|
12
12
|
handlers: Record<string, DaemonIpcHandler>;
|
|
13
13
|
paths?: DaemonIpcPaths;
|
|
14
14
|
}): Promise<DaemonIpcServer>;
|
|
15
|
+
export declare function timingSafeSecretEqual(value: unknown, secret: string): boolean;
|
|
16
|
+
export declare function daemonIpcListenOptions(paths: DaemonIpcPaths): string | {
|
|
17
|
+
path: string;
|
|
18
|
+
readableAll: false;
|
|
19
|
+
writableAll: false;
|
|
20
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
`);
|
|
3
|
-
|
|
1
|
+
import y from"node:crypto";import u from"node:fs";import h from"node:net";import{resolveDaemonIpcPaths as S}from"./paths.js";import{DAEMON_IPC_MAX_REQUEST_BYTES as w,DAEMON_IPC_MAX_RESPONSE_BYTES as I,DAEMON_IPC_VERSION as l,DaemonIpcError as f}from"./protocol.js";import{ensurePrivateRuntimeDirectory as g,loadOrCreateDaemonIpcSecret as P}from"./secret.js";function k(n,e=process.platform){const r=e==="darwin"?104:e==="linux"?107:null;if(r!==null&&Buffer.byteLength(n,"utf8")>r)throw new f("ipc_endpoint_too_long",`Daemon IPC endpoint exceeds the ${e} Unix socket path limit.`)}async function R(n){const e=n.paths??S();g(e.runtimeDirectory);const r=P(e.runtimeDirectory,e.secretFile);e.transport==="unix_socket"&&(k(e.endpoint),await v(e.endpoint));const o=h.createServer(t=>{t.setEncoding("utf8");let s="",c=!1;t.on("data",d=>{if(c)return;if(s+=d,Buffer.byteLength(s,"utf8")>w){c=!0,p(t,a("unknown","request_too_large","Daemon IPC request is too large."));return}const m=s.indexOf(`
|
|
2
|
+
`);m<0||(c=!0,D(s.slice(0,m),r,n.handlers).then(_=>p(t,_)).catch(()=>p(t,a("unknown","internal_error","Daemon IPC request failed."))))}),t.on("error",()=>{})});await new Promise((t,s)=>{const c=d=>s(d);o.once("error",c),o.listen(x(e),()=>{o.off("error",c),t()})});let i=null;if(e.transport==="unix_socket")try{u.chmodSync(e.endpoint,384);const t=u.lstatSync(e.endpoint);if(!t.isSocket()||t.isSymbolicLink())throw new f("unsafe_ipc_endpoint","Daemon IPC endpoint was not created as a Unix socket.");i={dev:t.dev,ino:t.ino}}catch(t){throw await new Promise(s=>o.close(()=>s())),t}return{paths:e,close:async()=>{if(await new Promise(t=>o.close(()=>t())),e.transport==="unix_socket"&&i)try{const t=u.lstatSync(e.endpoint);t.isSocket()&&t.dev===i.dev&&t.ino===i.ino&&u.unlinkSync(e.endpoint)}catch{}}}}async function v(n){try{const e=u.lstatSync(n);if(!e.isSocket()||e.isSymbolicLink())throw new f("unsafe_ipc_endpoint","Refusing to replace a non-socket IPC endpoint.");if(await C(n))throw new f("daemon_ipc_in_use","Another Shennian daemon IPC server is already running.");u.unlinkSync(n)}catch(e){if(q(e))return;throw e}}function C(n){return new Promise(e=>{const r=h.createConnection(n),o=i=>{r.destroy(),e(i)};r.once("connect",()=>o(!0)),r.once("error",()=>o(!1)),r.setTimeout(300,()=>o(!1))})}async function D(n,e,r){let o;try{o=JSON.parse(n)}catch{return a("unknown","invalid_json","Daemon IPC request must be JSON.")}const i=typeof o.requestId=="string"?o.requestId.slice(0,128):"unknown";if(o.version!==l)return a(i,"unsupported_version","Unsupported daemon IPC version.");if(!E(o.auth,e))return a(i,"unauthorized","Daemon IPC authentication failed.");if(typeof o.method!="string"||!/^[a-z][a-z0-9_.-]{0,127}$/.test(o.method))return a(i,"invalid_method","Invalid daemon IPC method.");const t=r[o.method];if(!t)return a(i,"method_not_found","Daemon IPC method is not supported.");try{const s=await t(o.params,{requestId:i});return{version:l,requestId:i,ok:!0,result:s}}catch(s){return s instanceof f?a(i,s.code,s.message):a(i,"method_failed","Daemon IPC method failed.")}}function E(n,e){if(typeof n!="string")return!1;const r=Buffer.from(n),o=Buffer.from(e),i=Buffer.alloc(o.length);return r.copy(i,0,0,o.length),y.timingSafeEqual(i,o)&&r.length===o.length}function a(n,e,r){return{version:l,requestId:n,ok:!1,error:{code:e,message:r}}}function p(n,e){let r=JSON.stringify(e);Buffer.byteLength(`${r}
|
|
3
|
+
`,"utf8")>I&&(r=JSON.stringify(a(e.requestId,"response_too_large","Daemon IPC response is too large."))),n.end(`${r}
|
|
4
|
+
`)}function x(n){return n.transport==="unix_socket"?n.endpoint:{path:n.endpoint,readableAll:!1,writableAll:!1}}function q(n){return typeof n=="object"&&n!==null&&"code"in n&&n.code==="ENOENT"}export{k as assertUnixSocketEndpointLength,x as daemonIpcListenOptions,R as startDaemonIpcServer,E as timingSafeSecretEqual};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const c="[redacted]";function f(t,e=[]){let o=t;for(const i of e)i.length>=6&&(o=o.split(i).join(c));return o.replace(/https?:\/\/[^\s"'<>]+/gi,i=>i.replace(/[?#].*$/,"")).replace(/\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+(\/[^\s?#]*)(?:[?#][^\s]*)/gi,"$1 $2").replace(/\b(Authorization\s*[:=]\s*)(?:(?:Bearer|Basic)\s+)?[^\s,;}"']+/gi,`$1${c}`).replace(/\b((?:Cookie|Set-Cookie)\s*[:=]\s*)[^\r\n]+/gi,`$1${c}`).replace(/Bearer\s+[^\s,"'}]+/gi,`Bearer ${c}`).replace(/([?&](?:token|access|invite|code|signature|ticket|randstr|csrf)=)[^&#\s]+/gi,`$1${c}`).replace(/(["']?(?:token|tokenPreview|credentialPreview|secretPreview|accessToken|refreshToken|machineToken|pairToken|pushToken|shareToken|idToken|apiKey|clientSecret|deviceSecret|deviceSecretHash|browserState|inviteToken|inviteCode|shareCode|signature|code|smsCode|verificationCode|oneTimeCode|otp|ticket|randstr|csrf|csrfToken|xsrfToken|password|credentials?)["']?\s*[:=]\s*)(["']?)[^"'\s,;}]+\2/gi,`$1$2${c}$2`).replace(/\bsk-[A-Za-z0-9_-]{8,}\b/g,c).replace(/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,c).replace(/[A-Za-z0-9_-]{80,}/g,c)}function g(t){const e=t.replace(/[^a-z0-9]/gi,"").toLowerCase();return e==="apikey"||e==="apikeys"||e==="credentials"||e==="tokenpreview"||e==="credentialpreview"||e==="secretpreview"||e==="authorization"||e==="cookie"||e==="code"||e==="smscode"||e==="verificationcode"||e==="onetimecode"||e==="otp"||e==="invitecode"||e==="sharecode"||e==="ticket"||e==="randstr"||e==="csrf"||e==="csrftoken"||e==="xsrftoken"||e==="devicesecrethash"||e.endsWith("token")||e.endsWith("tokens")||e.endsWith("secret")||e.endsWith("secrets")||e.endsWith("password")||e.endsWith("signature")}function d(t,e=[],o="",i=0,s=new WeakSet){if(o&&g(o))return c;if(typeof t=="string")return f(t,e);if(t instanceof Error){const r=new Error(f(t.message,e));return r.name=t.name,r.stack=t.stack?f(t.stack,e):void 0,r}if(t&&typeof t=="object"){if(i>=10)return"[max-depth]";if(s.has(t))return"[circular]";if(s.add(t),Array.isArray(t)){const n=t.map(a=>d(a,e,"",i+1,s));return s.delete(t),n}const r=Object.fromEntries(Object.entries(t).map(([n,a])=>[n,d(a,e,n,i+1,s)]));return s.delete(t),r}return t}function h(t,e){const o=new Set,i=/(token|secret|password|api[_-]?key|authorization|cookie|signature)/i;for(const[r,n]of Object.entries(t))n&&n.length>=6&&i.test(r)&&o.add(n);const s=(r,n="",a=0)=>{if(!(a>8||r==null)){if(typeof r=="string"){r.length>=6&&i.test(n)&&o.add(r);return}if(typeof r=="object")for(const[k,l]of Object.entries(r))s(l,k,a+1)}};return s(e),[...o]}let p=!1;function T(t){if(!p){p=!0;for(const e of["log","info","warn","error"]){const o=console[e].bind(console);console[e]=(...i)=>{o(...i.map(s=>d(s,t)))}}}}export{h as collectKnownLogSecrets,T as installCliLogRedaction,f as redactCliLogText,d as sanitizeCliLogValue};
|
|
1
|
+
const c="[redacted]";function f(t,e=[]){let o=t;for(const i of e)i.length>=6&&(o=o.split(i).join(c));return o.replace(/https?:\/\/[^\s"'<>]+/gi,i=>i.replace(/[?#].*$/,"")).replace(/\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+(\/[^\s?#]*)(?:[?#][^\s]*)/gi,"$1 $2").replace(/\b(Authorization\s*[:=]\s*)(?:(?:Bearer|Basic)\s+)?[^\s,;}"']+/gi,`$1${c}`).replace(/\b((?:Cookie|Set-Cookie)\s*[:=]\s*)[^\r\n]+/gi,`$1${c}`).replace(/Bearer\s+[^\s,"'}]+/gi,`Bearer ${c}`).replace(/([?&](?:token|access|invite|code|signature|ticket|randstr|csrf)=)[^&#\s]+/gi,`$1${c}`).replace(/(["']?(?:auth|token|secret|ipcSecret|daemonIpcSecret|tokenPreview|credentialPreview|secretPreview|accessToken|refreshToken|machineToken|pairToken|pushToken|shareToken|idToken|apiKey|clientSecret|deviceSecret|deviceSecretHash|browserState|inviteToken|inviteCode|shareCode|signature|code|smsCode|verificationCode|oneTimeCode|otp|ticket|randstr|csrf|csrfToken|xsrfToken|password|credentials?)["']?\s*[:=]\s*)(["']?)[^"'\s,;}]+\2/gi,`$1$2${c}$2`).replace(/\bsk-[A-Za-z0-9_-]{8,}\b/g,c).replace(/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,c).replace(/[A-Za-z0-9_-]{80,}/g,c)}function g(t){const e=t.replace(/[^a-z0-9]/gi,"").toLowerCase();return e==="apikey"||e==="apikeys"||e==="credentials"||e==="tokenpreview"||e==="credentialpreview"||e==="secretpreview"||e==="authorization"||e==="cookie"||e==="code"||e==="smscode"||e==="verificationcode"||e==="onetimecode"||e==="otp"||e==="invitecode"||e==="sharecode"||e==="ticket"||e==="randstr"||e==="csrf"||e==="csrftoken"||e==="xsrftoken"||e==="devicesecrethash"||e.endsWith("token")||e.endsWith("tokens")||e.endsWith("secret")||e.endsWith("secrets")||e.endsWith("password")||e.endsWith("signature")}function d(t,e=[],o="",i=0,s=new WeakSet){if(o&&g(o))return c;if(typeof t=="string")return f(t,e);if(t instanceof Error){const r=new Error(f(t.message,e));return r.name=t.name,r.stack=t.stack?f(t.stack,e):void 0,r}if(t&&typeof t=="object"){if(i>=10)return"[max-depth]";if(s.has(t))return"[circular]";if(s.add(t),Array.isArray(t)){const n=t.map(a=>d(a,e,"",i+1,s));return s.delete(t),n}const r=Object.fromEntries(Object.entries(t).map(([n,a])=>[n,d(a,e,n,i+1,s)]));return s.delete(t),r}return t}function h(t,e){const o=new Set,i=/(token|secret|password|api[_-]?key|authorization|cookie|signature)/i;for(const[r,n]of Object.entries(t))n&&n.length>=6&&i.test(r)&&o.add(n);const s=(r,n="",a=0)=>{if(!(a>8||r==null)){if(typeof r=="string"){r.length>=6&&i.test(n)&&o.add(r);return}if(typeof r=="object")for(const[k,l]of Object.entries(r))s(l,k,a+1)}};return s(e),[...o]}let p=!1;function T(t){if(!p){p=!0;for(const e of["log","info","warn","error"]){const o=console[e].bind(console);console[e]=(...i)=>{o(...i.map(s=>d(s,t)))}}}}export{h as collectKnownLogSecrets,T as installCliLogRedaction,f as redactCliLogText,d as sanitizeCliLogValue};
|