@agentdock/agent-runtime-core 0.0.97

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 (231) hide show
  1. package/dist/acpTypes.d.ts +171 -0
  2. package/dist/acpTypes.js +1 -0
  3. package/dist/adapters/dingtalk.d.ts +11 -0
  4. package/dist/adapters/dingtalk.js +7 -0
  5. package/dist/adapters/feishu.d.ts +13 -0
  6. package/dist/adapters/feishu.js +1 -0
  7. package/dist/adapters/webhookClient.d.ts +8 -0
  8. package/dist/adapters/webhookClient.js +1 -0
  9. package/dist/agentSettings.d.ts +42 -0
  10. package/dist/agentSettings.js +1 -0
  11. package/dist/agentSpawnTypes.d.ts +76 -0
  12. package/dist/agentSpawnTypes.js +1 -0
  13. package/dist/agentStderrPolicy.d.ts +6 -0
  14. package/dist/agentStderrPolicy.js +1 -0
  15. package/dist/boundedSet.d.ts +12 -0
  16. package/dist/boundedSet.js +1 -0
  17. package/dist/brand.d.ts +27 -0
  18. package/dist/brand.js +1 -0
  19. package/dist/checkpointService.d.ts +40 -0
  20. package/dist/checkpointService.js +2 -0
  21. package/dist/cli-arg-access.d.ts +1 -0
  22. package/dist/cli-arg-access.js +1 -0
  23. package/dist/cli-args.d.ts +75 -0
  24. package/dist/cli-args.js +1 -0
  25. package/dist/cli-handoff-args.d.ts +22 -0
  26. package/dist/cli-handoff-args.js +1 -0
  27. package/dist/constants.d.ts +1 -0
  28. package/dist/constants.js +1 -0
  29. package/dist/containerEnvPrompt.d.ts +1 -0
  30. package/dist/containerEnvPrompt.js +1 -0
  31. package/dist/contextUsageQuery.d.ts +14 -0
  32. package/dist/contextUsageQuery.js +1 -0
  33. package/dist/conversationRollback.d.ts +12 -0
  34. package/dist/conversationRollback.js +4 -0
  35. package/dist/debugMode.d.ts +2 -0
  36. package/dist/debugMode.js +1 -0
  37. package/dist/decodeChildOutput.d.ts +12 -0
  38. package/dist/decodeChildOutput.js +1 -0
  39. package/dist/dekMethods.d.ts +9 -0
  40. package/dist/dekMethods.js +1 -0
  41. package/dist/deployment.d.ts +16 -0
  42. package/dist/deployment.js +1 -0
  43. package/dist/deploymentBinding.d.ts +15 -0
  44. package/dist/deploymentBinding.js +1 -0
  45. package/dist/directEnvelopeDelivery.d.ts +27 -0
  46. package/dist/directEnvelopeDelivery.js +1 -0
  47. package/dist/envSanitize.d.ts +14 -0
  48. package/dist/envSanitize.js +2 -0
  49. package/dist/envelopeOutbound.d.ts +8 -0
  50. package/dist/envelopeOutbound.js +1 -0
  51. package/dist/fetchRetry.d.ts +9 -0
  52. package/dist/fetchRetry.js +1 -0
  53. package/dist/fileReceiver.d.ts +32 -0
  54. package/dist/fileReceiver.js +1 -0
  55. package/dist/fileWatcher.d.ts +1 -0
  56. package/dist/fileWatcher.js +1 -0
  57. package/dist/index.d.ts +1 -0
  58. package/dist/index.js +1 -0
  59. package/dist/ingest/claudePaths.d.ts +11 -0
  60. package/dist/ingest/claudePaths.js +1 -0
  61. package/dist/ingest/claudeSessionScanner.d.ts +11 -0
  62. package/dist/ingest/claudeSessionScanner.js +1 -0
  63. package/dist/ingest/index.d.ts +3 -0
  64. package/dist/ingest/index.js +1 -0
  65. package/dist/ingest/types.d.ts +82 -0
  66. package/dist/ingest/types.js +1 -0
  67. package/dist/jsonFileUtils.d.ts +3 -0
  68. package/dist/jsonFileUtils.js +1 -0
  69. package/dist/jsonlIndexService.d.ts +26 -0
  70. package/dist/jsonlIndexService.js +1 -0
  71. package/dist/jsonrpc-stdio.d.ts +52 -0
  72. package/dist/jsonrpc-stdio.js +3 -0
  73. package/dist/keepAlive.d.ts +45 -0
  74. package/dist/keepAlive.js +1 -0
  75. package/dist/knownProjects.d.ts +3 -0
  76. package/dist/knownProjects.js +1 -0
  77. package/dist/languageSettingsFile.d.ts +3 -0
  78. package/dist/languageSettingsFile.js +1 -0
  79. package/dist/lock.d.ts +12 -0
  80. package/dist/lock.js +1 -0
  81. package/dist/logger.d.ts +16 -0
  82. package/dist/logger.js +1 -0
  83. package/dist/messageQueue.d.ts +40 -0
  84. package/dist/messageQueue.js +1 -0
  85. package/dist/migration.d.ts +1 -0
  86. package/dist/migration.js +2 -0
  87. package/dist/modeLoop.d.ts +48 -0
  88. package/dist/modeLoop.js +1 -0
  89. package/dist/notificationChannels.d.ts +14 -0
  90. package/dist/notificationChannels.js +1 -0
  91. package/dist/notificationDispatcher.d.ts +11 -0
  92. package/dist/notificationDispatcher.js +1 -0
  93. package/dist/outbox.d.ts +49 -0
  94. package/dist/outbox.js +1 -0
  95. package/dist/paths.d.ts +24 -0
  96. package/dist/paths.js +1 -0
  97. package/dist/plaintextEnvelope.d.ts +5 -0
  98. package/dist/plaintextEnvelope.js +1 -0
  99. package/dist/processTree.d.ts +9 -0
  100. package/dist/processTree.js +5 -0
  101. package/dist/registerMachineOnConnect.d.ts +5 -0
  102. package/dist/registerMachineOnConnect.js +1 -0
  103. package/dist/responseLanguage.d.ts +5 -0
  104. package/dist/responseLanguage.js +5 -0
  105. package/dist/runtimeTargetGuard.d.ts +8 -0
  106. package/dist/runtimeTargetGuard.js +1 -0
  107. package/dist/sendClearedContextUsage.d.ts +4 -0
  108. package/dist/sendClearedContextUsage.js +1 -0
  109. package/dist/serverClient.d.ts +107 -0
  110. package/dist/serverClient.js +1 -0
  111. package/dist/serverClientEventHandlers.d.ts +6 -0
  112. package/dist/serverClientEventHandlers.js +1 -0
  113. package/dist/serverClientFactory.d.ts +3 -0
  114. package/dist/serverClientFactory.js +1 -0
  115. package/dist/serverClientTypes.d.ts +67 -0
  116. package/dist/serverClientTypes.js +1 -0
  117. package/dist/serverSettingsCache.d.ts +5 -0
  118. package/dist/serverSettingsCache.js +1 -0
  119. package/dist/session/backgroundTaskHandler.d.ts +29 -0
  120. package/dist/session/backgroundTaskHandler.js +1 -0
  121. package/dist/session/interactionDetector.d.ts +32 -0
  122. package/dist/session/interactionDetector.js +1 -0
  123. package/dist/session/modeHash.d.ts +6 -0
  124. package/dist/session/modeHash.js +1 -0
  125. package/dist/session/sessionBridge.d.ts +44 -0
  126. package/dist/session/sessionBridge.js +7 -0
  127. package/dist/session/sessionCompactBoundaryMapper.d.ts +17 -0
  128. package/dist/session/sessionCompactBoundaryMapper.js +1 -0
  129. package/dist/session/sessionMapper.d.ts +36 -0
  130. package/dist/session/sessionMapper.js +1 -0
  131. package/dist/session/sourceAgentRouting.d.ts +3 -0
  132. package/dist/session/sourceAgentRouting.js +1 -0
  133. package/dist/session/textAccumulator.d.ts +21 -0
  134. package/dist/session/textAccumulator.js +1 -0
  135. package/dist/session/turnTiming.d.ts +15 -0
  136. package/dist/session/turnTiming.js +1 -0
  137. package/dist/session/turnUsage.d.ts +17 -0
  138. package/dist/session/turnUsage.js +1 -0
  139. package/dist/session/workflowTracker.d.ts +63 -0
  140. package/dist/session/workflowTracker.js +1 -0
  141. package/dist/sessionBootstrap.d.ts +21 -0
  142. package/dist/sessionBootstrap.js +13 -0
  143. package/dist/sessionDeliveryDraft.d.ts +17 -0
  144. package/dist/sessionDeliveryDraft.js +1 -0
  145. package/dist/sessionDeliveryProtocol.d.ts +22 -0
  146. package/dist/sessionDeliveryProtocol.js +3 -0
  147. package/dist/sessionDeliverySubmit.d.ts +13 -0
  148. package/dist/sessionDeliverySubmit.js +1 -0
  149. package/dist/sessionDeliveryTool.d.ts +10 -0
  150. package/dist/sessionDeliveryTool.js +3 -0
  151. package/dist/sessionHandoffSystemPrompt.d.ts +10 -0
  152. package/dist/sessionHandoffSystemPrompt.js +3 -0
  153. package/dist/sessionMcpBootstrap.d.ts +13 -0
  154. package/dist/sessionMcpBootstrap.js +1 -0
  155. package/dist/sessionMcpInjection.d.ts +41 -0
  156. package/dist/sessionMcpInjection.js +1 -0
  157. package/dist/sessionMcpServer.d.ts +2 -0
  158. package/dist/sessionMcpServer.js +2 -0
  159. package/dist/sessionPrompt.d.ts +7 -0
  160. package/dist/sessionPrompt.js +3 -0
  161. package/dist/sessionRegistry.d.ts +42 -0
  162. package/dist/sessionRegistry.js +1 -0
  163. package/dist/sessionStatsCollector.d.ts +20 -0
  164. package/dist/sessionStatsCollector.js +1 -0
  165. package/dist/shellSanitizer.d.ts +1 -0
  166. package/dist/shellSanitizer.js +1 -0
  167. package/dist/shutdownHelper.d.ts +24 -0
  168. package/dist/shutdownHelper.js +1 -0
  169. package/dist/skillCache.d.ts +4 -0
  170. package/dist/skillCache.js +1 -0
  171. package/dist/skillParser.d.ts +20 -0
  172. package/dist/skillParser.js +6 -0
  173. package/dist/spawnConsole.d.ts +9 -0
  174. package/dist/spawnConsole.js +21 -0
  175. package/dist/startAbortHandler.d.ts +15 -0
  176. package/dist/startAbortHandler.js +1 -0
  177. package/dist/startAcpInitialPrompt.d.ts +51 -0
  178. package/dist/startAcpInitialPrompt.js +7 -0
  179. package/dist/startAcpPermission.d.ts +20 -0
  180. package/dist/startAcpPermission.js +1 -0
  181. package/dist/startAcpSwitchHelpers.d.ts +52 -0
  182. package/dist/startAcpSwitchHelpers.js +1 -0
  183. package/dist/startCancelTaskHandler.d.ts +17 -0
  184. package/dist/startCancelTaskHandler.js +1 -0
  185. package/dist/startCommandDaemonDebug.d.ts +8 -0
  186. package/dist/startCommandDaemonDebug.js +1 -0
  187. package/dist/startCommandRuntime.d.ts +162 -0
  188. package/dist/startCommandRuntime.js +5 -0
  189. package/dist/startCommandTypes.d.ts +33 -0
  190. package/dist/startCommandTypes.js +1 -0
  191. package/dist/startRpcHandler.d.ts +41 -0
  192. package/dist/startRpcHandler.js +1 -0
  193. package/dist/state.d.ts +29 -0
  194. package/dist/state.js +1 -0
  195. package/dist/statsAccumulator.d.ts +50 -0
  196. package/dist/statsAccumulator.js +1 -0
  197. package/dist/statsBuckets.d.ts +55 -0
  198. package/dist/statsBuckets.js +1 -0
  199. package/dist/subagentIds.d.ts +1 -0
  200. package/dist/subagentIds.js +1 -0
  201. package/dist/suggestedOptionsPrompt.d.ts +16 -0
  202. package/dist/suggestedOptionsPrompt.js +7 -0
  203. package/dist/taskTitle.d.ts +3 -0
  204. package/dist/taskTitle.js +1 -0
  205. package/dist/telemetryCollector.d.ts +15 -0
  206. package/dist/telemetryCollector.js +1 -0
  207. package/dist/terminalReset.d.ts +1 -0
  208. package/dist/terminalReset.js +1 -0
  209. package/dist/titleUpdater.d.ts +25 -0
  210. package/dist/titleUpdater.js +1 -0
  211. package/dist/tokenAuth.d.ts +6 -0
  212. package/dist/tokenAuth.js +1 -0
  213. package/dist/toolResultTruncation.d.ts +3 -0
  214. package/dist/toolResultTruncation.js +5 -0
  215. package/dist/transport.d.ts +13 -0
  216. package/dist/transport.js +1 -0
  217. package/dist/typeGuards.d.ts +7 -0
  218. package/dist/typeGuards.js +1 -0
  219. package/dist/userConfig.d.ts +5 -0
  220. package/dist/userConfig.js +1 -0
  221. package/dist/version.d.ts +1 -0
  222. package/dist/version.g.d.ts +1 -0
  223. package/dist/version.g.js +1 -0
  224. package/dist/version.js +1 -0
  225. package/dist/waitForConnection.d.ts +2 -0
  226. package/dist/waitForConnection.js +1 -0
  227. package/dist/windowsCommandShim.d.ts +6 -0
  228. package/dist/windowsCommandShim.js +1 -0
  229. package/dist/zombieReaper.d.ts +34 -0
  230. package/dist/zombieReaper.js +1 -0
  231. package/package.json +42 -0
@@ -0,0 +1,20 @@
1
+ import type { AgentMessage } from './acpTypes.js';
2
+ import type { StatsAccumulator } from './statsAccumulator.js';
3
+ import type { Logger } from './logger.js';
4
+
5
+ export interface SessionStatsCollectorOptions {
6
+ readonly accumulator: StatsAccumulator;
7
+ readonly logger?: Logger;
8
+ }
9
+
10
+ export interface SessionStatsCollector {
11
+
12
+ trackSession(sessionId: string, agentType: string, cwd: string): void;
13
+
14
+ onMessage(sessionId: string, msg: AgentMessage): void;
15
+
16
+ endSession(sessionId: string): void;
17
+
18
+ readonly dataPointCount: number;
19
+ }
20
+ export declare function createSessionStatsCollector(opts: SessionStatsCollectorOptions): SessionStatsCollector;
@@ -0,0 +1 @@
1
+ "use strict";export function createSessionStatsCollector(l){const{accumulator:s}=l,c=l.logger,a=new Map;let u=0;function p(o,e,t){a.set(o,{agentType:e,cwd:t,sessionId:o,toolCallCount:0}),c?.debug({sessionId:o,agentType:e,module:"daemon:usage"},"tracking session for stats")}function r(o,e){const t=a.get(o);if(t){if(e.type==="usage"){const n={model:e.model??`${t.agentType}-unknown`,inputTokens:e.inputTokens,outputTokens:e.outputTokens,cacheReadInputTokens:e.cacheReadTokens,cacheCreationInputTokens:e.cacheWriteTokens,timestamp:new Date().toISOString(),filePath:`session:${o}`,projectDir:t.cwd,toolCallCount:t.toolCallCount,agentType:t.agentType};n.inputTokens+n.outputTokens>0&&(s.addMessage(n),u++,t.toolCallCount=0)}if(e.type==="result"){const n=e.inputTokens??0,i=e.outputTokens??0;if(n+i>0){const C={model:`${t.agentType}-unknown`,inputTokens:n,outputTokens:i,cacheReadInputTokens:0,cacheCreationInputTokens:0,timestamp:new Date().toISOString(),filePath:`session:${o}`,projectDir:t.cwd,toolCallCount:t.toolCallCount,agentType:t.agentType};s.addMessage(C),u++,t.toolCallCount=0}}e.type==="tool-call"&&t.toolCallCount++}}function k(o){a.delete(o),c?.debug({sessionId:o,module:"daemon:usage"},"stopped tracking session for stats")}return{trackSession:p,onMessage:r,endSession:k,get dataPointCount(){return u}}}
@@ -0,0 +1 @@
1
+ export declare function sanitizeShell(shell: string | undefined): string;
@@ -0,0 +1 @@
1
+ "use strict";const i=new Set(["/bin/zsh","/bin/bash","/bin/sh","/usr/bin/zsh","/usr/bin/bash","/usr/bin/fish","/usr/bin/nu"]);export function sanitizeShell(n){return n?/^[A-Z]:\\Windows\\/i.test(n)||n.startsWith("/bin/")||n.startsWith("/usr/bin/")||i.has(n)?n:"custom":"unknown"}
@@ -0,0 +1,24 @@
1
+ export interface SessionInfo {
2
+ readonly pid: number;
3
+ readonly sessionId: string;
4
+ readonly agent: string;
5
+ }
6
+
7
+ export declare const PROCESS_EXIT_TIMEOUT_MS = 5000;
8
+
9
+ export declare function isAlive(pid: number): boolean;
10
+
11
+ export declare function waitForExit(pid: number, timeoutMs: number): Promise<boolean>;
12
+
13
+ export declare function stopLocalDaemon(pid: number, state: {
14
+ readonly httpPort: number;
15
+ readonly authToken?: string;
16
+ } | null, onStatus?: (msg: string) => void): Promise<boolean>;
17
+
18
+ export declare function fetchSessions(port: number, authToken: string): Promise<readonly SessionInfo[]>;
19
+
20
+ export declare function stopSession(port: number, authToken: string, sessionId: string): Promise<boolean>;
21
+
22
+ export declare function stopDaemonHttp(port: number, authToken: string): Promise<void>;
23
+
24
+ export declare function forceStopAllSessions(port: number, authToken: string, onStatus?: (msg: string) => void): Promise<void>;
@@ -0,0 +1 @@
1
+ "use strict";export const PROCESS_EXIT_TIMEOUT_MS=5e3;export function isAlive(t){try{return process.kill(t,0),!0}catch{return!1}}export async function waitForExit(t,e){const o=Date.now();for(;Date.now()-o<e;){if(!isAlive(t))return!0;await new Promise(s=>setTimeout(s,200))}try{process.kill(t,"SIGKILL")}catch{}return await new Promise(s=>setTimeout(s,200)),!isAlive(t)}export async function stopLocalDaemon(t,e,o){if(e?.authToken)await forceStopAllSessions(e.httpPort,e.authToken,o),await stopDaemonHttp(e.httpPort,e.authToken);else try{process.kill(t,"SIGTERM")}catch{}return waitForExit(t,5e3)}export async function fetchSessions(t,e){try{const o=await fetch(`http://127.0.0.1:${t}/sessions`,{headers:{Authorization:`Bearer ${e}`}});return o.ok?(await o.json()).sessions??[]:[]}catch{return[]}}export async function stopSession(t,e,o){try{return(await(await fetch(`http://127.0.0.1:${t}/rpc`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({method:"stop-session",params:{sessionId:o}})})).json()).ok}catch{return!1}}export async function stopDaemonHttp(t,e){try{await fetch(`http://127.0.0.1:${t}/stop`,{method:"POST",headers:{Authorization:`Bearer ${e}`}})}catch{}}export async function forceStopAllSessions(t,e,o){const s=await fetchSessions(t,e);if(s.length!==0){o?.(`Stopping ${s.length} active session(s)...`);for(const n of s)await stopSession(t,e,n.sessionId),await waitForExit(n.pid,5e3),o?.(`${n.agent} (PID: ${n.pid}) stopped`)}}
@@ -0,0 +1,4 @@
1
+ import type { SkillDefinition } from '@agentdock/wire';
2
+ export declare function discoverSkillsWithCache(projectCwds: readonly string[]): Record<string, SkillDefinition[]> | undefined;
3
+
4
+ export declare function clearSkillCache(): void;
@@ -0,0 +1 @@
1
+ "use strict";import{discoverSkills as i}from"./skillParser.js";let e=null,l=0;const r=6e4;export function discoverSkillsWithCache(c){const n=Date.now();if(e&&n-l<r)return e;try{const t=i(c);if(Object.keys(t).length>0)return e=t,l=n,t}catch{}return e??void 0}export function clearSkillCache(){e=null,l=0}
@@ -0,0 +1,20 @@
1
+ export interface ParsedSkill {
2
+ name: string;
3
+ description: string;
4
+ userInvocable: boolean;
5
+ }
6
+
7
+ export declare const AGENT_SKILL_DIRS: Record<string, {
8
+ user: () => readonly string[];
9
+ project: (cwd: string) => readonly string[];
10
+ }>;
11
+
12
+ export declare function parseSkillMd(filePath: string): ParsedSkill | null;
13
+
14
+ export declare function discoverSkills(projectCwds: readonly string[]): Record<string, {
15
+ name: string;
16
+ description: string;
17
+ userInvocable: boolean;
18
+ source: 'project' | 'user';
19
+ projectPath?: string;
20
+ }[]>;
@@ -0,0 +1,6 @@
1
+ "use strict";import f from"node:os";import t from"node:path";import{readFileSync as j,readdirSync as g,existsSync as S}from"node:fs";const b=new Set(["SKILL.md","skill.md"]);export const AGENT_SKILL_DIRS={claude:{user:()=>[t.join(f.homedir(),".claude","skills")],project:e=>[t.join(e,".claude","skills")]},hermes:{user:()=>[t.join(f.homedir(),".hermes","skills")],project:()=>[]},copilot:{user:()=>[t.join(f.homedir(),".copilot","skills")],project:e=>[t.join(e,".github","skills")]},gemini:{user:()=>[t.join(f.homedir(),".gemini","skills")],project:e=>[t.join(e,".gemini","skills")]},opencode:{user:()=>[t.join(f.homedir(),".config","opencode","skills")],project:e=>[t.join(e,".opencode","skills")]},openclaw:{user:()=>[t.join(f.homedir(),".openclaw","skills")],project:e=>[t.join(e,".agents","skills")]},codex:{user:()=>[t.join(f.homedir(),".agents","skills"),t.join(f.homedir(),".codex","skills")],project:e=>[t.join(e,".agents","skills"),t.join(e,".codex","skills")]}};function y(e,c,u){const r=[];let l=c+1;for(;l<e.length;){const n=e[l];if(n===void 0)break;const i=n.trimStart();if(i===""||n.length===i.length)break;if(i.startsWith("#")){l++;continue}r.push(i),l++}return u===">"?r.join(" "):r.join(`
2
+ `)}export function parseSkillMd(e){let c;try{c=j(e,"utf-8")}catch{return null}const u=c.replace(/\r\n/g,`
3
+ `).replace(/\r/g,`
4
+ `);if(!u.startsWith("---"))return null;const r=u.indexOf(`
5
+ ---`,3);if(r===-1)return null;const n=u.slice(4,r).split(`
6
+ `);let i="",s="",a=!0;for(let d=0;d<n.length;d++){const m=n[d];if(m===void 0||!m.trim()||m.trimStart().startsWith("#"))continue;const h=m.match(/^(\w+):\s*(.*)$/);if(!h)continue;const k=h[1];if(k===void 0)continue;let o=(h[2]??"").trim();switch((o===">"||o==="|")&&(o=y(n,d,o)),o.length>=2&&(o.startsWith('"')&&o.endsWith('"')||o.startsWith("'")&&o.endsWith("'"))&&(o=o.slice(1,-1)),k){case"name":i=o;break;case"description":s=o;break;case"user_invocable":a=o.toLowerCase()!=="false";break}}return!i||!s?null:{name:i,description:s,userInvocable:a}}function p(e,c,u){if(!S(e))return[];const r=[];let l;try{l=g(e,{withFileTypes:!0})}catch{return[]}for(const n of l)if(n.isDirectory()&&!(n.name.startsWith(".")&&n.name!==".system")){if(n.name===".system"){for(const i of p(t.join(e,n.name),c,u))r.push(i);continue}for(const i of b){const s=t.join(e,n.name,i),a=parseSkillMd(s);if(a){r.push({...a,source:c,projectPath:c==="project"?u:void 0});break}}}return r}export function discoverSkills(e){const c={};for(const[u,r]of Object.entries(AGENT_SKILL_DIRS)){const l=[];for(const s of r.user())for(const a of p(s,"user"))l.push(a);for(let s=e.length-1;s>=0;s--){const a=e[s];if(a)for(const d of r.project(a))for(const m of p(d,"project",a))l.push(m)}const n=new Set,i=[];for(const s of l.reverse())n.has(s.name)||(n.add(s.name),i.unshift(s));i.length>0&&(c[u]=i)}return c}
@@ -0,0 +1,9 @@
1
+ import { type ChildProcess } from 'node:child_process';
2
+
3
+ export declare function buildShellCommand(scripts: readonly string[], mainCmd: string): string;
4
+
5
+ export declare function spawnWithConsole(args: readonly string[], cwd: string, env: Record<string, string | undefined>, startupScripts?: readonly string[], useWindowsTerminal?: boolean): ChildProcess;
6
+
7
+ export declare function spawnDetached(args: readonly string[], cwd: string, env: Record<string, string | undefined>, startupScripts?: readonly string[]): ChildProcess;
8
+
9
+ export declare function cleanSpawnTmpFiles(): void;
@@ -0,0 +1,21 @@
1
+ "use strict";import u from"node:fs";import m from"node:path";import E from"node:os";import{randomUUID as O}from"node:crypto";import{spawn as d}from"node:child_process";import{getDaemonDir as P}from"./paths.js";import{getBrand as N}from"./brand.js";let w=null;function b(){if(w!==null)return w;try{const e=m.join(process.env.LOCALAPPDATA??m.join(E.homedir(),"AppData","Local"),"Microsoft","WindowsApps","wt.exe");u.accessSync(e,u.constants.X_OK),w=!0}catch{w=!1}return w}function x(e){return"'"+e.replace(/'/g,"'\\''")+"'"}function S(e){return"'"+e.replace(/'/g,"''")+"'"}function j(e){return'"'+e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'"'}export function buildShellCommand(e,t){return e.length===0?t:[...e,t].join(" && ")}function g(e,t,o,n,r){const i="& "+[e,...t].map(c=>S(c)).join(" "),s=r.includeConsoleFont?['try { Add-Type -TypeDefinition @"',"using System;","using System.Runtime.InteropServices;","public class ConsoleFont {"," [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]"," public struct CONSOLE_FONT_INFOEX {"," public uint cbSize;"," public uint nFont;"," public short dwFontSizeX;"," public short dwFontSizeY;"," public int FontFamily;"," public int FontWeight;"," [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]"," public string FaceName;"," }",' [DllImport("kernel32.dll", SetLastError = true)]'," static extern IntPtr GetStdHandle(int h);",' [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]'," static extern bool SetCurrentConsoleFontEx(IntPtr h, bool max, ref CONSOLE_FONT_INFOEX info);"," public static void Set(string name, short size) {"," var info = new CONSOLE_FONT_INFOEX();"," info.cbSize = (uint)Marshal.SizeOf(info);"," info.FaceName = name;"," info.dwFontSizeY = size;"," info.FontWeight = 400;"," SetCurrentConsoleFontEx(GetStdHandle(-11), false, ref info);"," }","}",'"@ } catch {}','[ConsoleFont]::Set("Consolas", 16)']:[];return["[Console]::OutputEncoding = [System.Text.Encoding]::UTF8","[Console]::InputEncoding = [System.Text.Encoding]::UTF8","$OutputEncoding = [System.Text.Encoding]::UTF8",...r.windowTitle?[`try { $host.UI.RawUI.WindowTitle = ${S(r.windowTitle)} } catch {}`]:[],...s,"try {"," Set-Location -LiteralPath "+S(o),...r.loadProfile?[" if (Test-Path $PROFILE) { . $PROFILE }"]:[],...n.map(c=>` ${c}`)," "+i,"} catch {",' Write-Host "Error: $_" -ForegroundColor Red'," exit 1","} finally {"," Remove-Item -LiteralPath $MyInvocation.MyCommand.Path -Force -ErrorAction SilentlyContinue","}","if ($LASTEXITCODE) { exit $LASTEXITCODE }"].join(`\r
2
+ `)+`\r
3
+ `}function C(e){const t=m.join(P(),"tmp");u.mkdirSync(t,{recursive:!0});for(let o=0;o<3;o++){const n=m.join(t,`spawn-${O()}.ps1`);try{return u.writeFileSync(n,`\uFEFF${e}`,{encoding:"utf8",flag:"wx"}),n}catch(r){if(!(typeof r=="object"&&r!==null&&"code"in r&&r.code==="EEXIST")||o===2)throw r}}throw new Error("unreachable: spawn script creation exhausted")}function L(e,t,o){const n=["-ExecutionPolicy","Bypass","-NoLogo","-NoProfile","-File",e],r="Start-Process -FilePath "+S("powershell.exe")+" -ArgumentList @("+n.map(i=>S(`"${i}"`)).join(", ")+") -WindowStyle Normal";return d("powershell.exe",["-NoLogo","-NoProfile","-Command",r],{stdio:"ignore",cwd:t,env:o,windowsHide:!0})}export function spawnWithConsole(e,t,o,n,r){if(process.platform==="win32"){const i=N().description;if(n&&n.length>0){const l=C(g(process.execPath,e,t,n,{includeConsoleFont:!0,loadProfile:!0,windowTitle:i}));return r&&b()?d("wt.exe",["-w","0","new-tab","--title",i,"--startingDirectory",t,"--","powershell.exe","-ExecutionPolicy","Bypass","-NoLogo","-NoProfile","-File",l],{detached:!0,stdio:"ignore",cwd:t,env:o}):L(l,t,o)}if(r&&b())return d("wt.exe",["-w","0","new-tab","--title",i,"--startingDirectory",t,"--",process.execPath,...e],{detached:!0,stdio:"ignore",cwd:t,env:o});const s=C(g(process.execPath,e,t,[],{includeConsoleFont:!0,loadProfile:!1,windowTitle:i}));return L(s,t,o)}if(process.platform==="darwin"){const i=Object.entries(o).filter(a=>a[0].startsWith("AGENTDOCK_")&&a[1]!==void 0).map(([a,y])=>`export ${a}=${x(y)}`).join("; "),s=[process.execPath,...e].map(a=>x(a)).join(" "),l=[i,`cd ${x(t)}`,"clear"].filter(Boolean),c=buildShellCommand(n??[],s),f=[...l,c].join(" && "),F=`tell application "Terminal"
4
+ activate
5
+ set t to do script ${j(f)}
6
+ set wId to id of window 1
7
+ end tell
8
+ delay 2
9
+ repeat
10
+ try
11
+ tell application "Terminal"
12
+ if busy of t is false then
13
+ close (first window whose id is wId)
14
+ exit repeat
15
+ end if
16
+ end tell
17
+ on error
18
+ exit repeat
19
+ end try
20
+ delay 1
21
+ end repeat`;return d("osascript",["-e",F],{detached:!0,stdio:"ignore",cwd:t,env:o})}if(n&&n.length>0){const i=process.env.SHELL||"/bin/sh",s=[process.execPath,...e].map(c=>x(c)).join(" "),l=buildShellCommand(n,`exec ${s}`);return d(i,["-lc",l],{detached:!0,stdio:"ignore",cwd:t,env:o})}return d(process.execPath,[...e],{detached:!0,stdio:"ignore",cwd:t,env:o})}export function spawnDetached(e,t,o,n){const r=m.join(E.tmpdir(),"agentdock-spawn-stderr.log"),i=u.openSync(r,"a"),s=()=>{try{u.closeSync(i)}catch{}};if(process.platform==="darwin"){const c=process.env.SHELL||"/bin/sh",f=Object.entries(o).filter(p=>p[0]!=="PATH"&&p[1]!==void 0).map(([p,T])=>`export ${p}=${x(T)}`).join("; "),F=[process.execPath,...e].map(p=>x(p)).join(" "),a=buildShellCommand(n??[],`exec ${F}`),y=[f,a].filter(Boolean).join("; "),h=d(c,["-lic",y],{cwd:t,env:o,detached:!0,stdio:["ignore","ignore",i]});return h.on("close",s),h.unref(),h}if(n&&n.length>0){if(process.platform==="linux"){const F=process.env.SHELL||"/bin/sh",a=[process.execPath,...e].map(p=>x(p)).join(" "),y=buildShellCommand(n,`exec ${a}`),h=d(F,["-lc",y],{cwd:t,env:o,detached:!0,stdio:["ignore","ignore",i]});return h.on("close",s),h.unref(),h}const c=C(g(process.execPath,e,t,n,{includeConsoleFont:!1,loadProfile:!0})),f=d("powershell.exe",["-ExecutionPolicy","Bypass","-NoLogo","-NoProfile","-File",c],{cwd:t,env:o,stdio:["ignore","ignore",i],windowsHide:!0});return f.on("close",s),f.unref(),f}const l=d(process.execPath,[...e],{cwd:t,env:o,detached:!0,stdio:["ignore","ignore",i],windowsHide:!0});return l.on("close",s),l.unref(),l}export function cleanSpawnTmpFiles(){const e=m.join(P(),"tmp");if(u.existsSync(e))for(const t of u.readdirSync(e)){if(!t.startsWith("spawn-"))continue;const o=m.join(e,t);try{u.unlinkSync(o)}catch{}}}
@@ -0,0 +1,15 @@
1
+ import type { Logger } from './logger.js';
2
+ import type { SessionSink } from '@agentdock/agent-runtime-contract/sessionSink';
3
+ import type { SendControlRequestFn } from './startCancelTaskHandler.js';
4
+ export interface AbortHandlerDeps {
5
+ readonly sessionId: string;
6
+ readonly serverClient: SessionSink | null;
7
+ readonly sendControlRequestRef: SendControlRequestFn;
8
+ readonly forceKillRef: {
9
+ current: (() => Promise<void>) | null;
10
+ };
11
+ readonly log: Logger;
12
+ }
13
+ export declare function createAbortHandler(deps: AbortHandlerDeps, abortPendingRef: {
14
+ current: boolean;
15
+ }): () => Promise<void>;
@@ -0,0 +1 @@
1
+ "use strict";export function createAbortHandler(e,t){return async()=>{const r=e.sendControlRequestRef.current;if(r){const n=r("interrupt",{}),o=new Promise((l,i)=>setTimeout(()=>i(new Error("interrupt timeout")),5e3));try{await Promise.race([n,o]),t.current=!0,e.log.info({sessionId:e.sessionId,module:"daemon:start"},"graceful interrupt acknowledged")}catch{e.log.warn({sessionId:e.sessionId,module:"daemon:start"},"graceful interrupt failed, falling back to force kill"),await e.forceKillRef.current?.()}}else e.forceKillRef.current?await e.forceKillRef.current():e.log.warn({sessionId:e.sessionId,module:"daemon:start"},"abort received but no interrupt channel and no backend to kill (forceKillRef null)");e.serverClient&&e.sessionId&&e.serverClient.sendSessionStatus(e.sessionId,"idle")}}
@@ -0,0 +1,51 @@
1
+ import type { SessionSink } from '@agentdock/agent-runtime-contract/sessionSink';
2
+ import type { MessageQueue } from './messageQueue.js';
3
+
4
+ export declare function buildAcpDeveloperInstructions(params: {
5
+ readonly agent: string;
6
+ readonly isScheduled: boolean;
7
+ readonly mergedSystemPrompt?: string;
8
+ }): string | undefined;
9
+ export declare function buildAcpInitialPrompt(params: {
10
+ readonly agent: string;
11
+ readonly initialPrompt?: string;
12
+ readonly appendSystemPrompt?: string;
13
+ readonly isScheduled: boolean;
14
+ }): string | undefined;
15
+
16
+ export declare function prepareAcpInitialPrompt(params: {
17
+ readonly agent: string;
18
+ readonly initialPrompt: string | undefined;
19
+ readonly mergedSystemPrompt: string | undefined;
20
+ readonly isScheduled: boolean;
21
+ readonly log: {
22
+ error: (obj: object, msg: string) => void;
23
+ };
24
+ }): Promise<string | undefined>;
25
+
26
+ export declare function startAcpBackendWithInitialPrompt(params: {
27
+ readonly agent: string;
28
+ readonly initialPrompt: string | undefined;
29
+ readonly mergedSystemPrompt: string | undefined;
30
+ readonly isScheduled: boolean;
31
+ readonly log: {
32
+ error: (obj: object, msg: string) => void;
33
+ };
34
+ readonly dispatch: Omit<DispatchInitialPromptParams, 'effectivePrompt'>;
35
+ readonly startBackend: () => Promise<void>;
36
+ }): Promise<boolean>;
37
+ export interface DispatchInitialPromptParams {
38
+ effectivePrompt: string | undefined;
39
+ initialPrompt: string | undefined;
40
+ serverClient: SessionSink | undefined;
41
+ sessionId: string | undefined;
42
+ messageQueue: MessageQueue;
43
+ sendMetadataUpdate: (update: Record<string, unknown>) => void;
44
+ resumeServerSessionId: string | undefined;
45
+ log: {
46
+ info: (obj: object, msg: string) => void;
47
+ error: (obj: object, msg: string) => void;
48
+ };
49
+ }
50
+
51
+ export declare function dispatchInitialPrompt(params: DispatchInitialPromptParams): boolean;
@@ -0,0 +1,7 @@
1
+ "use strict";import{createEnvelope as m,createId as g}from"@agentdock/wire";import{REMOTE_ENVIRONMENT_PROMPT as o,SUGGESTED_OPTIONS_PROMPT as u,withOpenCodeInstructions as S,writeOpenCodeInstructionsFile as h}from"./suggestedOptionsPrompt.js";export function buildAcpDeveloperInstructions(e){if(e.agent!=="codex"&&e.agent!=="pi")return;const t=e.isScheduled?[o]:[o,u];return e.mergedSystemPrompt&&t.push(e.mergedSystemPrompt),t.join(`
2
+
3
+ `)}export function buildAcpInitialPrompt(e){if(e.agent==="opencode"||e.agent==="codex"||e.agent==="pi")return e.initialPrompt;const t=e.isScheduled?[o]:[o,u];e.appendSystemPrompt&&t.push(e.appendSystemPrompt);const n=t.join(`
4
+
5
+ `);return e.initialPrompt?`${n}
6
+
7
+ ${e.initialPrompt}`:e.appendSystemPrompt?n:void 0}export async function prepareAcpInitialPrompt(e){if(e.agent==="opencode")try{await h(e.mergedSystemPrompt,e.isScheduled)}catch(t){e.log.error({err:t,module:"daemon:acp"},"failed to write opencode instructions file")}return buildAcpInitialPrompt({agent:e.agent,initialPrompt:e.initialPrompt,appendSystemPrompt:e.agent==="codex"||e.agent==="pi"?void 0:e.mergedSystemPrompt,isScheduled:e.isScheduled})}export async function startAcpBackendWithInitialPrompt(e){const t=async n=>{const i=dispatchInitialPrompt({...e.dispatch,effectivePrompt:n});return await e.startBackend(),i};return e.agent==="opencode"?S(e.mergedSystemPrompt,e.isScheduled,()=>t(buildAcpInitialPrompt(e))):t(await prepareAcpInitialPrompt(e))}export function dispatchInitialPrompt(e){const{effectivePrompt:t,initialPrompt:n,serverClient:i,sessionId:r,messageQueue:s,sendMetadataUpdate:l,resumeServerSessionId:p,log:d}=e;if(!t)return!1;const c=g();if(s.push(t,void 0,{messageUuid:c}),!n||!i||!r)return!1;const f=m("user",{t:"text",text:n},{messageUuid:c});return i.sendEnvelope(r,f).catch(P=>{d.error({err:P,module:"daemon:acp"},"failed to echo initial user message")}),p||l({title:n.slice(0,80)}),d.info({prompt:n.slice(0,80),module:"daemon:acp"},"initial prompt queued"),!0}
@@ -0,0 +1,20 @@
1
+ import type { AgentBackend } from './acpTypes.js';
2
+ import type { SessionSink } from '@agentdock/agent-runtime-contract/sessionSink';
3
+ import type { Logger } from './logger.js';
4
+ import type { MessageQueue } from './messageQueue.js';
5
+ import type { SessionBridge } from './session/sessionBridge.js';
6
+ export declare function createAcpPermissionHandler(deps: {
7
+ readonly serverClient: SessionSink;
8
+ readonly sessionId: string;
9
+ readonly log: Logger;
10
+ readonly agent: string;
11
+ readonly backend: AgentBackend;
12
+ readonly messageQueue: MessageQueue;
13
+ readonly bridgeRef: {
14
+ current: SessionBridge | undefined;
15
+ };
16
+
17
+ readonly onAllowedToolsChanged?: (rules: readonly string[]) => void;
18
+
19
+ readonly onAutoApproveEditsChanged?: () => void;
20
+ }): (requestId: string, approved: boolean, reason?: string, allowTools?: readonly string[], mode?: string, autoApproveEdits?: boolean, inputOverrides?: Record<string, unknown>) => void;
@@ -0,0 +1 @@
1
+ "use strict";import{createEnvelope as m}from"@agentdock/wire";const E=new Set(["copilot"]);export function createAcpPermissionHandler(s){return(r,o,n,e,c,p,g)=>{const{serverClient:d,sessionId:l,log:u,agent:a,backend:t,messageQueue:f,bridgeRef:h}=s;if(t.resolvePermission?.(r,o,n,g),o){if(e&&e.length>0){t.addAllowedTools?.(e);const i=t.getAllowedTools?.();i&&i.length>0&&s.onAllowedToolsChanged?.(i)}c&&t.setPermissionMode?.(c),p&&(t.setAutoApproveEdits?.(!0),s.onAutoApproveEditsChanged?.())}d.sendSessionStatus(l,"thinking");const v=o?c==="acceptEdits"?"approve-all-edits":e&&e.length?"approve-tool":"approve":"deny",A=m("agent",{t:"permission-resolved",requestId:r,action:v,...n?{reason:n}:{},...e?.length?{allowTools:[...e]}:{}});d.sendEnvelope(l,A).then(()=>{d.sendPermissionResolved(l,r),!o&&n&&E.has(a)&&(h.current?.skipNextIdle(),f.push(n,void 0,{echoToServer:!0}))}).catch(i=>{u.error({err:i,module:"daemon:acp"},"failed to send permission-resolved envelope")})}}
@@ -0,0 +1,52 @@
1
+ import type { AgentBackend } from './acpTypes.js';
2
+ import type { Logger } from './logger.js';
3
+ import type { SessionSink } from '@agentdock/agent-runtime-contract/sessionSink';
4
+
5
+ export interface AcpModeState {
6
+ currentModel: string | null;
7
+ pendingModelSwitch: string | null;
8
+ currentMode: string;
9
+ pendingModeSwitch: string | null;
10
+ pendingModeRevertTo: string | null;
11
+ }
12
+ export interface AnswerMetaDeps {
13
+ readonly agent: string;
14
+ readonly supportsNativeModeForward: boolean;
15
+ readonly backend: AgentBackend;
16
+ readonly log: Logger;
17
+ readonly sendMetadataUpdate: (patch: Record<string, unknown>) => void;
18
+ }
19
+
20
+ export declare function applyAnswerMetaChanges(state: AcpModeState, meta: {
21
+ model?: string;
22
+ permissionMode?: string;
23
+ } | undefined, deps: AnswerMetaDeps): string;
24
+
25
+ export interface SpawnPermissionMode {
26
+
27
+ readonly resolved: string;
28
+
29
+ readonly policyMode: string | null;
30
+
31
+ readonly supportsNativeModeForward: boolean;
32
+ }
33
+
34
+ export declare function resolveSpawnPermissionMode(agent: string, permissionMode: string): SpawnPermissionMode;
35
+
36
+ export type ModeRouting = {
37
+ readonly type: 'policy';
38
+ readonly policyMode: string;
39
+ } | {
40
+ readonly type: 'native';
41
+ } | {
42
+ readonly type: 'unsupported';
43
+ };
44
+
45
+ export declare function classifyModeChange(agent: string, requestedMode: string, supportsNativeModeForward: boolean): ModeRouting;
46
+ export declare function applyPendingModelSwitch(backend: AgentBackend, pendingModelSwitch: string | null, serverClient: SessionSink | undefined, sessionId: string | undefined, modelLabelMap: Map<string, string>, log: Logger, onSwitched?: (model: string) => void, onFailed?: (model: string) => void): Promise<string | null>;
47
+ export declare function applyPendingModeSwitch(backend: AgentBackend, pendingModeSwitch: string | null, serverClient: SessionSink | undefined, sessionId: string | undefined, modeLabelMap: Map<string, string>, log: Logger,
48
+
49
+ onFailed?: (mode: string) => void): Promise<string | null>;
50
+
51
+ export type CompactOutcome = 'compacted' | 'failed' | 'unsupported';
52
+ export declare function handleCompact(backend: AgentBackend, sendServiceEnvelope: (text: string) => void, sendMetadataUpdate: (patch: Record<string, unknown>) => void, log: Logger): Promise<CompactOutcome>;
@@ -0,0 +1 @@
1
+ "use strict";import{createEnvelope as s,createId as w,errorMessage as M,getAgentCapability as v,resolvePolicyMode as f}from"@agentdock/wire";export function applyAnswerMetaChanges(n,e,o){if(e?.model&&e.model!==(n.currentModel??"")?(n.pendingModelSwitch=e.model,o.log.info({model:e.model,currentModel:n.currentModel,module:"daemon:acp"},"model switch requested")):e?.model&&o.log.debug({model:e.model,currentModel:n.currentModel,module:"daemon:acp"},"model unchanged, skipping switch"),e?.permissionMode&&e.permissionMode!==n.currentMode){const d=classifyModeChange(o.agent,e.permissionMode,o.supportsNativeModeForward);if(d.type==="policy")n.currentMode=d.policyMode,o.backend.setPermissionMode?.(d.policyMode),o.sendMetadataUpdate({permissionMode:d.policyMode}),o.log.info({mode:d.policyMode,module:"daemon:acp"},"permission mode changed");else if(d.type==="native"){const r=n.currentMode;n.currentMode=e.permissionMode,o.sendMetadataUpdate({permissionMode:e.permissionMode}),o.log.info({mode:e.permissionMode,module:"daemon:acp"},"agent-native mode change requested"),n.pendingModeSwitch=e.permissionMode,n.pendingModeRevertTo=r}else o.log.warn({mode:e.permissionMode,agent:o.agent,module:"daemon:acp"},"agent does not support native mode forwarding; ignoring")}else e?.permissionMode&&o.log.debug({mode:e.permissionMode,currentMode:n.currentMode,module:"daemon:acp"},"permission mode unchanged, skipping");return w()}export function resolveSpawnPermissionMode(n,e){const o=f(n,e);return{resolved:o??e,policyMode:o,supportsNativeModeForward:v(n).supportsNativeModeForward}}export function classifyModeChange(n,e,o){const d=f(n,e);return d?{type:"policy",policyMode:d}:o?{type:"native"}:{type:"unsupported"}}export async function applyPendingModelSwitch(n,e,o,d,r,t,l,u){if(!e)return null;const i=!!n.switchModel;if(t.debug({pendingModelSwitch:e,hasSwitchModel:i,module:"daemon:acp"},"checking pending model switch"),i){const c=e;try{const a=await n.switchModel?.(c);if(t.info({model:c,ok:a,module:"daemon:acp"},"applied model switch"),a){if(l?.(c),o&&d){const m=s("agent",{t:"service",text:"model:switched:"+(r.get(c)??c)});o.sendEnvelope(d,m).catch(p=>{t.error({err:p,module:"daemon:acp"},"failed to send model switch envelope")})}}else if(u?.(c),t.warn({model:c,module:"daemon:acp"},"model switch returned false \u2014 configOption not found or RPC failed"),o&&d){const m=s("agent",{t:"service",text:"model:switch:failed:"+(r.get(c)??c)});o.sendEnvelope(d,m).catch(p=>{t.error({err:p,module:"daemon:acp"},"failed to send model switch failure envelope")})}}catch(a){if(u?.(c),t.error({err:a,module:"daemon:acp"},"failed to switch model via ACP"),o&&d){const m=r.get(c)??c,p=s("agent",{t:"service",text:"model:switch:failed:"+m});o.sendEnvelope(d,p).catch(h=>{t.error({err:h,module:"daemon:acp"},"failed to send model switch failure envelope")})}}return null}if(t.warn({pendingModelSwitch:e,module:"daemon:acp"},"backend.switchModel not available, discarding"),u?.(e),o&&d){const c=s("agent",{t:"service",text:"model:switch:failed:"+(r.get(e)??e)});o.sendEnvelope(d,c).catch(a=>{t.error({err:a,module:"daemon:acp"},"failed to send model switch failure envelope")})}return null}export async function applyPendingModeSwitch(n,e,o,d,r,t,l){if(!e)return null;const u=!!n.switchMode;if(t.debug({pendingModeSwitch:e,hasSwitchMode:u,module:"daemon:acp"},"checking pending mode switch"),u){const i=e,c=a=>{if(t.warn({mode:i,reason:a,module:"daemon:acp"},"mode switch failed"),l?.(i),o&&d){const m=s("agent",{t:"service",text:"mode:switch:failed:"+(r.get(i)??i)});o.sendEnvelope(d,m).catch(p=>{t.error({err:p,module:"daemon:acp"},"failed to send mode switch failure envelope")})}};try{const a=await n.switchMode?.(i);if(t.info({mode:i,ok:a,module:"daemon:acp"},"applied mode switch via ACP config option"),a&&o&&d){const m=s("agent",{t:"service",text:"mode:switched:"+(r.get(i)??i)});o.sendEnvelope(d,m).catch(p=>{t.error({err:p,module:"daemon:acp"},"failed to send mode switch envelope")})}else a||c("switchMode returned false \u2014 configOption not found or RPC failed")}catch(a){t.error({err:a,module:"daemon:acp"},"failed to switch mode via ACP"),c("switchMode threw")}return null}return t.warn({pendingModeSwitch:e,module:"daemon:acp"},"backend.switchMode not available, discarding"),l?.(e),null}export async function handleCompact(n,e,o,d){if(d.info({module:"daemon:acp"},"/compact received"),e("compact:started"),!n.compactThread)return"unsupported";const r=(l,u={})=>(d.warn({...u,reason:l,module:"daemon:acp"},"native compaction failed; /compact dropped"),e(`compact:failed:${l}`),"failed");let t;try{t=await n.compactThread()}catch(l){return r(M(l),{err:l})}return t.status==="compacted"?(d.info({newThreadId:t.threadId,module:"daemon:acp"},"native compaction succeeded"),o({claudeSessionId:t.threadId}),"compacted"):t.status==="aborted"?(d.info({module:"daemon:acp"},"native compaction aborted by the user"),"failed"):r(t.reason??"")}
@@ -0,0 +1,17 @@
1
+ import type { Logger } from './logger.js';
2
+ export interface SendControlRequestFn {
3
+ readonly current: ((subtype: string, params: Record<string, unknown>) => Promise<Record<string, unknown>>) | null;
4
+ }
5
+ export interface CancelTaskResult {
6
+ readonly ok: boolean;
7
+ readonly error?: string;
8
+ }
9
+
10
+ export interface CancelTaskHandlerOptions {
11
+ readonly sendControlRequestRef: SendControlRequestFn;
12
+ readonly sessionId: string;
13
+ readonly log: Logger;
14
+
15
+ readonly getWorkflowChildTaskIds?: () => ReadonlyMap<string, readonly string[]>;
16
+ }
17
+ export declare function createCancelTaskHandler(opts: CancelTaskHandlerOptions): (taskId: string) => Promise<CancelTaskResult>;
@@ -0,0 +1 @@
1
+ "use strict";import{parseWorkflowTaskId as i}from"./session/workflowTracker.js";export function createCancelTaskHandler(e){const{sendControlRequestRef:c}=e;return async o=>{const l=c.current;if(!l)return e.log.warn({taskId:o,sessionId:e.sessionId,module:"daemon:start"},"cancel-task: no backend to send control request"),{ok:!1,error:"no-backend"};const r=i(o);if(r!==null&&e.getWorkflowChildTaskIds){const n=e.getWorkflowChildTaskIds().get(r);if(!n||n.length===0)return e.log.warn({taskId:o,wfCallId:r,sessionId:e.sessionId,module:"daemon:start"},"cancel-task: Workflow has no active children"),{ok:!1,error:"no-children"};e.log.info({taskId:o,wfCallId:r,childCount:n.length,sessionId:e.sessionId,module:"daemon:start"},"cancelling Workflow with all children");let s=!0;for(const t of n)try{await l("stop_task",{task_id:t})}catch(d){e.log.error({err:d,taskId:o,childId:t,module:"daemon:start"},"cancel-task: failed to cancel Workflow child"),s=!1}return{ok:s}}e.log.info({taskId:o,sessionId:e.sessionId,module:"daemon:start"},"cancelling background task");try{return await l("stop_task",{task_id:o}),{ok:!0}}catch(a){return e.log.error({err:a,taskId:o,module:"daemon:start"},"cancel-task: sendControlRequest failed"),{ok:!1,error:"control-request-failed"}}}}
@@ -0,0 +1,8 @@
1
+ import type { Logger } from './logger.js';
2
+ interface DaemonDebugState {
3
+ httpPort: number;
4
+ authToken?: string;
5
+ }
6
+
7
+ export declare function applyDaemonDebugLevel(state: DaemonDebugState | undefined, log: Logger): Promise<void>;
8
+ export {};
@@ -0,0 +1 @@
1
+ "use strict";export async function applyDaemonDebugLevel(e,o){if(e)try{const t=await(await fetch(`http://127.0.0.1:${e.httpPort}/rpc`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.authToken??""}`},body:JSON.stringify({method:"get-debug",params:{}})})).json();t.ok===!0&&t.result?.enabled===!0&&(o.level="debug")}catch{}}
@@ -0,0 +1,162 @@
1
+ import { type SessionEnvelope } from '@agentdock/wire';
2
+ import type { SessionSink } from '@agentdock/agent-runtime-contract/sessionSink';
3
+ import { type KeepAlive, type LivenessHeartbeat, type SessionOwnershipLossReason } from './keepAlive.js';
4
+ type Mode = 'local' | 'remote';
5
+ interface MetadataLogger {
6
+ error(details: {
7
+ err: unknown;
8
+ module?: string;
9
+ }, message: string): void;
10
+ warn(details: Record<string, unknown>, message: string): void;
11
+ info(details: Record<string, unknown>, message: string): void;
12
+ }
13
+ interface PromptLogger {
14
+ info(details: Record<string, unknown>, message: string): void;
15
+ }
16
+ interface ModeChangeLogger {
17
+ info(details: Record<string, unknown>, message: string): void;
18
+ debug(details: Record<string, unknown>, message: string): void;
19
+
20
+ warn(details: Record<string, unknown>, message: string): void;
21
+ }
22
+
23
+ export type LocalNoticeEvent = 'remote-entered' | 'local-resumed';
24
+ interface ModeChangeOptions {
25
+ readonly mode: Mode;
26
+ readonly isInitial: boolean;
27
+ readonly previousMode: Mode | null;
28
+ readonly abortPending: boolean;
29
+ readonly keepAlive?: {
30
+ setMode(mode: Mode): void;
31
+ };
32
+ readonly scanner?: {
33
+ pause(): void;
34
+ resume(): void;
35
+ };
36
+ readonly stdinResume: {
37
+ listen(): void;
38
+ stop(): void;
39
+ };
40
+ readonly clearRemoteEnvelopes: () => void;
41
+ readonly clearQueuedMessages: () => void;
42
+ readonly serverClient?: SessionSink;
43
+ readonly sessionId?: string;
44
+ readonly sendMetadataUpdate: (patch: Record<string, unknown>) => void;
45
+
46
+ readonly noticeLocalUser: (event: LocalNoticeEvent) => void;
47
+ readonly log: ModeChangeLogger;
48
+ }
49
+ interface CleanupOptions {
50
+ readonly stdinResume: {
51
+ stop(): void;
52
+ };
53
+ readonly messageQueue: {
54
+ close(): void;
55
+ };
56
+ readonly scanner?: {
57
+ cleanup(): void;
58
+ releaseCurrentSession?(): void;
59
+ };
60
+ readonly keepAlive?: {
61
+ stop(): void;
62
+ };
63
+ readonly sessionId?: string;
64
+ readonly serverClient?: SessionSink;
65
+ readonly hookServer?: {
66
+ stop(): void;
67
+ };
68
+ readonly hookSettingsPath?: string;
69
+ readonly cleanupHookSettingsFile: (path: string) => Promise<void>;
70
+ readonly systemPromptFile?: string;
71
+
72
+ readonly daemonPid?: number;
73
+
74
+ readonly flushMetadata?: () => Promise<void>;
75
+
76
+ readonly shouldSendSessionEnd?: () => boolean;
77
+ }
78
+ interface EmergencyCleanupOptions extends CleanupOptions {
79
+ readonly markCleanedUp: () => boolean;
80
+ }
81
+ interface ExitLifecycleOptions {
82
+ readonly run: () => Promise<number>;
83
+ readonly onEmergencyExit: (code: number) => void;
84
+ readonly onAfterRun: () => Promise<void>;
85
+ }
86
+ export declare function createSessionOwnershipLossHandler(params: {
87
+ readonly sessionId: string;
88
+ readonly log: MetadataLogger;
89
+ readonly controllerRef: {
90
+ current: {
91
+ requestExit(): void;
92
+ } | null;
93
+ };
94
+ readonly reasonRef: {
95
+ current: SessionOwnershipLossReason | undefined;
96
+ };
97
+ }): (reason: SessionOwnershipLossReason) => void;
98
+ export declare function startSessionKeepAlive(params: {
99
+ readonly serverClient?: SessionSink;
100
+ readonly sessionId?: string;
101
+ readonly log: MetadataLogger;
102
+ readonly controllerRef: {
103
+ current: {
104
+ requestExit(): void;
105
+ } | null;
106
+ };
107
+ readonly reasonRef: {
108
+ current: SessionOwnershipLossReason | undefined;
109
+ };
110
+ }): {
111
+ keepAlive?: KeepAlive;
112
+ livenessHeartbeat?: LivenessHeartbeat;
113
+ };
114
+ export declare function createSessionMetadataUpdater(serverClient: SessionSink | undefined, sessionId: string | undefined, initialMeta: Record<string, unknown>, logger: MetadataLogger): {
115
+ update: (patch: Record<string, unknown>) => void;
116
+ flush: () => Promise<void>;
117
+ };
118
+ export declare function createRemoteEnvelopeSender(isRemote: () => boolean): {
119
+ clear(): void;
120
+ send(serverClient: SessionSink, sessionId: string, envelope: SessionEnvelope): Promise<void>;
121
+ };
122
+ export declare function queueInitialPrompt(serverClient: SessionSink | undefined, sessionId: string | undefined, initialPrompt: string | undefined, pushMessage: (text: string, messageUuid?: string) => void, sendMetadataUpdate: (patch: Record<string, unknown>) => void, logger: PromptLogger, skipTitle?: boolean): boolean;
123
+ export declare function applyModeChangeEffects({ mode, isInitial, previousMode, abortPending, keepAlive, scanner, stdinResume, clearRemoteEnvelopes, clearQueuedMessages, serverClient, sessionId, sendMetadataUpdate, noticeLocalUser, log, }: ModeChangeOptions): boolean;
124
+ export declare function runStartCommandCleanup(opts: CleanupOptions): Promise<void>;
125
+ export declare function createEmergencyCleanup(options: EmergencyCleanupOptions): () => Promise<void>;
126
+ export declare function runWithExitLifecycle({ run, onEmergencyExit, onAfterRun, }: ExitLifecycleOptions): Promise<number>;
127
+
128
+ export declare function echoUserEnvelopes(sc: SessionSink, sid: string, text: string, images: readonly {
129
+ data: string;
130
+ mediaType: string;
131
+ }[] | undefined, log: MetadataLogger, messageUuid?: string): void;
132
+
133
+ export declare function sendModeChangeEnvelopes(sc: SessionSink, sid: string, meta: {
134
+ model?: string;
135
+ permissionMode?: string;
136
+ } | undefined, currentMeta: {
137
+ model?: string;
138
+ permissionMode?: string;
139
+ }, log: MetadataLogger): void;
140
+
141
+ export declare function tryHotSwitch(sendControlRequestRef: {
142
+ current: ((subtype: string, params: Record<string, unknown>) => Promise<Record<string, unknown>>) | null;
143
+ }, meta: {
144
+ model?: string;
145
+ permissionMode?: string;
146
+ } | undefined, currentMeta: {
147
+ model?: string;
148
+ permissionMode?: string;
149
+ }, log: MetadataLogger, onPermissionModeSwitched?: (mode: string) => void): Promise<boolean>;
150
+
151
+ export declare function checkDaemonUpgrade(): {
152
+ exitCode: number;
153
+ } | undefined;
154
+
155
+ export declare function syncPermissionModeAfterApproval(approved: boolean, mode: string | undefined, currentRemoteMeta: {
156
+ permissionMode?: string;
157
+ }, sendMetadataUpdate: (fields: Record<string, unknown>) => void): {
158
+ permissionMode?: string;
159
+ };
160
+
161
+ export declare function loadAllowedToolsFromMeta(raw: unknown): readonly string[];
162
+ export {};
@@ -0,0 +1,5 @@
1
+ "use strict";import{killOwnChildProcessTrees as y}from"./processTree.js";import{createEnvelope as p,createId as M,errorMessage as g}from"@agentdock/wire";import{resetTerminalMouse as x}from"./terminalReset.js";import E from"node:fs/promises";import{getBrand as w}from"./brand.js";import{readDaemonState as T}from"./state.js";import{getStatePath as I}from"./paths.js";import{compareVersions as _}from"@agentdock/wire";import{VERSION as v}from"./version.js";import{isRecord as P}from"./typeGuards.js";import{createSessionKeepAliveSet as b}from"./keepAlive.js";export function createSessionOwnershipLossHandler(e){return r=>{e.reasonRef.current??=r,e.log.warn({sessionId:e.sessionId,reason:r,module:"daemon:start"},"session ownership lost; exiting CLI"),e.controllerRef.current?.requestExit()}}export function startSessionKeepAlive(e){if(!e.serverClient||!e.sessionId)return{};const r=createSessionOwnershipLossHandler({sessionId:e.sessionId,log:e.log,controllerRef:e.controllerRef,reasonRef:e.reasonRef});return b(e.serverClient,e.sessionId,void 0,r)}export function createSessionMetadataUpdater(e,r,n,t){let i=n,s=0,o=Promise.resolve();return{update:d=>{!e||!r||(i={...i,...d},o=o.then(async()=>{const c=s;try{await e.updateMetadata(r,JSON.stringify(i),c),s=c+1}catch(h){const u=P(h)?h.serverVersion:void 0;if(typeof u=="number"){t.warn({expectedVersion:c,serverVersion:u},"metadata version conflict, resyncing"),s=u;try{await e.updateMetadata(r,JSON.stringify(i),u),s=u+1}catch(S){t.error({err:S},"metadata resync retry failed")}}else t.error({err:h},"failed to update session metadata")}}))},flush:async()=>{let d;do d=o,await d;while(o!==d)}}}export function createRemoteEnvelopeSender(e){const r=new Set,n=t=>{if(!(!e()||!t.subagent))switch(t.ev.t){case"start":case"stop":case"tool-call-start":case"tool-call-end":return t.id;default:return}};return{clear(){r.clear()},async send(t,i,s){const o=n(s);if(!o){await t.sendEnvelope(i,s);return}if(!r.has(o)){r.add(o);try{await t.sendEnvelope(i,s)}catch(a){throw r.delete(o),a}}}}}export function queueInitialPrompt(e,r,n,t,i,s,o){if(!n||!e||!r)return!1;const a=M();return e.sendEnvelope(r,p("user",{t:"text",text:n},{messageUuid:a})).catch(()=>{}),t(n,a),o||i({title:n.slice(0,80)}),s.info({prompt:n.slice(0,80)},"initial prompt queued"),!0}export function applyModeChangeEffects({mode:e,isInitial:r,previousMode:n,abortPending:t,keepAlive:i,scanner:s,stdinResume:o,clearRemoteEnvelopes:a,clearQueuedMessages:m,serverClient:d,sessionId:c,sendMetadataUpdate:h,noticeLocalUser:u,log:S}){const f=e!==n;if(i?.setMode(e),e==="remote"?(s?.pause(),f&&u("remote-entered"),o.listen()):(a(),o.stop(),s?.resume(),m(),!r&&f&&u("local-resumed")),t){if(f&&h({mode:e}),d&&c&&(d.sendEnvelopeDirect(c,p("agent",{t:"turn-end",status:"cancelled"})).then(l=>{l.ok||S.warn({sessionId:c,error:l.error,module:"daemon:runtime"},"turn-end (cancelled) not synced")}).catch(l=>{S.warn({sessionId:c,err:l,module:"daemon:runtime"},"turn-end (cancelled) sync failed")}),f)){const l=e==="remote"?"mode:remote":"mode:local";d.sendEnvelope(c,p("agent",{t:"service",text:l})).catch(()=>{})}return S.debug({mode:e,isInitial:r,modeChanged:f,abortPending:!1,module:"daemon:runtime"},"mode changed"),!1}if(h({mode:e}),!r&&f&&d&&c){const l=e==="remote"?"mode:remote":"mode:local";d.sendEnvelope(c,p("agent",{t:"service",text:l})).catch(()=>{})}return S.info({mode:e,isInitial:r,modeChanged:f,abortPending:!1,module:"daemon:runtime"},"mode changed"),!1}export async function runStartCommandCleanup(e){if(e.stdinResume.stop(),x(),e.messageQueue.close(),e.scanner?.releaseCurrentSession?.(),e.scanner?.cleanup(),e.keepAlive?.stop(),e.flushMetadata)try{await Promise.race([e.flushMetadata(),new Promise(t=>setTimeout(t,2e3))])}catch{}if(e.sessionId&&e.serverClient&&(e.shouldSendSessionEnd?.()??!0))try{await Promise.race([e.serverClient.sendSessionEnd(e.sessionId),new Promise(t=>setTimeout(t,2e3))])}catch{}e.hookServer?.stop(),e.hookSettingsPath&&await e.cleanupHookSettingsFile(e.hookSettingsPath),e.systemPromptFile&&await E.unlink(e.systemPromptFile).catch(()=>{});const r=e.daemonPid?new Set([e.daemonPid]):void 0;y(r),e.serverClient?.disconnect()}export function createEmergencyCleanup(e){return async()=>{e.markCleanedUp()&&await runStartCommandCleanup(e)}}export async function runWithExitLifecycle({run:e,onEmergencyExit:r,onAfterRun:n}){const t=()=>r(130),i=()=>r(143),s=()=>r(129),o=()=>r(131);process.on("SIGINT",t),process.on("SIGTERM",i),process.on("SIGHUP",s),process.on("SIGQUIT",o);try{const a=await e();return await n(),a}catch(a){process.stderr.write(`FATAL: run() crashed: ${g(a)}
2
+ `);try{await n()}catch{}return 1}finally{process.removeListener("SIGINT",t),process.removeListener("SIGTERM",i),process.removeListener("SIGHUP",s),process.removeListener("SIGQUIT",o)}}export function echoUserEnvelopes(e,r,n,t,i,s){const o=t&&t.length>0;if(!n&&!o)return;const a=o?t.map(m=>({data:m.data,mediaType:m.mediaType})):void 0;e.sendEnvelope(r,p("user",{t:"text",text:n||"",...a?{images:a}:{}},{messageUuid:s})).catch(m=>{i.error({err:m,module:"daemon:runtime"},"failed to echo user message")})}export function sendModeChangeEnvelopes(e,r,n,t,i){if(n?.model&&n.model!==t.model){const s=p("agent",{t:"service",text:"model:switched:"+n.model});e.sendEnvelope(r,s).catch(o=>{i.error({err:o,module:"daemon:runtime"},"failed to send model switch envelope")})}if(n?.permissionMode&&n.permissionMode!==t.permissionMode){const s=p("agent",{t:"service",text:"permission:switched:"+n.permissionMode});e.sendEnvelope(r,s).catch(o=>{i.error({err:o,module:"daemon:runtime"},"failed to send permission switch envelope")})}}export async function tryHotSwitch(e,r,n,t,i){if(!e.current)return!1;if(!r)return!0;const s=e.current;try{return r.model&&r.model!==n.model&&(await s("set_model",{model:r.model}),t.info({module:"daemon:runtime",model:r.model},"hot-switched model via control_request")),r.permissionMode&&r.permissionMode!==n.permissionMode&&(await s("set_permission_mode",{mode:r.permissionMode}),i?.(r.permissionMode),t.info({module:"daemon:runtime",mode:r.permissionMode},"hot-switched permission mode via control_request")),!0}catch(o){return t.warn({err:o,module:"daemon:runtime"},"hot-switch via control_request failed, will fallback to restart"),!1}}export function checkDaemonUpgrade(){const e=T(I());if(e?.upgradeRequired)return process.stderr.write(`\x1B[31m\u2716 Server requires a newer daemon version.\x1B[0m
3
+ Run: ${w().binCommand} upgrade
4
+ `),{exitCode:1};e?.latestVersion&&_(v,e.latestVersion)<0&&process.stderr.write(`\x1B[33m\u26A0 Update available: v${v} \u2192 v${e.latestVersion}. Run: ${w().binCommand} upgrade\x1B[0m
5
+ `)}export function syncPermissionModeAfterApproval(e,r,n,t){return!e||!r||r===n.permissionMode?n:(t({permissionMode:r}),{...n,permissionMode:r})}export function loadAllowedToolsFromMeta(e){return Array.isArray(e)?e.every(r=>typeof r=="string")?e:[]:[]}
@@ -0,0 +1,33 @@
1
+ import type { Logger } from './logger.js';
2
+ export interface StartCommandOptions {
3
+
4
+ readonly agent?: string;
5
+ readonly cwd?: string;
6
+ readonly model?: string;
7
+ readonly permissionMode?: string;
8
+ readonly appendSystemPrompt?: string;
9
+
10
+ readonly mcpConfig?: string;
11
+ readonly resumeSessionId?: string;
12
+ readonly extraArgs?: readonly string[];
13
+ readonly logger?: Logger;
14
+ readonly serverEndpoint?: string;
15
+ readonly serverToken?: string;
16
+ readonly name?: string;
17
+
18
+ readonly source?: string;
19
+
20
+ readonly serverSessionId?: string;
21
+
22
+ readonly spawnToken?: string;
23
+
24
+ readonly takeoverToken?: string;
25
+
26
+ readonly sessionBootstrapFile?: string;
27
+
28
+ readonly registerBackendControl?: (id: string, fn: (subtype: string, params: Record<string, unknown>) => Promise<Record<string, unknown>>) => void;
29
+ readonly unregisterBackendControl?: (id: string) => void;
30
+ }
31
+ export interface StartCommandResult {
32
+ readonly exitCode: number;
33
+ }
@@ -0,0 +1 @@
1
+ "use strict";export{};
@@ -0,0 +1,41 @@
1
+ import type { CancelTaskResult } from './startCancelTaskHandler.js';
2
+ import type { Logger } from './logger.js';
3
+ type RpcResult = {
4
+ ok: true;
5
+ result: unknown;
6
+ } | {
7
+ ok: false;
8
+ error: string;
9
+ };
10
+
11
+ export declare const START_RPC_METHODS: readonly ["answer-question", "approve-permission", "deny-permission", "abort", "stop-session", "cancel-task", "get-context-usage"];
12
+
13
+ export interface RpcImageAttachment {
14
+ readonly data: string;
15
+ readonly mediaType: string;
16
+ }
17
+
18
+ export interface AnswerMeta {
19
+ readonly model?: string;
20
+ readonly permissionMode?: string;
21
+ }
22
+
23
+ export interface StartRpcDeps {
24
+ readonly sessionId: string;
25
+ readonly log?: Logger;
26
+
27
+ readonly onAnswerQuestion: (text: string, meta?: AnswerMeta, images?: readonly RpcImageAttachment[]) => Promise<void>;
28
+
29
+ readonly onAbort: () => Promise<void>;
30
+
31
+ readonly onStopSession: () => Promise<() => void>;
32
+
33
+ readonly onPermission?: (requestId: string, approved: boolean, reason?: string, allowTools?: readonly string[], mode?: string, autoApproveEdits?: boolean, inputOverrides?: Record<string, unknown>) => void;
34
+
35
+ readonly onCancelTask?: (taskId: string) => Promise<CancelTaskResult>;
36
+
37
+ readonly onGetContextUsage?: () => Promise<Record<string, unknown>>;
38
+ }
39
+ export type RpcRequestHandler = (method: string, params: Record<string, unknown>) => Promise<RpcResult>;
40
+ export declare function createStartRpcHandler(deps: StartRpcDeps): RpcRequestHandler;
41
+ export {};