@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,14 @@
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
+
5
+ export declare function unwrapContextUsageResponse(resp: Record<string, unknown>): Record<string, unknown>;
6
+ export declare function queryAndEmitContextUsage(sendRef: SendControlRequestFn, sc: SessionSink | undefined, sessionId: string | undefined, log: Logger): Promise<Record<string, unknown> | null>;
7
+
8
+ export declare function createContextUsageRefreshScheduler(options: {
9
+ readonly sendRef: SendControlRequestFn;
10
+ readonly sc: SessionSink;
11
+ readonly sessionId: string;
12
+ readonly log: Logger;
13
+ readonly waitForDelivery: () => Promise<boolean>;
14
+ }): () => void;
@@ -0,0 +1 @@
1
+ "use strict";export function unwrapContextUsageResponse(e){const t=e.response;return t!=null&&typeof t=="object"?t:e}export async function queryAndEmitContextUsage(e,t,n,r){const a=e.current;if(!a)return null;try{const o=await a("get_context_usage",{}),s=unwrapContextUsageResponse(o);return r.info({totalTokens:s.totalTokens,maxTokens:s.maxTokens,percentage:s.percentage,module:"daemon:start"},"context-usage data received from CLI"),t&&n&&t.sendContextUsage(n,s).catch(l=>{r.error({err:l,module:"daemon:start"},"failed to send context-usage to server")}),s}catch(o){return r.warn({err:o,module:"daemon:start"},"get_context_usage query failed"),null}}export function createContextUsageRefreshScheduler(e){let t=!1,n=null;const r=()=>{t=!0,!n&&(n=(async()=>{for(;t;){t=!1;try{if(!await e.waitForDelivery()){e.log.warn({sessionId:e.sessionId,module:"daemon:start"},"context-usage refresh skipped because lifecycle delivery is still pending");continue}}catch(a){e.log.warn({err:a,module:"daemon:start"},"context-usage delivery barrier failed");continue}await queryAndEmitContextUsage(e.sendRef,e.sc,e.sessionId,e.log)}})().finally(()=>{n=null,t&&r()}))};return r}
@@ -0,0 +1,12 @@
1
+ export declare function findMessageLineIndex(jsonlPath: string, messageId: string): Promise<number | null>;
2
+
3
+ export declare function truncateConversation(jsonlPath: string, messageId: string): Promise<{
4
+ truncatedCount: number;
5
+ pivotLine: number;
6
+ }>;
7
+
8
+ export declare function findMessageByTimestamp(jsonlPath: string, targetTimestamp: string): Promise<{
9
+ messageId: string;
10
+ lineIndex: number;
11
+ timestamp: string;
12
+ } | null>;
@@ -0,0 +1,4 @@
1
+ "use strict";import{createReadStream as p}from"node:fs";import{createInterface as d}from"node:readline";import{readFile as w,writeFile as I}from"node:fs/promises";import{isRecord as y}from"./typeGuards.js";export async function findMessageLineIndex(t,o){const e=d({input:p(t),crlfDelay:1/0});let s=0;for await(const n of e){s++;try{const i=JSON.parse(n);if(y(i)&&i.uuid===o)return s}catch{}}return null}export async function truncateConversation(t,o){const e=await findMessageLineIndex(t,o);if(e===null)throw new Error(`Message ${o} not found in ${t}`);const n=(await w(t,"utf-8")).split(`
2
+ `),i=n[n.length-1]===""?n.slice(0,-1):n,r=i.slice(0,e-1),a=i.length-r.length;return await I(t,r.join(`
3
+ `)+`
4
+ `,"utf-8"),{truncatedCount:a,pivotLine:e}}export async function findMessageByTimestamp(t,o){const e=new Date(o).getTime(),s=1e4,n=d({input:p(t),crlfDelay:1/0});let i=null,r=null,a=null,f=0;for await(const g of n){f++;try{const c=JSON.parse(g);if(!y(c))continue;const l=typeof c.timestamp=="string"?c.timestamp:void 0,u=typeof c.uuid=="string"?c.uuid:void 0;if(!l||!u)continue;a||(a={messageId:u,lineIndex:f,timestamp:l});const m=new Date(l).getTime();m<=e?i={messageId:u,lineIndex:f,timestamp:l}:m<=e+s&&!r&&(r={messageId:u,lineIndex:f,timestamp:l})}catch{}}return i??r??a??null}
@@ -0,0 +1,2 @@
1
+ export declare function isDebugEnabled(): boolean;
2
+ export declare function setDebugEnabled(enabled: boolean): void;
@@ -0,0 +1 @@
1
+ "use strict";let e=!1;export function isDebugEnabled(){return e}export function setDebugEnabled(n){e=n}
@@ -0,0 +1,12 @@
1
+ export declare function getOemCodePage(): number | null;
2
+ export interface StderrDecoder {
3
+
4
+ feed(chunk: Buffer): void;
5
+
6
+ finalize(): string;
7
+ }
8
+ export interface StderrDecoderOptions {
9
+
10
+ readonly oemCodePage?: number | null;
11
+ }
12
+ export declare function createStderrDecoder(opts?: StderrDecoderOptions): StderrDecoder;
@@ -0,0 +1 @@
1
+ "use strict";import{execSync as l}from"node:child_process";const a={932:"shift_jis",936:"gbk",949:"euc-kr",950:"big5"};let o;export function getOemCodePage(){if(o!==void 0)return o;if(process.platform!=="win32")return o=null,null;try{const n=l('powershell -NoProfile -Command "[System.Globalization.CultureInfo]::CurrentCulture.TextInfo.OEMCodePage"',{encoding:"utf-8",timeout:5e3,windowsHide:!0}).trim(),e=Number.parseInt(n,10);o=Number.isFinite(e)&&e>0?e:null}catch{o=null}return o}const s="\uFFFD";function c(n){let e=0;for(let t=0;t<n.length;t++)n[t]===s&&e++;return e}export function createStderrDecoder(n){const e=[];return{feed(t){e.push(t)},finalize(){if(e.length===0)return"";const t=Buffer.concat(e),r=t.toString("utf-8");if(c(r)===0)return r;const u=n?.oemCodePage!==void 0?n.oemCodePage:getOemCodePage();if(u===null||u===65001)return r;const i=a[u];if(!i)return r;try{const f=new TextDecoder(i,{fatal:!1}).decode(t);return c(f)<c(r)?f:r}catch{return r}}}}
@@ -0,0 +1,9 @@
1
+ import type { AgentdockClient } from '@agentdock/sdk';
2
+ import type { KeyManager } from '@agentdock/agent-runtime-contract/envelopeProtection';
3
+ import type { Logger } from './logger.js';
4
+
5
+ export declare function recoverSessionDek(keyManager: KeyManager | undefined, sessionId: string, wrappedDekBase64: string): Promise<boolean>;
6
+
7
+ export declare function provisionSessionDek(client: AgentdockClient, keyManager: KeyManager | undefined, log: Logger | undefined, sessionId: string): Promise<string | null>;
8
+
9
+ export declare function getSessionDek(keyManager: KeyManager | undefined, sessionId: string): Uint8Array | null;
@@ -0,0 +1 @@
1
+ "use strict";export async function recoverSessionDek(n,e,o){return n?n.unwrapAndSetSessionDek(e,o):!1}export async function provisionSessionDek(n,e,o,t){if(!e?.isEnabled)return null;try{const{dek:i,wrappedDekBase64:r}=await e.generateSessionKey(),u=await n.emitWithAck("provision-session-dek",{sessionId:t,dataEncryptionKey:r});if(!u?.ok)return null;const s=u.dataEncryptionKey??r;return s!==r?await e.unwrapAndSetSessionDek(t,s)?s:null:(e.setSessionDek(t,i),o?.info({sessionId:t,module:"daemon:server-client"},"DEK provisioned for session without encryption key"),r)}catch(i){return o?.error({err:i,sessionId:t,module:"daemon:server-client"},"failed to provision DEK"),null}}export function getSessionDek(n,e){return n?.getSessionDek(e)??null}
@@ -0,0 +1,16 @@
1
+ import type { Edition } from '@agentdock/wire';
2
+ export interface Deployment {
3
+
4
+ readonly edition: Edition;
5
+
6
+ readonly dataDirSuffix: string;
7
+
8
+ readonly extraWorkspaceRoot: string | null;
9
+
10
+ readonly defaultProfile: string;
11
+ }
12
+
13
+ export declare function configureDeployment(deployment: Deployment): void;
14
+
15
+ export declare function resetDeployment(): void;
16
+ export declare function getDeployment(): Deployment;
@@ -0,0 +1 @@
1
+ "use strict";let e;export function configureDeployment(t){e=t}export function resetDeployment(){e=void 0}export function getDeployment(){if(!e)throw new Error("deployment not configured \u2014 the process entry (cli.ts / daemonEntry.ts) must call bindDeploymentFromEdition() before anything reads paths");return e}
@@ -0,0 +1,15 @@
1
+ import type { Deployment } from './deployment.js';
2
+
3
+ export declare const ENTERPRISE_EXTRA_WORKSPACE = "/workspace";
4
+
5
+ export declare function detectDefaultProfile(moduleUrl: string): string;
6
+
7
+ export interface DeploymentInputs {
8
+
9
+ readonly edition: Deployment['edition'];
10
+
11
+ readonly platform: NodeJS.Platform;
12
+
13
+ readonly moduleUrl: string;
14
+ }
15
+ export declare function createDeployment(inputs: DeploymentInputs): Deployment;
@@ -0,0 +1 @@
1
+ "use strict";export const ENTERPRISE_EXTRA_WORKSPACE="/workspace";export function detectDefaultProfile(e){return e.includes("node_modules")||e.includes("/dist/")||e.includes("\\dist\\")?"":"dev"}export function createDeployment(e){const t=e.edition==="enterprise";return{edition:e.edition,dataDirSuffix:t?"-enterprise":"",extraWorkspaceRoot:t&&e.platform!=="win32"?ENTERPRISE_EXTRA_WORKSPACE:null,defaultProfile:detectDefaultProfile(e.moduleUrl)}}
@@ -0,0 +1,27 @@
1
+ import type { AgentdockClient } from '@agentdock/sdk';
2
+ import type { SessionEnvelope } from '@agentdock/wire';
3
+ import type { EnvelopeContent } from '@agentdock/agent-runtime-contract/envelopeProtection';
4
+ import type { EnqueueResult, OutboxStats, PendingMessage } from './outbox.js';
5
+ import type { Logger } from './logger.js';
6
+
7
+ export interface DeliveryQueue {
8
+ readonly enqueue: (msg: PendingMessage) => EnqueueResult;
9
+ readonly getStats: () => OutboxStats;
10
+ readonly hasPending: (sessionId: string) => boolean;
11
+ }
12
+ export interface DirectEnvelopeDeliveryDeps {
13
+ readonly client: AgentdockClient;
14
+ readonly outbox: DeliveryQueue;
15
+ readonly serialize: (sessionId: string, envelope: SessionEnvelope) => Promise<EnvelopeContent | null>;
16
+ readonly canWriteSession: (sessionId: string) => boolean;
17
+ readonly log?: Logger | undefined;
18
+ }
19
+ export interface DirectEnvelopeAck {
20
+ readonly ok: boolean;
21
+ readonly error?: string;
22
+ readonly seq?: number;
23
+ }
24
+
25
+ export declare function createDirectEnvelopeDelivery(deps: DirectEnvelopeDeliveryDeps): (sessionId: string, envelope: SessionEnvelope, opts?: {
26
+ readonly skipBroadcast?: boolean;
27
+ }) => Promise<DirectEnvelopeAck>;
@@ -0,0 +1 @@
1
+ "use strict";export function createDirectEnvelopeDelivery(l){const{client:c,outbox:t,serialize:u,canWriteSession:d,log:o}=l;return async function(e,r,a){const n=await u(e,r);if(!n)return o?.warn({sessionId:e,module:"daemon:serverClient"},"sendEnvelopeDirect: no DEK available"),{ok:!1,error:"no-dek"};if(!d(e)||t.hasPending(e)){const i=t.enqueue({sessionId:e,localId:r.id,content:n,skipBroadcast:a?.skipBroadcast,retries:0});return i.ok?(o?.info({sessionId:e,localId:r.id,module:"daemon:server-client"},"sendEnvelopeDirect: queued for redelivery"),{ok:!0}):(o?.warn({sessionId:e,localId:r.id,reason:i.reason,...t.getStats(),module:"daemon:server-client"},"sendEnvelopeDirect: outbox full, envelope refused (conversation content not queued)"),{ok:!1,error:"outbox-full"})}return c.emitWithAck("message",{sessionId:e,localId:r.id,content:n,...a?.skipBroadcast?{skipBroadcast:!0}:{}})}}
@@ -0,0 +1,14 @@
1
+ export declare function getAllowedAgentdockEnvVars(): readonly string[];
2
+ export declare function stripSessionEnv(env: Record<string, string | undefined>): Record<string, string | undefined>;
3
+
4
+ export declare function waitForFirstEnvPoll(): Promise<void>;
5
+
6
+ export declare function initEnvRefresh(): void;
7
+
8
+ export declare function stopEnvRefresh(): void;
9
+
10
+ export declare function refreshOsEnv(existingEnv: Record<string, string | undefined>): Record<string, string | undefined>;
11
+
12
+ export declare function pickRefreshedVars(): Record<string, string>;
13
+
14
+ export declare function parseRegOutput(output: string): Record<string, string>;
@@ -0,0 +1,2 @@
1
+ "use strict";import{spawn as _,execSync as R}from"node:child_process";const m=new Set(["AGENTDOCK_SERVER","AGENTDOCK_SERVER_URL","AGENTDOCK_PROFILE","AGENTDOCK_NPM_PACKAGE","AGENTDOCK_DISPLAY_NAME","AGENTDOCK_USERNAME","AGENTDOCK_WEB_URL","AGENTDOCK_NO_AUTOSTART","AGENTDOCK_SCRIPTED_DIR"]);export function getAllowedAgentdockEnvVars(){return[...m]}export function stripSessionEnv(e){const t={...e};for(const n of Object.keys(t)){const o=n.toUpperCase();!o.startsWith("AGENTDOCK_")||m.has(o)||delete t[n]}return t}let c=null,f=null,a=!1;const T=6e4,p=8e3;let l=null,O=new Promise(e=>{l=e}),u=!1,d=!1;export function waitForFirstEnvPoll(){return d?O:Promise.resolve()}function S(){const e={...process.env};if(process.platform!=="win32")return e;try{const t=R("reg query HKCU\\Environment",{encoding:"utf-8",timeout:3e3,windowsHide:!0,stdio:["ignore","pipe","ignore"]});Object.assign(e,parseRegOutput(t))}catch{}return e}export function initEnvRefresh(){d=!0,f===null&&(c=S(),process.platform==="win32"?(f=setInterval(A,T),f.unref(),A()):(f=setInterval(w,T),f.unref(),w()))}export function stopEnvRefresh(){f&&(clearInterval(f),f=null),a=!1,c=null,d=!1,u||(u=!0,l?.()),O=new Promise(e=>{l=e}),u=!1}export function refreshOsEnv(e){return c?{...e,...c}:e}const h=["ANTHROPIC_","COPILOT_","GEMINI_","HERMES_","GITHUB_"];export function pickRefreshedVars(){const e={};if(!c)return e;for(const[t,n]of Object.entries(c)){if(t.toLowerCase()==="path"||n===void 0)continue;const o=t.toUpperCase();h.some(r=>o.startsWith(r))&&(e[t]=n)}return e}function v(e,t){return new Promise((n,o)=>{const r=_("reg",["query",e],{windowsHide:!0,stdio:["ignore","pipe","ignore"]});let s="";const E=setTimeout(()=>{r.kill(),o(new Error("timeout"))},t);r.stdout?.on("data",i=>{s+=i.toString()}),r.on("close",i=>{clearTimeout(E),i===0&&s?n(s):o(new Error(`reg query exited ${i}`))}),r.on("error",i=>{clearTimeout(E),o(i)})})}export function parseRegOutput(e){const t={};for(const n of e.split(/\r?\n/)){const o=n.match(/^\s{4}(\S+)\s+REG_\w+\s+(.+)/);if(!o)continue;const r=o[1]??"",s=(o[2]??"").trim();!r||!s||r.toLowerCase()!=="path"&&(/%[^%]+%/.test(s)||(t[r]=s))}return t}async function A(){if(!a){a=!0;try{const e={...c};try{const n=await v("HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",p);Object.assign(e,parseRegOutput(n))}catch{}const t=await v("HKCU\\Environment",p);Object.assign(e,parseRegOutput(t)),c=e,!u&&l&&(u=!0,l())}catch{!u&&l&&(u=!0,l())}finally{a=!1}}}function C(e){return new Promise((t,n)=>{const o=process.env.SHELL||"/bin/sh",r=_(o,["-lic","env 2>/dev/null"],{stdio:["ignore","pipe","ignore"],env:process.env,detached:!0});let s="";const E=setTimeout(()=>{r.kill(),n(new Error("timeout"))},e);r.stdout?.on("data",i=>{s+=i.toString()}),r.on("close",i=>{clearTimeout(E),i===0&&s?t(s):n(new Error(`login shell exited ${i}`))}),r.on("error",i=>{clearTimeout(E),n(i)})})}async function w(){if(!a){a=!0;try{const e=await C(p),t={...c};for(const n of e.split(`
2
+ `)){const o=n.indexOf("=");o<=0||(t[n.slice(0,o)]=n.slice(o+1))}c=t,t.PATH&&(process.env.PATH=t.PATH),!u&&l&&(u=!0,l())}catch{!u&&l&&(u=!0,l())}finally{a=!1}}}
@@ -0,0 +1,8 @@
1
+ import type { SessionEnvelope } from '@agentdock/wire';
2
+ import type { EnvelopeContent, EnvelopeKeyManager, KeyManager } from '@agentdock/agent-runtime-contract/envelopeProtection';
3
+ import type { Logger } from './logger.js';
4
+ export interface EnvelopeOutbound {
5
+ readonly keys: KeyManager | undefined;
6
+ serializeEnvelope(sessionId: string, envelope: SessionEnvelope): Promise<EnvelopeContent | null>;
7
+ }
8
+ export declare function createEnvelopeOutbound(envelope: EnvelopeKeyManager | undefined, log?: Logger): EnvelopeOutbound;
@@ -0,0 +1 @@
1
+ "use strict";export function createEnvelopeOutbound(e,d){return e?{keys:e.kind==="encrypted"?e.keys:void 0,serializeEnvelope:(n,r)=>e.serialize(n,r)}:{keys:void 0,async serializeEnvelope(n,r){return d?.error({sessionId:n,localId:r.id,module:"daemon:server-client"},"SECURITY: envelope port not bound \u2014 envelope dropped"),null}}}
@@ -0,0 +1,9 @@
1
+ export declare function isTransientError(err: unknown): boolean;
2
+
3
+ export declare const FETCH_TIMEOUT_MS = 30000;
4
+
5
+ export declare function delay(ms: number): Promise<void>;
6
+
7
+ export declare function fetchWithRetry(url: string, options: RequestInit, retries: number, timeoutMs: number, onRetry?: (attempt: number, maxRetries: number) => void): Promise<Response>;
8
+
9
+ export { delay as retryDelay };
@@ -0,0 +1 @@
1
+ "use strict";import{errorMessage as s}from"@agentdock/wire";export function isTransientError(t){const e=s(t).toLowerCase();return e.includes("fetch failed")||e.includes("timeout")||e.includes("etimedout")||e.includes("econnrefused")||e.includes("econnreset")||e.includes("enotfound")||e.includes("und_err_connect_timeout")||e.includes("network")||e.includes("aborted")}export const FETCH_TIMEOUT_MS=3e4;export function delay(t){return new Promise(r=>setTimeout(r,t))}export async function fetchWithRetry(t,r,e,c,i){for(let n=1;n<=e;n++)try{return await fetch(t,{...r,signal:AbortSignal.timeout(c)})}catch(o){if(n===e||!isTransientError(o))throw o;i?.(n,e),await delay(Math.min(n*2e3,1e4))}throw new Error("unreachable")}export{delay as retryDelay};
@@ -0,0 +1,32 @@
1
+ import type { Logger } from './logger.js';
2
+ export interface ChunkPayload {
3
+ readonly chunkId: number;
4
+ readonly fileId: string;
5
+ readonly sessionId: string;
6
+ readonly data: Uint8Array;
7
+ readonly isLast: boolean;
8
+ readonly totalChunks: number;
9
+ readonly filename?: string;
10
+ readonly sha256?: string;
11
+ }
12
+ export interface ChunkResult {
13
+ readonly ok: boolean;
14
+ readonly error?: string;
15
+ readonly chunkId?: number;
16
+ }
17
+ export interface CompleteResult {
18
+ readonly ok: boolean;
19
+ readonly error?: string;
20
+ readonly filePath?: string;
21
+ readonly size?: number;
22
+ }
23
+ export interface FileReceiverDeps {
24
+ readonly maxFileSize: number;
25
+ readonly logger?: Logger;
26
+ readonly allowedExtensions?: readonly string[];
27
+ }
28
+ export declare function createFileReceiver(deps: FileReceiverDeps): {
29
+ handleChunk: (payload: ChunkPayload) => Promise<ChunkResult>;
30
+ complete: (sessionId: string, fileId: string) => Promise<CompleteResult>;
31
+ cancel: (sessionId: string, fileId: string) => void;
32
+ };
@@ -0,0 +1 @@
1
+ "use strict";import S from"node:crypto";import g from"node:fs/promises";import $ from"node:os";import d from"node:path";export function createFileReceiver(w){const{maxFileSize:v,logger:a,allowedExtensions:h}=w,s=new Map,p=new Set;function x(n){if(!h||h.length===0)return!0;const e=d.extname(n).toLowerCase();return h.includes(e)}async function R(n){const{chunkId:e,fileId:i,sessionId:r,data:o,totalChunks:c,filename:l,sha256:f}=n,u=`${r}:${i}`;if(p.has(i))return a?.warn({fileId:i,sessionId:r,module:"daemon:fileReceiver"},"duplicate fileId rejected"),{ok:!1,error:"duplicate-file-id"};let t=s.get(u);if(!t){if(!l||!f)return a?.warn({fileId:i,sessionId:r,module:"daemon:fileReceiver"},"missing filename or sha256 in first chunk"),{ok:!1,error:"missing-filename-or-sha256"};if(!x(l))return a?.warn({fileId:i,sessionId:r,filename:l,module:"daemon:fileReceiver"},"unsupported file extension"),{ok:!1,error:"unsupported-file-type"};t={chunks:new Map,filename:l,sha256:f,totalChunks:c,totalSize:0},s.set(u,t)}return t.totalSize+o.length>v?(s.delete(u),a?.warn({fileId:i,sessionId:r,size:t.totalSize+o.length,module:"daemon:fileReceiver"},"file exceeds size limit"),{ok:!1,error:"file-too-large"}):(t.chunks.set(e,o),t.totalSize+=o.length,{ok:!0,chunkId:e})}async function z(n,e){const i=`${n}:${e}`,r=s.get(i);if(!r)return a?.warn({fileId:e,sessionId:n,module:"daemon:fileReceiver"},"complete: no active transfer"),{ok:!1,error:"no-active-transfer"};try{const o=[];for(let m=0;m<r.totalChunks;m++){const k=r.chunks.get(m);if(!k)return a?.warn({fileId:e,sessionId:n,chunkIndex:m,module:"daemon:fileReceiver"},"complete: missing chunk"),{ok:!1,error:`missing-chunk:${m}`};o.push(k)}const c=Buffer.concat(o),l=S.createHash("sha256").update(c).digest("hex");if(l!==r.sha256)return a?.warn({fileId:e,expected:r.sha256,actual:l,module:"daemon:fileReceiver"},"SHA-256 mismatch"),{ok:!1,error:"sha256-mismatch"};const f=$.tmpdir();await g.mkdir(f,{recursive:!0});const u=d.basename(r.filename),t=d.join(f,u);return d.dirname(t)!==f?(a?.warn({fileId:e,filename:r.filename,module:"daemon:fileReceiver"},"rejected filename resolving outside destination dir"),{ok:!1,error:"invalid-filename"}):(await g.writeFile(t,c),p.add(e),s.delete(i),a?.info({fileId:e,sessionId:n,size:c.length,path:t,originalName:r.filename,module:"daemon:fileReceiver"},"file received and written"),{ok:!0,filePath:t,size:c.length})}catch(o){return a?.error({err:o,fileId:e,sessionId:n,module:"daemon:fileReceiver"},"file completion failed"),{ok:!1,error:"write-failed"}}}function y(n,e){const i=`${n}:${e}`;s.delete(i)}return{handleChunk:R,complete:z,cancel:y}}
@@ -0,0 +1 @@
1
+ export declare function startFileWatcher(file: string, onChange: () => void): () => void;
@@ -0,0 +1 @@
1
+ "use strict";import{watch as n}from"node:fs/promises";const o=1e3;export function startFileWatcher(e,a){const t=new AbortController;return(async()=>{for(;!t.signal.aborted;)try{const r=n(e,{persistent:!0,signal:t.signal});for await(const i of r){if(t.signal.aborted)return;a()}}catch{if(t.signal.aborted)return;await new Promise(r=>setTimeout(r,o))}})(),()=>{t.abort()}}
@@ -0,0 +1 @@
1
+ export { BoundedSet } from './boundedSet.js';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";export{BoundedSet}from"./boundedSet.js";
@@ -0,0 +1,11 @@
1
+ export declare function getClaudeHome(home?: string): string;
2
+
3
+ export declare function getStatsCachePath(home?: string): string;
4
+
5
+ export declare function getProjectsDir(home?: string): string;
6
+
7
+ export declare function encodeProjectDirName(cwd: string): string;
8
+
9
+ export declare function getProjectDir(cwd: string, home?: string): string;
10
+
11
+ export declare function decodeProjectDirName(dirName: string): string;
@@ -0,0 +1 @@
1
+ "use strict";import t from"node:path";import i from"node:os";export function getClaudeHome(e){return t.join(e??i.homedir(),".claude")}export function getStatsCachePath(e){return t.join(getClaudeHome(e),"stats-cache.json")}export function getProjectsDir(e){return t.join(getClaudeHome(e),"projects")}export function encodeProjectDirName(e){return t.resolve(e).replace(/[^a-zA-Z0-9-]/g,"-")}export function getProjectDir(e,r){return t.join(getProjectsDir(r),encodeProjectDirName(e))}export function decodeProjectDirName(e){const r=/^([A-Za-z])--(.*)$/.exec(e);if(r){const n=r[1]??"",c=r[2]??"",o=process.platform==="win32"?"\\":"/";return`${n}:${o}${c.replace(/-/g,o)}`}return e.replace(/^-/,"/").replace(/-/g,"/")}
@@ -0,0 +1,11 @@
1
+ import type { ActivitySource, ProjectSummary } from './types.js';
2
+
3
+ export declare function listJsonlFiles(dirPath: string): Promise<readonly string[]>;
4
+
5
+ export declare function scanProjects(home?: string, opts?: {
6
+ verifyPaths?: boolean;
7
+ }): Promise<readonly ProjectSummary[]>;
8
+
9
+ export declare function createClaudeSessionScanner(home?: string, opts?: {
10
+ verifyPaths?: boolean;
11
+ }): ActivitySource<readonly ProjectSummary[]>;
@@ -0,0 +1 @@
1
+ "use strict";import r from"node:fs/promises";import m from"node:path";import{getProjectsDir as j}from"./claudePaths.js";import{decodeProjectDirName as M}from"./claudePaths.js";async function l(t){try{return(await r.readdir(t)).filter(e=>e.endsWith(".jsonl")).length}catch{return 0}}async function f(t){try{return(await r.stat(t)).mtimeMs}catch{return 0}}async function g(t){try{return await r.access(t),!0}catch{return!1}}export async function listJsonlFiles(t){try{return(await r.readdir(t)).filter(e=>e.endsWith(".jsonl")).map(e=>e.replace(".jsonl",""))}catch{return[]}}async function P(t){try{return(await r.readdir(t,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>String(e.name))}catch{return[]}}export async function scanProjects(t,n){const e=n?.verifyPaths??!0,c=j(t),d=await P(c),i=[];for(const s of d){const a=M(s);if(e&&!await g(a))continue;const o=m.join(c,s),h=await l(o),u=m.join(o,"subagents"),p=await l(u),y=await f(o),w=await f(u);i.push({summary:{projectPath:a,sessionCount:h,subagentSessionCount:p,totalTokens:0},latestMtime:Math.max(y,w)})}return i.sort((s,a)=>a.latestMtime-s.latestMtime),i.map(s=>s.summary)}export function createClaudeSessionScanner(t,n){return{name:"claude-session-scanner",read:()=>scanProjects(t,n)}}
@@ -0,0 +1,3 @@
1
+ export type { ActivitySource, ClaudeStatsData, DailyActivity, DailyModelTokens, LongestSession, ModelUsageEntry, ProjectSummary, SessionTokenResult, StatsOverview, } from './types.js';
2
+ export { getClaudeHome, getStatsCachePath, getProjectsDir, decodeProjectDirName, } from './claudePaths.js';
3
+ export { scanProjects, createClaudeSessionScanner } from './claudeSessionScanner.js';
@@ -0,0 +1 @@
1
+ "use strict";export{getClaudeHome,getStatsCachePath,getProjectsDir,decodeProjectDirName}from"./claudePaths.js";export{scanProjects,createClaudeSessionScanner}from"./claudeSessionScanner.js";
@@ -0,0 +1,82 @@
1
+ export interface ActivitySource<T> {
2
+ readonly name: string;
3
+ read(): Promise<T | null>;
4
+ }
5
+
6
+ export interface DailyActivity {
7
+ readonly date: string;
8
+ readonly messageCount: number;
9
+ readonly sessionCount: number;
10
+ readonly toolCallCount: number;
11
+ }
12
+
13
+ export interface DailyModelTokens {
14
+ readonly date: string;
15
+ readonly tokensByModel: Readonly<Record<string, number>>;
16
+ }
17
+
18
+ export interface ModelUsageEntry {
19
+ readonly inputTokens: number;
20
+ readonly outputTokens: number;
21
+ readonly cacheReadInputTokens: number;
22
+ readonly cacheCreationInputTokens: number;
23
+ }
24
+
25
+ export interface LongestSession {
26
+ readonly sessionId: string;
27
+ readonly duration: number;
28
+ readonly messageCount: number;
29
+ readonly timestamp: string;
30
+ }
31
+
32
+ export interface ClaudeStatsData {
33
+ readonly version: number;
34
+ readonly totalSessions: number;
35
+ readonly totalMessages: number;
36
+ readonly dailyActivity: readonly DailyActivity[];
37
+ readonly dailyModelTokens: readonly DailyModelTokens[];
38
+ readonly modelUsage: Readonly<Record<string, ModelUsageEntry>>;
39
+ readonly longestSession: LongestSession | null;
40
+ readonly firstSessionDate: string | null;
41
+ readonly hourCounts: Readonly<Record<string, number>>;
42
+ }
43
+
44
+ export interface ProjectSummary {
45
+ readonly projectPath: string;
46
+ readonly sessionCount: number;
47
+ readonly subagentSessionCount: number;
48
+ readonly totalTokens: number;
49
+ }
50
+
51
+ export interface SessionTokenResult {
52
+
53
+ readonly dailyActivity: readonly DailyActivity[];
54
+
55
+ readonly dailyModelTokens: readonly DailyModelTokens[];
56
+
57
+ readonly modelUsage: Readonly<Record<string, ModelUsageEntry>>;
58
+
59
+ readonly totalSessions: number;
60
+
61
+ readonly totalMessages: number;
62
+
63
+ readonly hourCounts: Readonly<Record<string, number>>;
64
+ }
65
+
66
+ export interface AgentTypeUsage {
67
+ readonly agentType: string;
68
+ readonly totalSessions: number;
69
+ readonly totalMessages: number;
70
+ readonly totalTokens: number;
71
+ readonly tokensUnavailable?: boolean;
72
+
73
+ readonly stats?: ClaudeStatsData;
74
+
75
+ readonly projects?: readonly ProjectSummary[];
76
+ }
77
+
78
+ export interface StatsOverview {
79
+ readonly stats: ClaudeStatsData | null;
80
+ readonly projects: readonly ProjectSummary[];
81
+ readonly agentTypeUsage?: readonly AgentTypeUsage[];
82
+ }
@@ -0,0 +1 @@
1
+ "use strict";export{};
@@ -0,0 +1,3 @@
1
+ export declare function readJsonFile<T>(filePath: string, fallback: T): T;
2
+
3
+ export declare function writeJsonFile(filePath: string, data: unknown): void;
@@ -0,0 +1 @@
1
+ "use strict";import n from"node:fs";import t from"node:path";export function readJsonFile(r,e){try{const o=n.readFileSync(r,"utf-8");return JSON.parse(o)}catch{return e}}export function writeJsonFile(r,e){n.mkdirSync(t.dirname(r),{recursive:!0}),n.writeFileSync(r,JSON.stringify(e,null,2),{encoding:"utf-8",mode:384}),process.platform!=="win32"&&n.chmodSync(r,384)}
@@ -0,0 +1,26 @@
1
+ export interface OneTimeEntry {
2
+
3
+ readonly uuid: string;
4
+
5
+ readonly line: number;
6
+
7
+ readonly type: string;
8
+
9
+ readonly parentUuid: string | null;
10
+
11
+ readonly rawContent?: unknown;
12
+ }
13
+
14
+ export interface OneTimeIndex {
15
+
16
+ readonly uuidMap: Map<string, OneTimeEntry>;
17
+
18
+ readonly totalLines: number;
19
+ }
20
+
21
+ export declare function buildOneTimeIndex(jsonlPath: string, toolCallId?: string): Promise<{
22
+ index: OneTimeIndex;
23
+ targetEntry: OneTimeEntry | null;
24
+ }>;
25
+
26
+ export declare function walkToUserPrompt(index: OneTimeIndex, startUuid: string, maxHops?: number): OneTimeEntry | null;
@@ -0,0 +1 @@
1
+ "use strict";import{createReadStream as l}from"node:fs";import{createInterface as d}from"node:readline";import{isRecord as c}from"./typeGuards.js";export async function buildOneTimeIndex(i,t){const n=new Map;let r=null,u=0;const o=d({input:l(i),crlfDelay:1/0});for await(const a of o)if(u++,!!a.trim())try{const e=JSON.parse(a);if(!c(e))continue;const f=e.uuid;if(typeof f!="string")continue;const s=typeof e.type=="string"?e.type:void 0;if(!s)continue;const p={uuid:f,line:u,type:s,parentUuid:typeof e.parentUuid=="string"?e.parentUuid:null,rawContent:(c(e.message)?e.message:void 0)?.content};n.set(f,p),!r&&t&&a.includes(t)&&(s==="assistant"||s==="user")&&(r=p)}catch{}return{index:{uuidMap:n,totalLines:u},targetEntry:r}}function y(i){if(i.type!=="user")return!1;const t=i.rawContent;return t==null||typeof t=="string"?!0:Array.isArray(t)?!t.some(n=>c(n)&&n.type==="tool_result"):!0}export function walkToUserPrompt(i,t,n=500){let r=t,u=0;for(;r&&u<n;){const o=i.uuidMap.get(r);if(!o)return null;if(y(o))return o;r=o.parentUuid,u++}return null}
@@ -0,0 +1,52 @@
1
+ import { spawn as defaultSpawn } from 'node:child_process';
2
+
3
+ export type SpawnFn = typeof defaultSpawn;
4
+
5
+ export type NotificationHandler = (params: unknown) => void;
6
+
7
+ export type RequestHandler = (params: unknown) => Promise<unknown>;
8
+
9
+ export type WildcardNotificationHandler = (method: string, params: unknown) => void;
10
+
11
+ export declare class JsonRpcResponseError extends Error {
12
+ readonly code: number | undefined;
13
+ constructor(message: string, code: number | undefined);
14
+ }
15
+
16
+ export interface JsonRpcStdioOptions {
17
+ readonly command: string;
18
+ readonly args: readonly string[];
19
+ readonly cwd: string;
20
+ readonly env?: Record<string, string>;
21
+
22
+ readonly defaultTimeoutMs?: number;
23
+
24
+ readonly shell?: boolean;
25
+
26
+ readonly spawn?: SpawnFn;
27
+
28
+ readonly onStderr?: (line: string) => void;
29
+ }
30
+
31
+ export type JsonRpcStdioState = 'idle' | 'connected' | 'error' | 'disposed';
32
+
33
+ export interface JsonRpcStdioClient {
34
+
35
+ connect(): Promise<void>;
36
+
37
+ request<T>(method: string, params?: unknown, timeoutMs?: number): Promise<T>;
38
+
39
+ notify(method: string, params?: unknown): void;
40
+
41
+ onNotification(method: string, handler: NotificationHandler): void;
42
+
43
+ onWildcardNotification(handler: WildcardNotificationHandler): void;
44
+
45
+ onRequest(method: string, handler: RequestHandler): void;
46
+
47
+ dispose(): Promise<void>;
48
+
49
+ getState(): JsonRpcStdioState;
50
+ }
51
+
52
+ export declare function createJsonRpcStdioClient(opts: JsonRpcStdioOptions): JsonRpcStdioClient;
@@ -0,0 +1,3 @@
1
+ "use strict";import{spawn as R}from"node:child_process";import{createInterface as j}from"node:readline";import{errorMessage as x}from"@agentdock/wire";import{killProcessTree as E}from"./processTree.js";import{pickRefreshedVars as P}from"./envSanitize.js";import{createStderrDecoder as q}from"./decodeChildOutput.js";import{agentProcessExitMessage as I}from"./agentStderrPolicy.js";export class JsonRpcResponseError extends Error{code;constructor(p,w){super(p),this.code=w,this.name="JsonRpcResponseError"}}const J=3e4,N=5e3;export function createJsonRpcStdioClient(i){const p=i.spawn??R,w=i.defaultTimeoutMs??J;let n="idle",l=null,a=null,T=1;const d=new Map,g=new Map,S=new Map;let h=null;function f(r){l?.stdin?.write(JSON.stringify(r)+`
2
+ `)}function m(r){for(const[t,e]of d)clearTimeout(e.timer),e.reject(new Error(r)),d.delete(t)}function M(r){const t=r.trim();if(!t)return;let e;try{e=JSON.parse(t)}catch{return}if(!(!e||typeof e!="object")){if(e.id!==void 0&&!e.method){const o=d.get(e.id);if(!o)return;clearTimeout(o.timer),d.delete(e.id),e.error?o.reject(new JsonRpcResponseError(e.error.message??`JSON-RPC error ${e.error.code}`,e.error.code)):o.resolve(e.result);return}if(e.id!==void 0&&e.method){const o=S.get(e.method);if(o){const c=e.id;o(e.params).then(s=>{f({jsonrpc:"2.0",id:c,result:s})}).catch(s=>{const u=x(s);f({jsonrpc:"2.0",id:c,error:{code:-32603,message:u}})})}return}if(e.method&&e.id===void 0){const o=g.get(e.method);o?o(e.params):h&&h(e.method,e.params)}}}return{async connect(){if(n==="connected")throw new Error("already connected");if(n==="disposed")throw new Error("client disposed");const r=p(i.command,[...i.args],{stdio:["pipe","pipe","pipe"],cwd:i.cwd,env:{...process.env,...P(),...i.env},shell:i.shell??process.platform==="win32",windowsHide:!0});if(l=r,n="connected",r.stdout&&(a=j({input:r.stdout}),a.on("line",M)),r.stderr){const t=q();r.stderr.on("data",e=>{if(t.feed(e),i.onStderr){const o=e.toString();for(const c of o.split(`
3
+ `)){const s=c.trim();s&&i.onStderr(s)}}}),r.on("close",e=>{if(n==="disposed")return;n="error";const o=t.finalize().trim();m(I(e,o))})}else r.on("close",()=>{n!=="disposed"&&(n="error",m("process exited"))});r.on("error",t=>{n!=="disposed"&&(n="error",m(t.message))})},request(r,t,e){if(n!=="connected")return Promise.reject(new Error("not connected"));const o=T++,c=e??w;return new Promise((s,u)=>{const y=setTimeout(()=>{d.delete(o),u(new Error(`request timeout: ${r}`))},c);d.set(o,{resolve:s,reject:u,timer:y}),f({jsonrpc:"2.0",id:o,method:r,params:t})})},notify(r,t){n==="connected"&&f({jsonrpc:"2.0",method:r,params:t})},onNotification(r,t){g.set(r,t)},onWildcardNotification(r){h=r},onRequest(r,t){S.set(r,t)},async dispose(){if(n!=="disposed"){if(m("disposed"),a&&(a.close(),a=null),l){const r=l;l=null,typeof r.exitCode!="number"&&!r.killed&&await new Promise(t=>{const e=setTimeout(()=>{try{E(r)}catch{}t()},N);r.on("close",()=>{clearTimeout(e),t()}),E(r)})}n="disposed"}},getState(){return n}}}
@@ -0,0 +1,45 @@
1
+ export interface KeepAliveStatus {
2
+ readonly thinking: boolean;
3
+ readonly mode: 'local' | 'remote';
4
+ }
5
+
6
+ export type KeepAliveSender = (sessionId: string, status: KeepAliveStatus) => void;
7
+ export interface KeepAliveOptions {
8
+ readonly sessionId: string;
9
+ readonly send: KeepAliveSender;
10
+
11
+ readonly intervalMs?: number;
12
+ }
13
+ export interface KeepAlive {
14
+
15
+ setThinking(thinking: boolean): void;
16
+
17
+ setMode(mode: 'local' | 'remote'): void;
18
+
19
+ updateSessionId(sessionId: string): void;
20
+
21
+ stop(): void;
22
+ }
23
+
24
+ export declare function createKeepAlive(options: KeepAliveOptions): KeepAlive;
25
+ export interface LivenessHeartbeat {
26
+ stop(): void;
27
+ }
28
+
29
+ export declare function createLivenessHeartbeat(send: (sessionId: string) => void, sessionId: string): LivenessHeartbeat;
30
+ export interface SessionKeepAliveSet {
31
+ keepAlive: KeepAlive;
32
+ livenessHeartbeat: LivenessHeartbeat;
33
+ }
34
+ export type SessionOwnershipLossReason = 'ownership-lost' | 'session-terminated';
35
+
36
+ export interface SessionKeepAliveClient {
37
+ sendSessionAlive(sessionId: string): Promise<{
38
+ ok: boolean;
39
+ error?: string;
40
+ } | null>;
41
+ sendLivenessHeartbeat(sessionId: string): void;
42
+ onStatusChange?(listener: (status: 'connected' | 'connecting' | 'disconnected' | 'error') => void): (() => void) | undefined;
43
+ }
44
+
45
+ export declare function createSessionKeepAliveSet(client: SessionKeepAliveClient, sessionId: string, initialMode?: 'local' | 'remote', onOwnershipLost?: (reason: SessionOwnershipLossReason) => void): SessionKeepAliveSet;
@@ -0,0 +1 @@
1
+ "use strict";const v=2e3;export function createKeepAlive(e){const{send:r,intervalMs:o=2e3}=e;let l=e.sessionId,i=!1,c="local";function n(){r(l,{thinking:i,mode:c})}n();const u=setInterval(n,o);return{setThinking(t){i=t,n()},setMode(t){c=t,n()},updateSessionId(t){l=t},stop(){clearInterval(u)}}}export function createLivenessHeartbeat(e,r){e(r);const o=setInterval(()=>e(r),300*1e3);return{stop:()=>clearInterval(o)}}export function createSessionKeepAliveSet(e,r,o,l){const i={current:void 0},c={current:void 0};let n=!1;const u=s=>{n||(n=!0,i.current?.stop(),c.current?.stop(),l?.(s))},t=createKeepAlive({sessionId:r,send:s=>{e.sendSessionAlive(s).then(a=>{if(!a?.ok){if(a?.error==="session-terminated"){u("session-terminated");return}(a?.error==="foreign-owner"||a?.error==="owner-revoked"||a?.error==="invalid-reconnect-key")&&u("ownership-lost")}}).catch(()=>{})}});i.current=t,e.onStatusChange?.(s=>{}),o&&t.setMode(o);const d=createLivenessHeartbeat(s=>e.sendLivenessHeartbeat(s),r);return c.current=d,{keepAlive:t,livenessHeartbeat:d}}
@@ -0,0 +1,3 @@
1
+ export declare function readKnownProjects(): readonly string[];
2
+
3
+ export declare function recordProjectPath(cwd: string): void;
@@ -0,0 +1 @@
1
+ "use strict";import i from"node:fs";import f from"node:path";import{getDaemonDir as S}from"./paths.js";import{getProjectsDir as v}from"./ingest/claudePaths.js";import{decodeProjectDirName as P}from"./ingest/claudePaths.js";import{readJsonFile as x}from"./jsonFileUtils.js";const j=2,w="known-projects.json",D=200;function p(){return f.join(S(),w)}function A(s){const e=P(s);try{return i.statSync(f.resolve(e)),e}catch{}const r=process.platform==="win32"?"\\":"/",o=/^([A-Za-z])--(.*)$/.exec(s);if(o){const t=o[1]??"",n=o[2]??"",l=[];for(let a=0;a<n.length;a++)n[a]==="-"&&l.push(a);if(l.length===0||l.length>12)return null;const c=1<<l.length;for(let a=0;a<c;a++){const d=n.split("");for(let h=0;h<l.length;h++){const y=l[h];y!==void 0&&(d[y]=a&1<<h?r:"-")}const u=`${t}:${r}${d.join("")}`;try{return i.statSync(f.resolve(u)),u}catch{}}return null}if(s.startsWith("-")){const t=s.slice(1),n=[];for(let c=0;c<t.length;c++)t[c]==="-"&&n.push(c);if(n.length===0||n.length>12)return null;const l=1<<n.length;for(let c=0;c<l;c++){const a=t.split("");for(let u=0;u<n.length;u++){const h=n[u];h!==void 0&&(a[h]=c&1<<u?"/":"-")}const d=`/${a.join("")}`;try{return i.statSync(f.resolve(d)),d}catch{}}return null}return null}function N(){const s=v();let e;try{e=i.readdirSync(s,{withFileTypes:!0})}catch{return[]}return e.filter(r=>r.isDirectory()).map(r=>{const o=A(r.name);if(!o)return null;try{const t=f.join(s,r.name),n=i.statSync(t);return{path:o,lastUsedAt:n.mtimeMs}}catch{return null}}).filter(r=>r!==null)}function g(){const s=x(p(),null);return s===null||s?.version!==j||!Array.isArray(s.projects)?[]:s.projects.filter(e=>typeof e=="object"&&e!==null&&typeof e.path=="string"&&typeof e.lastUsedAt=="number")}function m(s){const e=[...s].sort((l,c)=>c.lastUsedAt-l.lastUsedAt).slice(0,D),r={version:j,projects:e},o=p(),t=f.dirname(o);i.existsSync(t)||i.mkdirSync(t,{recursive:!0});const n=o+".tmp";i.writeFileSync(n,JSON.stringify(r,null,2),"utf-8"),i.renameSync(n,o)}export function readKnownProjects(){const s=i.existsSync(p());let e=g();if(e.length===0){const t=N();if(t.length>0){try{m(t)}catch{}e=[...t]}}let r=!1;const o=[];for(const t of e)try{const n=f.resolve(t.path);i.statSync(n).isDirectory()?o.push(t):r=!0}catch{r=!0}if(r||!s)try{m(o)}catch{}return o.map(t=>t.path)}export function recordProjectPath(s){const e=f.resolve(s);try{if(!i.statSync(e).isDirectory())return}catch{return}const r=g(),o=r.findIndex(n=>f.resolve(n.path)===e),t={path:e,lastUsedAt:Date.now()};o>=0?r[o]=t:r.push(t),m(r)}
@@ -0,0 +1,3 @@
1
+ import type { AccountLanguage } from '@agentdock/wire';
2
+
3
+ export declare function writeLanguageSettingsFile(language: AccountLanguage): Promise<string>;
@@ -0,0 +1 @@
1
+ "use strict";import s from"node:crypto";import e from"node:fs/promises";import r from"node:path";import{getDaemonDir as c}from"./paths.js";import{toClaudeLanguageSetting as g}from"./responseLanguage.js";export async function writeLanguageSettingsFile(o){const i=r.join(c(),"tmp");await e.mkdir(i,{recursive:!0});const a=JSON.stringify({language:g(o)}),n=s.createHash("sha256").update(a).digest("hex").slice(0,12),t=r.join(i,`lang-settings-${n}.json`);try{await e.access(t)}catch{await e.writeFile(t,a,"utf-8")}return t}
package/dist/lock.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export interface LockResult {
2
+ readonly acquired: boolean;
3
+ readonly existingPid?: number;
4
+ }
5
+
6
+ export declare function acquireLock(lockPath: string): LockResult;
7
+
8
+ export declare function releaseLock(lockPath: string): void;
9
+
10
+ export declare function isLocked(lockPath: string): boolean;
11
+
12
+ export declare function readLockPid(lockPath: string): number | null;
package/dist/lock.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";import t from"node:fs";import s from"node:path";import{errnoCode as c}from"./typeGuards.js";function i(r){try{return process.kill(r,0),!0}catch(n){return c(n)==="EPERM"}}function u(r,n){try{const e=t.openSync(r,t.constants.O_WRONLY|t.constants.O_CREAT|t.constants.O_EXCL);return t.writeSync(e,String(n)),t.closeSync(e),!0}catch(e){if(c(e)==="EEXIST")return!1;throw e}}export function acquireLock(r){const n=s.dirname(r);if(t.mkdirSync(n,{recursive:!0}),u(r,process.pid))return{acquired:!0};const e=readLockPid(r);if(e!==null&&i(e))return{acquired:!1,existingPid:e};try{t.unlinkSync(r)}catch{}return u(r,process.pid)?{acquired:!0}:{acquired:!1,existingPid:readLockPid(r)??void 0}}export function releaseLock(r){try{readLockPid(r)===process.pid&&t.unlinkSync(r)}catch{}}export function isLocked(r){const n=readLockPid(r);return n===null?!1:i(n)}export function readLockPid(r){try{const n=t.readFileSync(r,"utf-8").trim(),e=Number(n);return Number.isInteger(e)&&e>0?e:null}catch{return null}}
@@ -0,0 +1,16 @@
1
+ import type { Logger } from 'pino';
2
+ export type { Logger };
3
+
4
+ export interface DaemonLoggerOptions {
5
+
6
+ readonly level?: string;
7
+
8
+ readonly file?: string;
9
+
10
+ readonly pretty?: boolean;
11
+ }
12
+ export declare function createDaemonLogger(opts?: DaemonLoggerOptions, onLog?: (level: 'error' | 'warn', message: string, ctx: Record<string, unknown>) => void): Logger;
13
+
14
+ export declare function createSilentLogger(): Logger;
15
+ export declare function logSessionStatusSkipped(log: Logger | undefined, sessionId: string, status: string): void;
16
+ export declare function logSessionStatusSent(log: Logger | undefined, sessionId: string, status: string, runtimeStatus: string): void;
package/dist/logger.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";import c from"pino";import{isRecord as l}from"./typeGuards.js";import{VERSION as S}from"./version.js";const f=["password","masterSecret","masterSecretBase64","dataEncryptionKey","encryptedPayload"],v=["token","accessToken","apiKey"],A=[...f,...v];function h(e,o){const t=o.join(".");return f.includes(t)?"[REDACTED]":typeof e=="string"&&e.length>8?e.slice(0,8)+"***":"[REDACTED]"}const D={level:e=>({level:e})};export function createDaemonLogger(e,o){const t="production",p=e?.level??process.env.LOG_LEVEL??(t==="test"?"silent":t==="development"?"debug":"info"),u={env:t,version:S,pid:process.pid},m={paths:A,censor:h},r=o?{logMethod(s,g,a){if(a===50||a===40){const n=s[0],d=n instanceof Error,y=d?n.message:typeof n=="string"?n:typeof s[1]=="string"?s[1]:l(n)&&typeof n.msg=="string"?n.msg:"",E=d?{}:l(n)?n:l(s[1])?s[1]:{};o(a===50?"error":"warn",String(y),E)}return g.apply(this,s)}}:void 0,i={level:p,name:"agentdock-daemon",formatters:D,base:u,redact:m};return e?.file?c(r?{...i,hooks:r}:i,c.transport({target:"pino-roll",options:{file:e.file,frequency:"daily",dateFormat:"yyyy-MM-dd",size:"10m",limit:{count:7,removeOtherLogFiles:!0},mkdir:!0}})):e?.pretty?c({...i,...r?{hooks:r}:{},transport:{target:"pino-pretty",options:{colorize:!0}}}):c(r?{...i,hooks:r}:i)}export function createSilentLogger(){return c({level:"silent"})}export function logSessionStatusSkipped(e,o,t){e?.debug({sessionId:o,status:t,module:"daemon:serverClient"},"session status skipped while reconnecting")}export function logSessionStatusSent(e,o,t,p){e?.debug({sessionId:o,status:t,runtimeStatus:p,module:"daemon:serverClient"},"session status sent")}