kslock-daemon 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +27 -0
  2. package/dist/index.js +12 -0
  3. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # kslock-daemon
2
+
3
+ Local machine daemon for kslock agent collaboration.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npx -y kslock-daemon@0.1.1 start \
9
+ --server-url https://api.kslock.ai \
10
+ --machine-key mk_xxx
11
+ ```
12
+
13
+ The daemon connects to the API websocket gateway and executes configured local runtimes such as Codex, Claude, kscc, and opencode.
14
+
15
+ ## Runtime Paths
16
+
17
+ Runtime CLI paths can be pinned with environment variables:
18
+
19
+ ```bash
20
+ CODEX_BIN=/absolute/path/to/codex \
21
+ CLAUDE_BIN=/absolute/path/to/claude \
22
+ KSCC_BIN=/absolute/path/to/kscc \
23
+ OPENCODE_BIN=/absolute/path/to/opencode \
24
+ npx -y kslock-daemon@0.1.1 start \
25
+ --server-url https://api.kslock.ai \
26
+ --machine-key mk_xxx
27
+ ```
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import Y from"node:os";import{existsSync as Nt,readFileSync as $t}from"node:fs";import{join as _}from"node:path";function De(e,t=process.env){let n=t.KSLOCK_SERVER_URL||t.DAEMON_SERVER_URL||"",r=t.KSLOCK_MACHINE_KEY||t.DAEMON_MACHINE_KEY||"";for(let s=0;s<e.length;s+=1){let o=e[s];if(o!=="start"){if(o==="--server-url"&&e[s+1]){n=e[++s];continue}o==="--machine-key"&&e[s+1]&&(r=e[++s])}}return!n||!r?null:{serverUrl:n.replace(/\/$/,""),machineKey:r,daemonVersion:"0.1.0-dev",hostname:Y.hostname(),os:Y.platform(),arch:Y.arch(),reconnectBaseMs:1e3}}function Oe(e=process.env,t=process.cwd()){let n=Jt(e.KSLOCK_ENV??e.NODE_ENV),r=Bt(t),s=[n?_(r,`.env.${n}`):null,_(r,".env")];for(let o of s)o&&Nt(o)&&Kt(o,e)}function Bt(e){return e.endsWith(_("apps","daemon"))?_(e,"..",".."):e}function Kt(e,t){for(let n of $t(e,"utf8").split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;let s=r.indexOf("=");if(s===-1)continue;let o=r.slice(0,s).trim();if(t[o]!==void 0)continue;let i=r.slice(s+1).trim();i.startsWith('"')&&i.endsWith('"')&&(i=i.slice(1,-1)),i.startsWith("'")&&i.endsWith("'")&&(i=i.slice(1,-1)),t[o]=i}}function Jt(e){let t=e?.trim().toLowerCase();if(t)return t==="development"||t==="local"?"dev":t==="production"?"prod":t}var Z=["Usage: kslock-daemon [start] --server-url <url> --machine-key <key>","","Environment:"," KSLOCK_SERVER_URL API server URL, for example https://api.kslock.ai"," KSLOCK_MACHINE_KEY Machine key created from the web console"].join(`
3
+ `);import Mt from"ws";var M=class{constructor(t){this.sendFrame=t}delivered(t){this.sendFrame({type:"agent:delivery_ack",deliveryId:t.deliveryId,agentId:t.agentId,status:"delivered"})}completed(t){this.sendFrame({type:"agent:delivery_ack",deliveryId:t.deliveryId,agentId:t.agentId,status:"completed"})}failed(t,n){this.sendFrame({type:"agent:delivery_ack",deliveryId:t.deliveryId,agentId:t.agentId,status:"failed",error:n})}status(t,n,r){this.sendFrame({type:"agent:status",agentId:t.agentId,status:n,...r!==void 0?{sessionId:r}:{}})}runtimeLog(t,n,r){this.sendFrame({type:"runtime:log",agentId:t.agentId,deliveryId:t.deliveryId,stream:n,content:r})}message(t,n){this.sendFrame({type:"agent:message",agentId:t.agentId,channelId:t.channelId,threadId:t.threadId,replyToMessageId:t.messageId,deliveryId:t.deliveryId,content:n})}messageDelta(t,n,r){!n&&!r||this.sendFrame({type:"agent:message_delta",agentId:t.agentId,channelId:t.channelId,threadId:t.threadId,replyToMessageId:t.messageId,deliveryId:t.deliveryId,contentDelta:n,...r!==void 0?{contentSnapshot:r}:{}})}taskInReview(t){t.taskId&&this.sendFrame({type:"task:status",taskId:t.taskId,agentId:t.agentId,status:"in_review",message:`${t.runtimeType} agent completed the task and requested review.`})}};var T=class{constructor(t){this.onCancelledBeforeStart=t}deliveryQueues=new Map;activeDeliveries=new Map;cancelledDeliveries=new Map;async enqueue(t,n){let s=(this.deliveryQueues.get(t.agentId)??Promise.resolve()).catch(()=>{}).then(()=>this.run(t,n));this.deliveryQueues.set(t.agentId,s),await s.finally(()=>{this.deliveryQueues.get(t.agentId)===s&&this.deliveryQueues.delete(t.agentId)})}cancel(t,n="cancelled_by_user"){this.cancelledDeliveries.set(t,n),this.activeDeliveries.get(t)?.abort(n)}async run(t,n){let r=this.cancelledDeliveries.get(t.deliveryId);if(r){this.cancelledDeliveries.delete(t.deliveryId),this.onCancelledBeforeStart(t,r);return}let s=new AbortController;this.activeDeliveries.set(t.deliveryId,s);try{await n(t,s.signal)}finally{this.activeDeliveries.delete(t.deliveryId),this.cancelledDeliveries.delete(t.deliveryId)}}};import{appendFile as Ut,mkdir as qt,rename as Vt,stat as Wt}from"node:fs/promises";import{join as Ht}from"node:path";import{homedir as zt}from"node:os";import{join as ee}from"node:path";function Gt(){return ee(zt(),".agent-collab")}function te(e){return ee(Gt(),"agents",e)}function Le(e){return ee(te(e),"logs")}var Qt="session.log",Xt=1e6,Yt=5;async function C(e,t,n){let r=Le(e);await qt(r,{recursive:!0});let s=Ht(r,Qt);await Zt(s);let o=JSON.stringify({time:new Date().toISOString(),stream:t,content:n});await Ut(s,`${o}
4
+ `,"utf8")}async function Zt(e){try{if((await Wt(e)).size<Xt)return}catch{return}for(let t=Yt-1;t>=1;t-=1)await Pe(`${e}.${t}`,`${e}.${t+1}`);await Pe(e,`${e}.1`)}async function Pe(e,t){try{await Vt(e,t)}catch{}}var j=class{constructor(t){this.publisher=t}create(t,n){return{cwd:t.workspacePath??void 0,abortSignal:n,env:{...process.env,AGENT_ID:t.agentId,SERVER_ID:t.serverId,CHANNEL_ID:t.channelId,WORKSPACE_ID:t.workspaceId??"",AGENT_TOKEN:t.agentToken,AGENT_PROXY_URL:"",AGENT_RUNTIME:t.runtimeType},onLog:(r,s)=>{this.publisher.runtimeLog(t,r,s),C(t.agentId,r,s)},onPartial:(r,s)=>{this.publisher.messageDelta(t,r,s)}}}};var N=class{constructor(t,n){this.runtimes=t;this.publisher=n;this.contextFactory=new j(n)}contextFactory;async run(t,n){this.publisher.delivered(t),this.publisher.status(t,"working");try{this.publisher.runtimeLog(t,"system",`using ${t.executionPolicy.preset} execution policy for @${t.agentHandle}`);let s=await this.runtimes.get(t.runtimeType).handleDelivery(t,this.contextFactory.create(t,n));t.attachments.length>0&&await C(t.agentId,"system",`delivery has attachments: ${t.attachments.map(o=>o.filename).join(", ")}`),s.sessionId&&this.publisher.status(t,"working",s.sessionId),this.publisher.message(t,s.content),this.publisher.taskInReview(t),this.publisher.completed(t),this.publisher.status(t,"idle",s.sessionId??null)}catch(r){let s=r instanceof Error?r.message:`${t.runtimeType} runtime failed`;C(t.agentId,"stderr",s),this.publisher.failed(t,s),this.publisher.status(t,"error")}}};import{randomUUID as Qe}from"node:crypto";import{mkdir as en,readFile as tn,writeFile as nn}from"node:fs/promises";import{join as _e}from"node:path";function y(e){return te(e)}async function h(e){try{let t=await tn(_e(y(e),"session.json"),"utf8");return JSON.parse(t)}catch{return null}}async function w(e){let t=y(e.agentId);await en(t,{recursive:!0}),await nn(_e(t,"session.json"),`${JSON.stringify(e,null,2)}
5
+ `,"utf8")}import{spawn as Te}from"node:child_process";import{constants as rn}from"node:fs";import{access as sn,readdir as on}from"node:fs/promises";import{homedir as re}from"node:os";import{delimiter as an,join as I}from"node:path";var un=/^[a-zA-Z0-9._-]+$/,ne=new Map;async function v(e,t){let n=ln(e,t),r=`${n.command}:${n.envVars.join(",")}:${n.extraCandidates.join(",")}`,s=[...cn(n),...n.extraCandidates,...gn(n.command)],o=ne.get(r);if(o&&(s.length===0||s.includes(o))&&await Me(o))return o;o&&ne.delete(r);let i=[...s,await mn(n.command),...await pn(n.command),n.command].filter(Boolean);for(let u of hn(i))if(await Me(u))return ne.set(r,u),u;return null}function ln(e,t){return typeof e!="string"?{command:e.command,envVars:e.envVars??[],extraCandidates:e.extraCandidates??[]}:{command:e,envVars:t?[t]:[],extraCandidates:[]}}function cn(e){return[...e.envVars,...dn(e.command)].map(t=>process.env[t]?.trim()).filter(Boolean)}function dn(e){let t=e.toUpperCase().replace(/[^A-Z0-9]+/g,"_");return[`${t}_BIN`,`${t}_PATH`,`KSLOCK_${t}_BIN`,`KSLOCK_RUNTIME_${t}_BIN`]}async function mn(e){if(!un.test(e))return null;let t=process.env.SHELL||"/bin/zsh";return new Promise(n=>{let r="",s=Te(t,["-lc",`command -v ${e}`],{stdio:["ignore","pipe","ignore"]});s.stdout.on("data",o=>{r+=o.toString()}),s.on("error",()=>n(null)),s.on("exit",o=>{let i=r.trim().split(/\r?\n/)[0];n(o===0&&i?i:null)})})}async function pn(e){return[...await yn(e),I(re(),".local","bin",e),I(re(),"bin",e),I("/opt/homebrew/bin",e),I("/usr/local/bin",e)]}function gn(e){return fn(process.env.KSLOCK_RUNTIME_PATHS||process.env.KSLOCK_RUNTIME_PATH).map(t=>I(t,e))}function fn(e){return(e??"").split(an).map(t=>t.trim()).filter(Boolean)}async function yn(e){let t=I(re(),".nvm","versions","node");try{return(await on(t)).sort((r,s)=>s.localeCompare(r)).map(r=>I(t,r,"bin",e))}catch{return[]}}async function Me(e){if(e.includes("/"))try{await sn(e,rn.X_OK)}catch{return!1}return new Promise(t=>{let n=!1,r=i=>{n||(n=!0,t(i))},s=Te(e,["--version"],{stdio:"ignore"}),o=setTimeout(()=>{s.kill("SIGTERM"),r(!1)},3e3);o.unref?.(),s.on("error",()=>{clearTimeout(o),r(!1)}),s.on("exit",()=>{clearTimeout(o),r(!0)})})}function hn(e){return[...new Set(e)]}function x(e){if(e.attachments.length===0)return e.content;let t=e.attachments.map(n=>`- ${n.filename} (${n.contentType}, ${n.size} bytes)`).join(`
6
+ `);return`${e.content}
7
+
8
+ Attachments:
9
+ ${t}`}function je(e){return e.preset==="read_only"?["--permission-mode","dontAsk","--tools","Read,Grep,Glob,LS"]:e.preset==="full_access"?["--dangerously-skip-permissions"]:["--permission-mode","acceptEdits","--allowedTools",["Read","Grep","Glob","LS","Edit","MultiEdit","Write","Bash(git status *)","Bash(git diff *)","Bash(git log *)","Bash(git show *)","Bash(pnpm test *)","Bash(pnpm run test *)","Bash(pnpm typecheck *)","Bash(pnpm run typecheck *)","Bash(pnpm lint *)","Bash(pnpm run lint *)","Bash(pnpm build *)","Bash(pnpm run build *)","Bash(npm test *)","Bash(npm run test *)","Bash(npm run typecheck *)","Bash(npm run lint *)","Bash(npm run build *)","Bash(yarn test *)","Bash(yarn typecheck *)","Bash(yarn lint *)","Bash(yarn build *)","Bash(tsc *)","Bash(vitest *)"].join(","),"--disallowedTools",["Bash(rm *)","Bash(sudo *)","Bash(chmod *)","Bash(chown *)","Bash(curl *)","Bash(wget *)"].join(",")]}function se(e){return["-p","--output-format","stream-json","--verbose","--include-partial-messages",...e.resume?["--resume",e.sessionId]:["--session-id",e.sessionId],...wn(e.model),...je(e.frame.executionPolicy),e.message]}function oe(e){return e.CLAUDE_MODEL?.trim()||e.ANTHROPIC_MODEL?.trim()||null}function wn(e){return e?["--model",e]:[]}var $="Claude \u8FD4\u56DE\u9519\u8BEF\uFF0C\u672A\u63D0\u4F9B\u8BE6\u7EC6\u539F\u56E0";function $e(e){if(!e||typeof e!="object")return null;let t=e;for(let n of["type","subtype","event","event_name"])if(typeof t[n]=="string")return t[n];return null}function ae(e){if(!e||typeof e!="object")return null;let t=e;for(let n of["session_id","sessionId"])if(typeof t[n]=="string"&&vn(t[n]))return t[n];for(let n of Object.values(t)){let r=ae(n);if(r)return r}return null}function ue(e){if(!e||typeof e!="object")return null;let t=e;if(typeof t.result=="string"&&t.result.trim())return t.result;if(typeof t.content=="string"&&t.content.trim())return t.content;let n=t.message;if(n&&typeof n=="object"){let r=Ne(n.content);if(r)return r}return Ne(t.content)}function B(e){if(!e)return null;let t=xn(e),r=(t?b(t):e)?.trim();return!r||ie(r)?null:r}function R(e){if(!e||typeof e!="object")return null;let t=e,n=typeof t.type=="string"?t.type:"",r=typeof t.subtype=="string"?t.subtype:"";return n==="error"||r==="error"||r==="failure"||t.is_error===!0||n==="result"&&r&&r!=="success"?b(e)??$:null}function le(e,t){return!e||e===$&&t!==$?t:e}function Ne(e){if(typeof e=="string"&&e.trim())return e;if(!Array.isArray(e))return null;let t=e.map(n=>{if(!n||typeof n!="object")return"";let r=n;return typeof r.text=="string"?r.text:""}).filter(Boolean).join("");return t.trim()?t:null}function b(e){if(typeof e=="string"&&e&&!ie(e))return e;if(!e||typeof e!="object")return null;let t=e;for(let r of["message","detail","reason","error"]){let s=t[r];if(typeof s=="string"&&s&&!ie(s))return s}let n=b(t.error);if(n)return n;for(let r of Object.values(t)){let s=b(r);if(s)return s}return null}function vn(e){return/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(e)}function ie(e){let t=e.trim().toLowerCase();return t==="error"||t==="failure"}function xn(e){try{return JSON.parse(e)}catch{return null}}import{spawn as In}from"node:child_process";function Ue(e){return new Promise((t,n)=>{let r=[],s=[],o="",i=[],u="",a="",l="",c=In(e.command,e.args,{cwd:e.cwd||process.cwd(),env:e.env,stdio:["ignore","pipe","pipe"]});if(e.signal?.aborted){c.kill("SIGTERM"),n(new Error("runtime_cancelled"));return}e.signal?.addEventListener("abort",()=>{c.kill("SIGTERM"),n(new Error("runtime_cancelled"))},{once:!0}),c.stdout.on("data",m=>{a=Be(a+m.toString(),p=>{let d=Ke(p);if(d){let g=e.onJson(d)??R(d);g&&(u=le(u,g));let f=ue(d);f&&(Je(d)?s.push(f):o=ze(f,o,e.onPartial));return}r.push(p),e.onLog("stdout",p)})}),c.stderr.on("data",m=>{l=Be(l+m.toString(),p=>{i.push(p),e.onLog("stderr",p)})}),c.on("error",n),c.on("exit",m=>{if(a.trim()){let d=Ke(a.trim());if(d){let g=e.onJson(d)??R(d);g&&(u=le(u,g));let f=ue(d);f&&(Je(d)?s.push(f):o=ze(f,o,e.onPartial))}else r.push(a.trim()),e.onLog("stdout",a.trim())}if(l.trim()&&(i.push(l.trim()),e.onLog("stderr",l.trim())),e.onLog("system",`${e.command} exited with code ${m??"unknown"}`),m===0){t({output:Cn(s,o,r)});return}let p=B(Ge(i))??Ge(i);n(new Error(u||p||`${e.command} exited with code ${m}`))})})}function Be(e,t){let n=e.split(/\r?\n/),r=n.pop()??"";for(let s of n)s.trim()&&t(s);return r}function Ke(e){try{return JSON.parse(e)}catch{return null}}function Je(e){return!!(e&&typeof e=="object"&&e.type==="result")}function ze(e,t,n){let r=e.startsWith(t)?e:`${t}${e}`,s=r.slice(t.length);return s&&n?.(s,r),r}function Cn(e,t,n){let r=e.at(-1)?.trim();if(r)return r;let s=t.trim();return s||n.join(`
10
+ `).trim()}function Ge(e){return e.map(t=>t.trim()).filter(Boolean).at(-1)??""}import{mkdir as bn,readFile as Rn,writeFile as qe}from"node:fs/promises";import{join as An}from"node:path";var En="claude-last-message.txt";function Sn(e){return An(y(e),En)}async function Ve(e){await bn(y(e),{recursive:!0});let t=Sn(e);return await qe(t,"","utf8"),t}async function We(e,t){await qe(e,t,"utf8")}async function He(e){try{return await Rn(e,"utf8")}catch{return""}}var A=class{type="claude";capabilities={supportsSession:!0,supportsStreaming:!0,supportsExecutionPolicy:!0};async detect(){return!!await this.resolveCommand()}async handleDelivery(t,n){let r=await this.resolveCommand();if(!r)throw new Error("claude runtime is not available");let s=await h(t.agentId),o=s?.runtimeType===this.type?s.runtimeSessionId:null,i=o??Qe(),u=o?`resuming ${o}`:`starting new session ${i}`;n.onLog("system",`claude ${u} in ${n.cwd??process.cwd()}`);let a;try{a=await this.runClaude(r,t,n,i,!!o)}catch(l){if(!o)throw l;let c=Qe();n.onLog("stderr",`claude resume ${o} failed; starting a new session ${c}. ${l instanceof Error?l.message:""}`),a=await this.runClaude(r,t,n,c,!1)}return await w({agentId:t.agentId,runtimeType:this.type,runtimeSessionId:a.sessionId,workspacePath:n.cwd??null,updatedAt:new Date().toISOString()}),n.onLog("system",`claude session ${a.sessionId}`),{content:a.output.trim()||"claude runtime completed without output",sessionId:a.sessionId}}async runClaude(t,n,r,s,o){let i=x(n),u=oe(r.env),a=await Ve(n.agentId);r.onLog("system",u?`claude using model override ${u}`:"claude using configured model"),r.onLog("system",o?`claude resume ${s}`:`claude session-id ${s}`);let l=new Set,c=await Ue({command:t,args:se({frame:n,message:i,sessionId:s,resume:o,model:u}),cwd:r.cwd,env:r.env,signal:r.abortSignal,onPartial:r.onPartial,onJson:m=>{let p=ae(m);p&&l.add(p);let d=$e(m);d&&r.onLog("system",`[claude:event] ${d}`);let g=B(R(m));return g?(r.onLog("stderr",`[claude:error] ${g}`),g):null},onLog:r.onLog});return await We(a,c.output),{output:c.output||await He(a),sessionId:[...l].at(-1)??s}}async resolveCommand(){return v({command:"claude",envVars:["CLAUDE_BIN"]})}};import{mkdir as Tn,writeFile as jn}from"node:fs/promises";import{join as Nn}from"node:path";function K(e){return e.preset==="read_only"?"read-only":e.preset==="full_access"?"danger-full-access":"workspace-write"}function ce(e){let t=["-a","never","-s",K(e.frame.executionPolicy),"exec"];return e.sessionId?[...t,"resume","--json","--skip-git-repo-check",...Xe(e.model),"--output-last-message",e.outputFile,e.sessionId,e.prompt]:[...t,"--json","--skip-git-repo-check",...Xe(e.model),"--output-last-message",e.outputFile,e.prompt]}function de(e){return e.CODEX_MODEL?.trim()||null}function Xe(e){return e?["--model",e]:[]}var me="Codex \u8FD4\u56DE\u9519\u8BEF\uFF0C\u672A\u63D0\u4F9B\u8BE6\u7EC6\u539F\u56E0",kn=/The ['‘"]?([^'’"]+)['’"]? model requires a newer version of Codex\. Please upgrade to the latest app or CLI and try again\./i;function z(e){if(!e||typeof e!="object")return null;let t=e;for(let n of["type","event","event_name","method"])if(typeof t[n]=="string")return t[n];return null}function pe(e){if(!e||typeof e!="object")return null;let t=e;for(let n of["session_id","sessionId","thread_id","threadId","conversation_id","conversationId"])if(typeof t[n]=="string"&&t[n])return t[n];for(let n of Object.values(t)){let r=pe(n);if(r)return r}return null}function Ye(e){if(!e)return null;let t=Dn(e),r=(t?E(t):e)?.trim();return!r||J(r)?null:Fn(r)}function Ze(e){if(!e||typeof e!="object")return null;let t=z(e);return t!=="error"&&t!=="turn.failed"?null:me}function et(e){if(!e||typeof e!="object")return null;let t=e,n=z(e);if(n!=="error"&&n!=="turn.failed")return null;for(let s of["message","detail","reason"])if(typeof t[s]=="string"&&t[s]&&!J(t[s]))return t[s];let r=E(t.error);if(r)return r;for(let[s,o]of Object.entries(t)){if(["type","event","event_name","method","status","error"].includes(s))continue;let i=E(o);if(i)return i}return null}function ge(e,t){return!e||e===me&&t!==me?t:e}function E(e){if(typeof e=="string"&&e&&!J(e))return e;if(!e||typeof e!="object")return null;let t=e;for(let r of["message","detail","reason"])if(typeof t[r]=="string"&&t[r]&&!J(t[r]))return t[r];let n=E(t.error);if(n)return n;for(let r of Object.values(t)){let s=E(r);if(s)return s}return null}function J(e){let t=e.trim().toLowerCase();return t==="error"||t==="turn.failed"}function Fn(e){let t=e.match(kn);return t?`Codex CLI \u7248\u672C\u8FC7\u4F4E\uFF0C\u6682\u4E0D\u652F\u6301\u6A21\u578B ${t[1]??"\u5F53\u524D\u6A21\u578B"}\u3002\u8BF7\u5347\u7EA7 Codex CLI \u540E\u91CD\u542F daemon\uFF0C\u6216\u5C06 CODEX_MODEL \u8C03\u6574\u4E3A\u5F53\u524D CLI \u652F\u6301\u7684\u6A21\u578B\u540E\u91CD\u8BD5\u3002`:e}function Dn(e){try{return JSON.parse(e)}catch{return null}}import{spawn as On}from"node:child_process";var Ln="Reading additional input from stdin...";function rt(e){return new Promise((t,n)=>{let r=[],s="",o="",i="",u=On(e.command,e.args,{cwd:e.cwd||process.cwd(),env:e.env,stdio:["ignore","pipe","pipe"]});if(e.signal?.aborted){u.kill("SIGTERM"),n(new Error("runtime_cancelled"));return}e.signal?.addEventListener("abort",()=>{u.kill("SIGTERM"),n(new Error("runtime_cancelled"))},{once:!0}),u.stdout.on("data",a=>{o=tt(o+a.toString(),l=>{let c=nt(l);if(c){let m=e.onJson(c);m&&(s=ge(s,m));return}e.onLog("stdout",l)})}),u.stderr.on("data",a=>{i=tt(i+a.toString(),l=>{fe(l)||(r.push(l),e.onLog("stderr",l))})}),u.on("error",n),u.on("exit",a=>{if(o.trim()){let l=nt(o.trim());if(l){let c=e.onJson(l);c&&(s=ge(s,c))}else e.onLog("stdout",o.trim())}if(i.trim()&&!fe(i.trim())&&(r.push(i.trim()),e.onLog("stderr",i.trim())),e.onLog("system",`${e.command} exited with code ${a??"unknown"}`),a===0){t();return}n(new Error(s||Pn(r)||`${e.command} exited with code ${a}`))})})}function tt(e,t){let n=e.split(/\r?\n/),r=n.pop()??"";for(let s of n)s.trim()&&t(s);return r}function nt(e){try{return JSON.parse(e)}catch{return null}}function fe(e){return e.trim()===Ln}function Pn(e){return e.map(t=>t.trim()).filter(t=>t&&!fe(t)).at(-1)??""}import{readFile as _n}from"node:fs/promises";async function st(e){try{return await _n(e,"utf8")}catch{return""}}function ot(e){if(!e||typeof e!="object")return null;let t=e,n=Mn(e)??"";for(let s of["delta","text_delta","content_delta"])if(typeof t[s]=="string"&&t[s])return t[s];if(n.includes("delta")||n.includes("stream")){for(let s of["text","content","message"])if(typeof t[s]=="string"&&t[s])return t[s]}return it(t.delta??t.message??t.item)}function it(e){if(typeof e=="string"&&e)return e;if(!e||typeof e!="object")return null;let t=e;for(let n of["delta","text_delta","content_delta","text"])if(typeof t[n]=="string"&&t[n])return t[n];for(let n of Object.values(t)){let r=it(n);if(r)return r}return null}function Mn(e){if(!e||typeof e!="object")return null;let t=e;for(let n of["type","event","event_name","method"])if(typeof t[n]=="string")return t[n];return null}var S=class{type="codex";capabilities={supportsSession:!0,supportsStreaming:!0,supportsExecutionPolicy:!0};async detect(){return!!await this.resolveCommand()}async handleDelivery(t,n){let r=await this.resolveCommand();if(!r)throw new Error("codex runtime is not available");let s=await h(t.agentId),o=s?.runtimeType===this.type?s.runtimeSessionId:null,i=o?`resuming ${o}`:"starting new session";n.onLog("system",`codex ${i} in ${n.cwd??process.cwd()}`);let u;try{u=await this.runCodex(r,t,n,o)}catch(l){if(!o)throw l;n.onLog("stderr",`codex resume ${o} failed; starting a new session. ${l instanceof Error?l.message:""}`),u=await this.runCodex(r,t,n,null)}let a=u.sessionId??o??null;return await w({agentId:t.agentId,runtimeType:this.type,runtimeSessionId:a,workspacePath:n.cwd??null,updatedAt:new Date().toISOString()}),a?n.onLog("system",`codex session ${a}`):n.onLog("system","codex completed without exposing a resumable session id"),{content:u.output.trim()||"codex runtime completed without output",sessionId:a}}async runCodex(t,n,r,s){let o=y(n.agentId);await Tn(o,{recursive:!0});let i=Nn(o,"last-message.txt");await jn(i,"","utf8");let u=x(n),a=de(r.env);r.onLog("system",a?`codex using model override ${a}`:"codex using configured model"),r.onLog("system",`codex sandbox ${K(n.executionPolicy)}`);let l=new Set;return await rt({command:t,args:ce({frame:n,prompt:u,outputFile:i,model:a,sessionId:s}),cwd:r.cwd,env:r.env,signal:r.abortSignal,onJson:c=>{let m=ot(c);m&&r.onPartial?.(m);let p=pe(c);p&&l.add(p);let d=z(c);d&&r.onLog("system",`[codex:event] ${d}`);let g=Ye(et(c))??Ze(c);return g?(r.onLog("stderr",`[codex:error] ${g}`),g):null},onLog:r.onLog}),{output:await st(i),sessionId:[...l].at(-1)??null}}async resolveCommand(){return v({command:"codex",envVars:["CODEX_BIN","CODEX_CLI_PATH"]})}};import{randomUUID as xt}from"node:crypto";function at(e){return e.preset==="read_only"?["--permission-mode","dontAsk","--tools","Read,Grep,Glob,LS"]:e.preset==="full_access"?["--dangerously-skip-permissions"]:["--permission-mode","acceptEdits","--allowedTools",["Read","Grep","Glob","LS","Edit","MultiEdit","Write","Bash(git status *)","Bash(git diff *)","Bash(git log *)","Bash(git show *)","Bash(pnpm test *)","Bash(pnpm run test *)","Bash(pnpm typecheck *)","Bash(pnpm run typecheck *)","Bash(pnpm lint *)","Bash(pnpm run lint *)","Bash(pnpm build *)","Bash(pnpm run build *)","Bash(npm test *)","Bash(npm run test *)","Bash(npm run typecheck *)","Bash(npm run lint *)","Bash(npm run build *)","Bash(yarn test *)","Bash(yarn typecheck *)","Bash(yarn lint *)","Bash(yarn build *)","Bash(tsc *)","Bash(vitest *)"].join(","),"--disallowedTools",["Bash(rm *)","Bash(sudo *)","Bash(chmod *)","Bash(chown *)","Bash(curl *)","Bash(wget *)"].join(",")]}function ye(e){return["-p","--output-format","stream-json","--verbose","--include-partial-messages",...e.resume?["--resume",e.sessionId]:["--session-id",e.sessionId],...$n(e.model),...at(e.frame.executionPolicy),e.message]}function he(e){return e.KSCC_MODEL?.trim()||e.ANTHROPIC_MODEL?.trim()||null}function $n(e){return e?["--model",e]:[]}var G="kscc \u8FD4\u56DE\u9519\u8BEF\uFF0C\u672A\u63D0\u4F9B\u8BE6\u7EC6\u539F\u56E0";function lt(e){if(!e||typeof e!="object")return null;let t=e;for(let n of["type","subtype","event","event_name"])if(typeof t[n]=="string")return t[n];return null}function ve(e){if(!e||typeof e!="object")return null;let t=e;for(let n of["session_id","sessionId"])if(typeof t[n]=="string"&&Bn(t[n]))return t[n];for(let n of Object.values(t)){let r=ve(n);if(r)return r}return null}function xe(e){if(!e||typeof e!="object")return null;let t=e;if(typeof t.result=="string"&&t.result.trim())return t.result;if(typeof t.content=="string"&&t.content.trim())return t.content;let n=t.message;if(n&&typeof n=="object"){let r=ut(n.content);if(r)return r}return ut(t.content)}function U(e){if(!e)return null;let t=Kn(e),r=(t?k(t):e)?.trim();return!r||we(r)?null:r}function F(e){if(!e||typeof e!="object")return null;let t=e,n=typeof t.type=="string"?t.type:"",r=typeof t.subtype=="string"?t.subtype:"";return n==="error"||r==="error"||r==="failure"||t.is_error===!0||n==="result"&&r&&r!=="success"?k(e)??G:null}function Ie(e,t){return!e||e===G&&t!==G?t:e}function ut(e){if(typeof e=="string"&&e.trim())return e;if(!Array.isArray(e))return null;let t=e.map(n=>{if(!n||typeof n!="object")return"";let r=n;return typeof r.text=="string"?r.text:""}).filter(Boolean).join("");return t.trim()?t:null}function k(e){if(typeof e=="string"&&e&&!we(e))return e;if(!e||typeof e!="object")return null;let t=e;for(let r of["message","detail","reason","error"]){let s=t[r];if(typeof s=="string"&&s&&!we(s))return s}let n=k(t.error);if(n)return n;for(let r of Object.values(t)){let s=k(r);if(s)return s}return null}function Bn(e){return/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(e)}function we(e){let t=e.trim().toLowerCase();return t==="error"||t==="failure"}function Kn(e){try{return JSON.parse(e)}catch{return null}}import{spawn as Jn}from"node:child_process";function ft(e){return new Promise((t,n)=>{let r=[],s=[],o="",i=[],u="",a="",l="",c=Jn(e.command,e.args,{cwd:e.cwd||process.cwd(),env:e.env,stdio:["ignore","pipe","pipe"]});if(e.signal?.aborted){c.kill("SIGTERM"),n(new Error("runtime_cancelled"));return}e.signal?.addEventListener("abort",()=>{c.kill("SIGTERM"),n(new Error("runtime_cancelled"))},{once:!0}),c.stdout.on("data",m=>{a=ct(a+m.toString(),p=>{let d=dt(p);if(d){let g=e.onJson(d)??F(d);g&&(u=Ie(u,g));let f=xe(d);f&&(mt(d)?s.push(f):o=pt(f,o,e.onPartial));return}r.push(p),e.onLog("stdout",p)})}),c.stderr.on("data",m=>{l=ct(l+m.toString(),p=>{i.push(p),e.onLog("stderr",p)})}),c.on("error",n),c.on("exit",m=>{if(a.trim()){let d=dt(a.trim());if(d){let g=e.onJson(d)??F(d);g&&(u=Ie(u,g));let f=xe(d);f&&(mt(d)?s.push(f):o=pt(f,o,e.onPartial))}else r.push(a.trim()),e.onLog("stdout",a.trim())}if(l.trim()&&(i.push(l.trim()),e.onLog("stderr",l.trim())),e.onLog("system",`${e.command} exited with code ${m??"unknown"}`),m===0){t({output:zn(s,o,r)});return}let p=U(gt(i))??gt(i);n(new Error(u||p||`${e.command} exited with code ${m}`))})})}function ct(e,t){let n=e.split(/\r?\n/),r=n.pop()??"";for(let s of n)s.trim()&&t(s);return r}function dt(e){try{return JSON.parse(e)}catch{return null}}function mt(e){return!!(e&&typeof e=="object"&&e.type==="result")}function pt(e,t,n){let r=e.startsWith(t)?e:`${t}${e}`,s=r.slice(t.length);return s&&n?.(s,r),r}function zn(e,t,n){let r=e.at(-1)?.trim();if(r)return r;let s=t.trim();return s||n.join(`
11
+ `).trim()}function gt(e){return e.map(t=>t.trim()).filter(Boolean).at(-1)??""}import{mkdir as Gn,readFile as Un,writeFile as yt}from"node:fs/promises";import{join as qn}from"node:path";var Vn="kscc-last-message.txt";function Wn(e){return qn(y(e),Vn)}async function ht(e){await Gn(y(e),{recursive:!0});let t=Wn(e);return await yt(t,"","utf8"),t}async function wt(e,t){await yt(e,t,"utf8")}async function vt(e){try{return await Un(e,"utf8")}catch{return""}}var D=class{type="kscc";capabilities={supportsSession:!0,supportsStreaming:!0,supportsExecutionPolicy:!0};async detect(){return!!await this.resolveCommand()}async handleDelivery(t,n){let r=await this.resolveCommand();if(!r)throw new Error("kscc runtime is not available");let s=await h(t.agentId),o=s?.runtimeType===this.type?s.runtimeSessionId:null,i=o??xt(),u=o?`resuming ${o}`:`starting new session ${i}`;n.onLog("system",`kscc ${u} in ${n.cwd??process.cwd()}`);let a;try{a=await this.runKscc(r,t,n,i,!!o)}catch(l){if(!o)throw l;let c=xt();n.onLog("stderr",`kscc resume ${o} failed; starting a new session ${c}. ${l instanceof Error?l.message:""}`),a=await this.runKscc(r,t,n,c,!1)}return await w({agentId:t.agentId,runtimeType:this.type,runtimeSessionId:a.sessionId,workspacePath:n.cwd??null,updatedAt:new Date().toISOString()}),n.onLog("system",`kscc session ${a.sessionId}`),{content:a.output.trim()||"kscc runtime completed without output",sessionId:a.sessionId}}async runKscc(t,n,r,s,o){let i=x(n),u=he(r.env),a=await ht(n.agentId);r.onLog("system",u?`kscc using model override ${u}`:"kscc using configured model"),r.onLog("system",o?`kscc resume ${s}`:`kscc session-id ${s}`);let l=new Set,c=await ft({command:t,args:ye({frame:n,message:i,sessionId:s,resume:o,model:u}),cwd:r.cwd,env:r.env,signal:r.abortSignal,onPartial:r.onPartial,onJson:m=>{let p=ve(m);p&&l.add(p);let d=lt(m);d&&r.onLog("system",`[kscc:event] ${d}`);let g=U(F(m));return g?(r.onLog("stderr",`[kscc:error] ${g}`),g):null},onLog:r.onLog});return await wt(a,c.output),{output:c.output||await vt(a),sessionId:[...l].at(-1)??s}}async resolveCommand(){return v({command:"kscc",envVars:["KSCC_BIN"]})}};function It(e){return e.preset==="full_access"?"allow":e.preset==="read_only"?{"*":"deny",read:{"*":"allow","*.env":"deny","*.env.*":"deny","*.env.example":"allow"},glob:"allow",grep:"allow",list:"allow",lsp:"allow",todoread:"allow",edit:"deny",bash:"deny",task:"deny",skill:"deny",todowrite:"deny",webfetch:"deny",websearch:"deny",codesearch:"deny",external_directory:"deny",doom_loop:"deny"}:{"*":"deny",read:{"*":"allow","*.env":"deny","*.env.*":"deny","*.env.example":"allow"},glob:"allow",grep:"allow",list:"allow",lsp:"allow",todoread:"allow",todowrite:"allow",edit:"allow",skill:"allow",bash:{"*":"deny","git status *":"allow","git diff *":"allow","git log *":"allow","git show *":"allow","pnpm test *":"allow","pnpm run test *":"allow","pnpm typecheck *":"allow","pnpm run typecheck *":"allow","pnpm lint *":"allow","pnpm run lint *":"allow","pnpm build *":"allow","pnpm run build *":"allow","npm test *":"allow","npm run test *":"allow","npm run typecheck *":"allow","npm run lint *":"allow","npm run build *":"allow","yarn test *":"allow","yarn typecheck *":"allow","yarn lint *":"allow","yarn build *":"allow","tsc *":"allow","vitest *":"allow","rm *":"deny","sudo *":"deny","chmod *":"deny","chown *":"deny","curl *":"deny","wget *":"deny"},task:"deny",webfetch:"deny",websearch:"deny",codesearch:"deny",external_directory:"deny",doom_loop:"deny"}}function Ce(e){return["run","--format","json",...Hn(e.sessionId),...Qn(e.model),...Xn(e.frame.executionPolicy),e.message]}function be(e,t){return{...e,OPENCODE_PERMISSION:JSON.stringify(It(t))}}function Re(e){return e.OPENCODE_MODEL?.trim()||null}function Hn(e){return e?["--session",e]:[]}function Qn(e){return e?["--model",e]:[]}function Xn(e){return e.preset==="full_access"?["--dangerously-skip-permissions"]:[]}var q="opencode \u8FD4\u56DE\u9519\u8BEF\uFF0C\u672A\u63D0\u4F9B\u8BE6\u7EC6\u539F\u56E0";function bt(e){if(!e||typeof e!="object")return null;let t=e;for(let n of["type","subtype","event","event_name","eventName"])if(typeof t[n]=="string")return t[n];return null}function Ee(e){if(!e||typeof e!="object")return null;let t=e;for(let r of["sessionID","sessionId","session_id"])if(typeof t[r]=="string"&&t[r].trim())return t[r];let n=t.session;if(n&&typeof n=="object"){let r=n.id;if(typeof r=="string"&&r.trim())return r}for(let r of Object.values(t)){let s=Ee(r);if(s)return s}return null}function Se(e){if(!e||typeof e!="object")return null;let t=e;if(typeof t.result=="string"&&t.result.trim())return t.result;if(typeof t.output=="string"&&t.output.trim())return t.output;let n=Ct(t.message);if(n)return n;let r=Ct(t.part);if(r)return r;if(Yn(t)){if(typeof t.content=="string"&&t.content.trim())return t.content;if(typeof t.text=="string"&&t.text.trim())return t.text;let s=V(t.content);if(s)return s;let o=V(t.parts);if(o)return o}return null}function W(e){if(!e)return null;let t=Zn(e),r=(t?O(t):e)?.trim();return!r||Ae(r)?null:r}function L(e){if(!e||typeof e!="object")return null;let t=e,n=typeof t.type=="string"?t.type.toLowerCase():"",r=typeof t.subtype=="string"?t.subtype.toLowerCase():"";return n.includes("error")||r==="error"||r==="failure"||t.is_error===!0||n==="result"&&r&&r!=="success"?O(e)??q:null}function ke(e,t){return!e||e===q&&t!==q?t:e}function Ct(e){if(!e||typeof e!="object")return null;let t=e,n=typeof t.role=="string"?t.role.toLowerCase():"",r=typeof t.type=="string"?t.type.toLowerCase():"";return n&&n!=="assistant"?null:typeof t.text=="string"&&t.text.trim()?t.text:typeof t.content=="string"&&t.content.trim()?t.content:r&&r!=="text"&&!r.includes("assistant")&&!r.includes("message")&&!r.includes("part")?null:V(t.content)??V(t.parts)}function V(e){if(typeof e=="string"&&e.trim())return e;if(!Array.isArray(e))return null;let t=e.map(n=>{if(!n||typeof n!="object")return"";let r=n;return typeof r.text=="string"?r.text:typeof r.content=="string"?r.content:""}).filter(Boolean).join("");return t.trim()?t:null}function Yn(e){let t=typeof e.role=="string"?e.role.toLowerCase():"";if(t&&t!=="assistant")return!1;let n=typeof e.type=="string"?e.type.toLowerCase():"";return n?n==="result"||n==="text"||n.includes("assistant")||n.includes("message")||n.includes("part"):t==="assistant"}function O(e){if(typeof e=="string"&&e&&!Ae(e))return e;if(!e||typeof e!="object")return null;let t=e;for(let r of["message","detail","reason","error"]){let s=t[r];if(typeof s=="string"&&s&&!Ae(s))return s}let n=O(t.error);if(n)return n;for(let r of Object.values(t)){let s=O(r);if(s)return s}return null}function Ae(e){let t=e.trim().toLowerCase();return t==="error"||t==="failure"}function Zn(e){try{return JSON.parse(e)}catch{return null}}import{spawn as er}from"node:child_process";function Ft(e){return new Promise((t,n)=>{let r=[],s=[],o="",i=[],u="",a="",l="",c=er(e.command,e.args,{cwd:e.cwd||process.cwd(),env:e.env,stdio:["ignore","pipe","pipe"]});if(e.signal?.aborted){c.kill("SIGTERM"),n(new Error("runtime_cancelled"));return}e.signal?.addEventListener("abort",()=>{c.kill("SIGTERM"),n(new Error("runtime_cancelled"))},{once:!0}),c.stdout.on("data",m=>{a=Rt(a+m.toString(),p=>{let d=At(p);if(d){let g=e.onJson(d)??L(d);g&&(u=ke(u,g));let f=Se(d);f&&(Et(d)?s.push(f):o=St(f,o,e.onPartial));return}r.push(p),e.onLog("stdout",p)})}),c.stderr.on("data",m=>{l=Rt(l+m.toString(),p=>{i.push(p),e.onLog("stderr",p)})}),c.on("error",n),c.on("exit",m=>{if(a.trim()){let d=At(a.trim());if(d){let g=e.onJson(d)??L(d);g&&(u=ke(u,g));let f=Se(d);f&&(Et(d)?s.push(f):o=St(f,o,e.onPartial))}else r.push(a.trim()),e.onLog("stdout",a.trim())}if(l.trim()&&(i.push(l.trim()),e.onLog("stderr",l.trim())),e.onLog("system",`${e.command} exited with code ${m??"unknown"}`),m===0){t({output:tr(s,o,r)});return}let p=W(kt(i))??kt(i);n(new Error(u||p||`${e.command} exited with code ${m}`))})})}function Rt(e,t){let n=e.split(/\r?\n/),r=n.pop()??"";for(let s of n)s.trim()&&t(s);return r}function At(e){try{return JSON.parse(e)}catch{return null}}function Et(e){if(!e||typeof e!="object")return!1;let t=e,n=typeof t.type=="string"?t.type.toLowerCase():"";return n==="result"||n.includes("result")||n.includes("complete")}function St(e,t,n){let r=e.startsWith(t)?e:`${t}${e}`,s=r.slice(t.length);return s&&n?.(s,r),r}function tr(e,t,n){let r=e.at(-1)?.trim();if(r)return r;let s=t.trim();return s||n.join(`
12
+ `).trim()}function kt(e){return e.map(t=>t.trim()).filter(Boolean).at(-1)??""}import{mkdir as nr,readFile as rr,writeFile as Dt}from"node:fs/promises";import{join as sr}from"node:path";var or="opencode-last-message.txt";function ir(e){return sr(y(e),or)}async function Ot(e){await nr(y(e),{recursive:!0});let t=ir(e);return await Dt(t,"","utf8"),t}async function Lt(e,t){await Dt(e,t,"utf8")}async function Pt(e){try{return await rr(e,"utf8")}catch{return""}}var P=class{type="opencode";capabilities={supportsSession:!0,supportsStreaming:!0,supportsExecutionPolicy:!0};async detect(){return!!await this.resolveCommand()}async handleDelivery(t,n){let r=await this.resolveCommand();if(!r)throw new Error("opencode runtime is not available");let s=await h(t.agentId),o=s?.runtimeType===this.type?s.runtimeSessionId:null,i=o?`resuming ${o}`:"starting new session";n.onLog("system",`opencode ${i} in ${n.cwd??process.cwd()}`);let u;try{u=await this.runOpenCode(r,t,n,o)}catch(a){if(!o)throw a;n.onLog("stderr",`opencode resume ${o} failed; starting a new session. ${a instanceof Error?a.message:""}`),u=await this.runOpenCode(r,t,n,null)}return await w({agentId:t.agentId,runtimeType:this.type,runtimeSessionId:u.sessionId,workspacePath:n.cwd??null,updatedAt:new Date().toISOString()}),u.sessionId&&n.onLog("system",`opencode session ${u.sessionId}`),{content:u.output.trim()||"opencode runtime completed without output",sessionId:u.sessionId}}async runOpenCode(t,n,r,s){let o=x(n),i=Re(r.env),u=await Ot(n.agentId),a=be(r.env,n.executionPolicy);r.onLog("system",i?`opencode using model override ${i}`:"opencode using configured model"),r.onLog("system",s?`opencode session ${s}`:"opencode new session");let l=new Set,c=await Ft({command:t,args:Ce({frame:n,message:o,sessionId:s,model:i}),cwd:r.cwd,env:a,signal:r.abortSignal,onPartial:r.onPartial,onJson:m=>{let p=Ee(m);p&&l.add(p);let d=bt(m);d&&r.onLog("system",`[opencode:event] ${d}`);let g=W(L(m));return g?(r.onLog("stderr",`[opencode:error] ${g}`),g):null},onLog:r.onLog});return await Lt(u,c.output),{output:c.output||await Pt(u),sessionId:[...l].at(-1)??s}}async resolveCommand(){return v({command:"opencode",envVars:["OPENCODE_BIN"]})}};var Fe=class{runtimes=new Map;constructor(t){for(let n of t)this.runtimes.set(n.type,n)}get(t){let n=this.runtimes.get(t);if(!n)throw new Error(`runtime ${t} is not registered`);return n}detectable(){return[...this.runtimes.values()]}async detectCapabilities(){return Promise.all(this.detectable().map(async t=>{try{return{type:t.type,available:t.detect?await t.detect():!0,...t.capabilities}}catch{return{type:t.type,available:!1,...t.capabilities}}}))}};function _t(){return new Fe([new S,new A,new D,new P])}var H=class{runtimes=_t();publisher;runner;queue;constructor(t){this.publisher=new M(t),this.runner=new N(this.runtimes,this.publisher),this.queue=new T((n,r)=>{this.publisher.failed(n,r),this.publisher.status(n,"error")})}async deliver(t){await this.queue.enqueue(t,(n,r)=>this.runner.run(n,r))}cancelDelivery(t,n="cancelled_by_user"){this.queue.cancel(t,n)}handlePermissionResponse(t){}async detectAvailableRuntimes(){return(await this.detectRuntimeCapabilities()).filter(n=>n.available).map(n=>n.type)}async detectRuntimeCapabilities(){return(await this.runtimes.detectCapabilities()).map(n=>({...n,available:n.available}))}};var Q=class{frames=[];enqueue(t){return ar(t)?(this.frames.push(t),this.frames.length>200&&this.frames.splice(0,this.frames.length-200),!0):!1}drain(){return this.frames.splice(0)}get size(){return this.frames.length}};function ar(e){return e.type==="agent:delivery_ack"||e.type==="agent:message"||e.type==="agent:status"||e.type==="task:status"}var X=class{constructor(t){this.config=t}ws=null;reconnectAttempts=0;reconnectTimer=null;stopped=!1;outbox=new Q;agentManager=new H(t=>this.send(t));connect(){this.stopped=!1;let t=this.buildWebSocketUrl();this.ws=new Mt(t),this.ws.on("open",()=>{this.handleOpen()}),this.ws.on("message",n=>{let r=ur(n.toString());r&&this.handleFrame(r)}),this.ws.on("close",()=>{console.log("[Daemon] Disconnected"),this.ws=null,this.scheduleReconnect()}),this.ws.on("error",n=>{console.error(`[Daemon] WebSocket error: ${n.message}`)})}close(){this.stopped=!0,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws?.close()}async handleFrame(t){if(t.type==="ping"){this.send({type:"pong",requestId:t.requestId});return}if(t.type==="error"){console.error(`[Daemon] Server error ${t.code}: ${t.message}`),(t.code==="invalid_machine_key"||t.code==="machine_key_revoked")&&(this.stopped=!0);return}if(t.type==="agent:deliver"){await this.agentManager.deliver(t);return}if(t.type==="agent:cancel"){this.agentManager.cancelDelivery(t.deliveryId,t.reason);return}t.type==="permission:response"&&this.agentManager.handlePermissionResponse(t)}async handleOpen(){this.reconnectAttempts=0,console.log(`[Daemon] Connected to ${this.config.serverUrl}`);let t=await this.agentManager.detectRuntimeCapabilities();this.send({type:"machine:ready",daemonVersion:this.config.daemonVersion,hostname:this.config.hostname,os:this.config.os,arch:this.config.arch,availableRuntimes:t.filter(n=>n.available).map(n=>n.type),runtimeCapabilities:t}),this.flushOutbox()}send(t){this.sendNow(t)||this.stopped||this.outbox.enqueue(t)&&console.warn(`[Daemon] Queued ${t.type}; websocket is not open`)}sendNow(t){if(!this.ws||this.ws.readyState!==Mt.OPEN)return!1;try{return this.ws.send(JSON.stringify(t)),!0}catch{return!1}}flushOutbox(){if(this.outbox.size===0)return;let t=this.outbox.drain();console.log(`[Daemon] Flushing ${t.length} queued frame(s)`);for(let n of t)this.sendNow(n)||this.outbox.enqueue(n)}buildWebSocketUrl(){return`${this.config.serverUrl.replace(/^http/,"ws")}/daemon/connect?key=${encodeURIComponent(this.config.machineKey)}`}scheduleReconnect(){if(this.stopped||this.reconnectTimer)return;let t=Math.min(this.config.reconnectBaseMs*2**this.reconnectAttempts,3e4);this.reconnectAttempts+=1,console.log(`[Daemon] Reconnecting in ${t}ms`),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.stopped||this.connect()},t)}};function ur(e){try{return JSON.parse(e)}catch{return null}}function Tt(e=process.argv.slice(2)){if(e.includes("--help")||e.includes("-h"))return console.log(Z),null;Oe();let t=De(e);if(!t)return console.error(Z),process.exitCode=1,null;let n=new X(t);n.connect();let r=()=>{n.close(),process.exit(0)};return process.once("SIGINT",r),process.once("SIGTERM",r),n}Tt();
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "kslock-daemon",
3
+ "version": "0.1.1",
4
+ "description": "Local machine daemon for kslock agent collaboration.",
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "main": "dist/index.js",
8
+ "exports": {
9
+ ".": "./dist/index.js"
10
+ },
11
+ "bin": {
12
+ "kslock-daemon": "dist/index.js"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "engines": {
19
+ "node": ">=20"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "dependencies": {
25
+ "ws": "^8.18.0"
26
+ },
27
+ "devDependencies": {
28
+ "esbuild": "0.25.12",
29
+ "@types/ws": "^8.5.13"
30
+ },
31
+ "scripts": {
32
+ "dev": "KSLOCK_ENV=dev tsx watch src/index.ts",
33
+ "dev:local": "KSLOCK_ENV=dev tsx watch src/index.ts",
34
+ "clean": "node scripts/clean-dist.mjs",
35
+ "prebuild": "pnpm run clean",
36
+ "build": "node scripts/build.mjs",
37
+ "postbuild": "node scripts/prepare-dist.mjs",
38
+ "pack:check": "pnpm run build && node scripts/pack-smoke.mjs",
39
+ "release:publish": "pnpm publish --no-git-checks",
40
+ "release:patch": "pnpm version patch && pnpm publish --no-git-checks",
41
+ "release:minor": "pnpm version minor && pnpm publish --no-git-checks",
42
+ "release:major": "pnpm version major && pnpm publish --no-git-checks",
43
+ "typecheck": "tsc -p tsconfig.json --noEmit",
44
+ "test": "node ../../tests/run-node-tests.mjs tests/unit/daemon"
45
+ }
46
+ }