@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.
- package/dist/acpTypes.d.ts +171 -0
- package/dist/acpTypes.js +1 -0
- package/dist/adapters/dingtalk.d.ts +11 -0
- package/dist/adapters/dingtalk.js +7 -0
- package/dist/adapters/feishu.d.ts +13 -0
- package/dist/adapters/feishu.js +1 -0
- package/dist/adapters/webhookClient.d.ts +8 -0
- package/dist/adapters/webhookClient.js +1 -0
- package/dist/agentSettings.d.ts +42 -0
- package/dist/agentSettings.js +1 -0
- package/dist/agentSpawnTypes.d.ts +76 -0
- package/dist/agentSpawnTypes.js +1 -0
- package/dist/agentStderrPolicy.d.ts +6 -0
- package/dist/agentStderrPolicy.js +1 -0
- package/dist/boundedSet.d.ts +12 -0
- package/dist/boundedSet.js +1 -0
- package/dist/brand.d.ts +27 -0
- package/dist/brand.js +1 -0
- package/dist/checkpointService.d.ts +40 -0
- package/dist/checkpointService.js +2 -0
- package/dist/cli-arg-access.d.ts +1 -0
- package/dist/cli-arg-access.js +1 -0
- package/dist/cli-args.d.ts +75 -0
- package/dist/cli-args.js +1 -0
- package/dist/cli-handoff-args.d.ts +22 -0
- package/dist/cli-handoff-args.js +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/containerEnvPrompt.d.ts +1 -0
- package/dist/containerEnvPrompt.js +1 -0
- package/dist/contextUsageQuery.d.ts +14 -0
- package/dist/contextUsageQuery.js +1 -0
- package/dist/conversationRollback.d.ts +12 -0
- package/dist/conversationRollback.js +4 -0
- package/dist/debugMode.d.ts +2 -0
- package/dist/debugMode.js +1 -0
- package/dist/decodeChildOutput.d.ts +12 -0
- package/dist/decodeChildOutput.js +1 -0
- package/dist/dekMethods.d.ts +9 -0
- package/dist/dekMethods.js +1 -0
- package/dist/deployment.d.ts +16 -0
- package/dist/deployment.js +1 -0
- package/dist/deploymentBinding.d.ts +15 -0
- package/dist/deploymentBinding.js +1 -0
- package/dist/directEnvelopeDelivery.d.ts +27 -0
- package/dist/directEnvelopeDelivery.js +1 -0
- package/dist/envSanitize.d.ts +14 -0
- package/dist/envSanitize.js +2 -0
- package/dist/envelopeOutbound.d.ts +8 -0
- package/dist/envelopeOutbound.js +1 -0
- package/dist/fetchRetry.d.ts +9 -0
- package/dist/fetchRetry.js +1 -0
- package/dist/fileReceiver.d.ts +32 -0
- package/dist/fileReceiver.js +1 -0
- package/dist/fileWatcher.d.ts +1 -0
- package/dist/fileWatcher.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/ingest/claudePaths.d.ts +11 -0
- package/dist/ingest/claudePaths.js +1 -0
- package/dist/ingest/claudeSessionScanner.d.ts +11 -0
- package/dist/ingest/claudeSessionScanner.js +1 -0
- package/dist/ingest/index.d.ts +3 -0
- package/dist/ingest/index.js +1 -0
- package/dist/ingest/types.d.ts +82 -0
- package/dist/ingest/types.js +1 -0
- package/dist/jsonFileUtils.d.ts +3 -0
- package/dist/jsonFileUtils.js +1 -0
- package/dist/jsonlIndexService.d.ts +26 -0
- package/dist/jsonlIndexService.js +1 -0
- package/dist/jsonrpc-stdio.d.ts +52 -0
- package/dist/jsonrpc-stdio.js +3 -0
- package/dist/keepAlive.d.ts +45 -0
- package/dist/keepAlive.js +1 -0
- package/dist/knownProjects.d.ts +3 -0
- package/dist/knownProjects.js +1 -0
- package/dist/languageSettingsFile.d.ts +3 -0
- package/dist/languageSettingsFile.js +1 -0
- package/dist/lock.d.ts +12 -0
- package/dist/lock.js +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.js +1 -0
- package/dist/messageQueue.d.ts +40 -0
- package/dist/messageQueue.js +1 -0
- package/dist/migration.d.ts +1 -0
- package/dist/migration.js +2 -0
- package/dist/modeLoop.d.ts +48 -0
- package/dist/modeLoop.js +1 -0
- package/dist/notificationChannels.d.ts +14 -0
- package/dist/notificationChannels.js +1 -0
- package/dist/notificationDispatcher.d.ts +11 -0
- package/dist/notificationDispatcher.js +1 -0
- package/dist/outbox.d.ts +49 -0
- package/dist/outbox.js +1 -0
- package/dist/paths.d.ts +24 -0
- package/dist/paths.js +1 -0
- package/dist/plaintextEnvelope.d.ts +5 -0
- package/dist/plaintextEnvelope.js +1 -0
- package/dist/processTree.d.ts +9 -0
- package/dist/processTree.js +5 -0
- package/dist/registerMachineOnConnect.d.ts +5 -0
- package/dist/registerMachineOnConnect.js +1 -0
- package/dist/responseLanguage.d.ts +5 -0
- package/dist/responseLanguage.js +5 -0
- package/dist/runtimeTargetGuard.d.ts +8 -0
- package/dist/runtimeTargetGuard.js +1 -0
- package/dist/sendClearedContextUsage.d.ts +4 -0
- package/dist/sendClearedContextUsage.js +1 -0
- package/dist/serverClient.d.ts +107 -0
- package/dist/serverClient.js +1 -0
- package/dist/serverClientEventHandlers.d.ts +6 -0
- package/dist/serverClientEventHandlers.js +1 -0
- package/dist/serverClientFactory.d.ts +3 -0
- package/dist/serverClientFactory.js +1 -0
- package/dist/serverClientTypes.d.ts +67 -0
- package/dist/serverClientTypes.js +1 -0
- package/dist/serverSettingsCache.d.ts +5 -0
- package/dist/serverSettingsCache.js +1 -0
- package/dist/session/backgroundTaskHandler.d.ts +29 -0
- package/dist/session/backgroundTaskHandler.js +1 -0
- package/dist/session/interactionDetector.d.ts +32 -0
- package/dist/session/interactionDetector.js +1 -0
- package/dist/session/modeHash.d.ts +6 -0
- package/dist/session/modeHash.js +1 -0
- package/dist/session/sessionBridge.d.ts +44 -0
- package/dist/session/sessionBridge.js +7 -0
- package/dist/session/sessionCompactBoundaryMapper.d.ts +17 -0
- package/dist/session/sessionCompactBoundaryMapper.js +1 -0
- package/dist/session/sessionMapper.d.ts +36 -0
- package/dist/session/sessionMapper.js +1 -0
- package/dist/session/sourceAgentRouting.d.ts +3 -0
- package/dist/session/sourceAgentRouting.js +1 -0
- package/dist/session/textAccumulator.d.ts +21 -0
- package/dist/session/textAccumulator.js +1 -0
- package/dist/session/turnTiming.d.ts +15 -0
- package/dist/session/turnTiming.js +1 -0
- package/dist/session/turnUsage.d.ts +17 -0
- package/dist/session/turnUsage.js +1 -0
- package/dist/session/workflowTracker.d.ts +63 -0
- package/dist/session/workflowTracker.js +1 -0
- package/dist/sessionBootstrap.d.ts +21 -0
- package/dist/sessionBootstrap.js +13 -0
- package/dist/sessionDeliveryDraft.d.ts +17 -0
- package/dist/sessionDeliveryDraft.js +1 -0
- package/dist/sessionDeliveryProtocol.d.ts +22 -0
- package/dist/sessionDeliveryProtocol.js +3 -0
- package/dist/sessionDeliverySubmit.d.ts +13 -0
- package/dist/sessionDeliverySubmit.js +1 -0
- package/dist/sessionDeliveryTool.d.ts +10 -0
- package/dist/sessionDeliveryTool.js +3 -0
- package/dist/sessionHandoffSystemPrompt.d.ts +10 -0
- package/dist/sessionHandoffSystemPrompt.js +3 -0
- package/dist/sessionMcpBootstrap.d.ts +13 -0
- package/dist/sessionMcpBootstrap.js +1 -0
- package/dist/sessionMcpInjection.d.ts +41 -0
- package/dist/sessionMcpInjection.js +1 -0
- package/dist/sessionMcpServer.d.ts +2 -0
- package/dist/sessionMcpServer.js +2 -0
- package/dist/sessionPrompt.d.ts +7 -0
- package/dist/sessionPrompt.js +3 -0
- package/dist/sessionRegistry.d.ts +42 -0
- package/dist/sessionRegistry.js +1 -0
- package/dist/sessionStatsCollector.d.ts +20 -0
- package/dist/sessionStatsCollector.js +1 -0
- package/dist/shellSanitizer.d.ts +1 -0
- package/dist/shellSanitizer.js +1 -0
- package/dist/shutdownHelper.d.ts +24 -0
- package/dist/shutdownHelper.js +1 -0
- package/dist/skillCache.d.ts +4 -0
- package/dist/skillCache.js +1 -0
- package/dist/skillParser.d.ts +20 -0
- package/dist/skillParser.js +6 -0
- package/dist/spawnConsole.d.ts +9 -0
- package/dist/spawnConsole.js +21 -0
- package/dist/startAbortHandler.d.ts +15 -0
- package/dist/startAbortHandler.js +1 -0
- package/dist/startAcpInitialPrompt.d.ts +51 -0
- package/dist/startAcpInitialPrompt.js +7 -0
- package/dist/startAcpPermission.d.ts +20 -0
- package/dist/startAcpPermission.js +1 -0
- package/dist/startAcpSwitchHelpers.d.ts +52 -0
- package/dist/startAcpSwitchHelpers.js +1 -0
- package/dist/startCancelTaskHandler.d.ts +17 -0
- package/dist/startCancelTaskHandler.js +1 -0
- package/dist/startCommandDaemonDebug.d.ts +8 -0
- package/dist/startCommandDaemonDebug.js +1 -0
- package/dist/startCommandRuntime.d.ts +162 -0
- package/dist/startCommandRuntime.js +5 -0
- package/dist/startCommandTypes.d.ts +33 -0
- package/dist/startCommandTypes.js +1 -0
- package/dist/startRpcHandler.d.ts +41 -0
- package/dist/startRpcHandler.js +1 -0
- package/dist/state.d.ts +29 -0
- package/dist/state.js +1 -0
- package/dist/statsAccumulator.d.ts +50 -0
- package/dist/statsAccumulator.js +1 -0
- package/dist/statsBuckets.d.ts +55 -0
- package/dist/statsBuckets.js +1 -0
- package/dist/subagentIds.d.ts +1 -0
- package/dist/subagentIds.js +1 -0
- package/dist/suggestedOptionsPrompt.d.ts +16 -0
- package/dist/suggestedOptionsPrompt.js +7 -0
- package/dist/taskTitle.d.ts +3 -0
- package/dist/taskTitle.js +1 -0
- package/dist/telemetryCollector.d.ts +15 -0
- package/dist/telemetryCollector.js +1 -0
- package/dist/terminalReset.d.ts +1 -0
- package/dist/terminalReset.js +1 -0
- package/dist/titleUpdater.d.ts +25 -0
- package/dist/titleUpdater.js +1 -0
- package/dist/tokenAuth.d.ts +6 -0
- package/dist/tokenAuth.js +1 -0
- package/dist/toolResultTruncation.d.ts +3 -0
- package/dist/toolResultTruncation.js +5 -0
- package/dist/transport.d.ts +13 -0
- package/dist/transport.js +1 -0
- package/dist/typeGuards.d.ts +7 -0
- package/dist/typeGuards.js +1 -0
- package/dist/userConfig.d.ts +5 -0
- package/dist/userConfig.js +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.g.d.ts +1 -0
- package/dist/version.g.js +1 -0
- package/dist/version.js +1 -0
- package/dist/waitForConnection.d.ts +2 -0
- package/dist/waitForConnection.js +1 -0
- package/dist/windowsCommandShim.d.ts +6 -0
- package/dist/windowsCommandShim.js +1 -0
- package/dist/zombieReaper.d.ts +34 -0
- package/dist/zombieReaper.js +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{SESSION_RPC_METHODS as c,AnswerQuestionParamsSchema as m,ApprovePermissionParamsSchema as k,DenyPermissionParamsSchema as g}from"@agentdock/wire";import{optionalStringParam as p}from"./typeGuards.js";export const START_RPC_METHODS=c;export function createStartRpcHandler(r){return async(l,t)=>{const f=p(t,"sessionId");if(!f||f!==r.sessionId)return{ok:!1,error:"session-not-found"};switch(l){case"answer-question":{const e=m.safeParse(t);if(!e.success)return{ok:!1,error:"invalid-answer-payload"};const{text:o,images:s,meta:n}=e.data,a=!!s&&s.length>0;if(!o&&!a)return{ok:!1,error:"text-required"};const u=n?{model:typeof n.model=="string"?n.model:void 0,permissionMode:typeof n.permissionMode=="string"?n.permissionMode:void 0}:void 0,d=a?s.map(i=>({data:i.data,mediaType:i.mediaType})):void 0;try{return await r.onAnswerQuestion(o??"",u,d&&d.length>0?d:void 0),{ok:!0,result:null}}catch(i){return r.log?.error({err:i,sessionId:r.sessionId,module:"daemon:start-rpc"},"answer-question provider submission failed"),{ok:!1,error:"message-send-failed"}}}case"abort":return await r.onAbort(),{ok:!0,result:null};case"stop-session":{const e=await r.onStopSession();return setTimeout(e,0),{ok:!0,result:null}}case"approve-permission":case"deny-permission":{if(!r.onPermission)return{ok:!1,error:"not-in-remote-mode"};if(l==="approve-permission"){const e=k.safeParse(t);if(!e.success)return{ok:!1,error:"request-not-found"};const{requestId:o,mode:s,allowTools:n,autoApproveEdits:a,inputOverrides:u}=e.data;r.onPermission(o,!0,void 0,n,s,a,u)}else{const e=g.safeParse(t);if(!e.success)return{ok:!1,error:"request-not-found"};const{requestId:o,reason:s}=e.data;r.onPermission(o,!1,s,void 0,void 0,void 0,void 0)}return{ok:!0,result:null}}case"cancel-task":{const e=typeof t.taskId=="string"?t.taskId:void 0;if(!e)return{ok:!1,error:"taskId-required"};if(!r.onCancelTask)return{ok:!1,error:"not-supported"};const o=await r.onCancelTask(e);return o.ok?{ok:!0,result:null}:{ok:!1,error:o.error??"cancel-failed"}}case"get-context-usage":{if(!r.onGetContextUsage)return{ok:!1,error:"not-supported"};try{return{ok:!0,result:await r.onGetContextUsage()}}catch(e){const o=e instanceof Error?e.message:String(e);return r.log&&r.log.error({err:e,sessionId:r.sessionId,module:"daemon:start-rpc"},"get-context-usage failed"),{ok:!1,error:o}}}default:return{ok:!1,error:"unknown-method"}}}}
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface DaemonState {
|
|
2
|
+
readonly pid: number;
|
|
3
|
+
readonly httpPort: number;
|
|
4
|
+
readonly startTime: string;
|
|
5
|
+
readonly version: string;
|
|
6
|
+
readonly lastHeartbeat?: string;
|
|
7
|
+
|
|
8
|
+
readonly authToken?: string;
|
|
9
|
+
|
|
10
|
+
readonly serverUrl?: string;
|
|
11
|
+
|
|
12
|
+
readonly latestVersion?: string;
|
|
13
|
+
|
|
14
|
+
readonly upgradeRequired?: boolean;
|
|
15
|
+
|
|
16
|
+
readonly connectionStatus?: 'connected' | 'connecting' | 'disconnected' | 'error';
|
|
17
|
+
|
|
18
|
+
readonly lastUpgradeError?: string;
|
|
19
|
+
|
|
20
|
+
readonly daemonGen?: string;
|
|
21
|
+
|
|
22
|
+
readonly deferredReapGens?: readonly string[];
|
|
23
|
+
|
|
24
|
+
readonly lastFailedVersion?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export declare function writeDaemonState(statePath: string, state: DaemonState): void;
|
|
28
|
+
|
|
29
|
+
export declare function readDaemonState(statePath: string): DaemonState | null;
|
package/dist/state.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{readJsonFile as n,writeJsonFile as o}from"./jsonFileUtils.js";export function writeDaemonState(e,t){o(e,t)}export function readDaemonState(e){return n(e,null)}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { StatsOverview } from './ingest/types.js';
|
|
2
|
+
import { type AgentBucketSnapshot, type ModelState, type DaySnapshot, type SessionSnapshot } from './statsBuckets.js';
|
|
3
|
+
|
|
4
|
+
export interface MessageDataPoint {
|
|
5
|
+
readonly model: string;
|
|
6
|
+
readonly inputTokens: number;
|
|
7
|
+
readonly outputTokens: number;
|
|
8
|
+
readonly cacheReadInputTokens: number;
|
|
9
|
+
readonly cacheCreationInputTokens: number;
|
|
10
|
+
readonly timestamp: string;
|
|
11
|
+
readonly filePath: string;
|
|
12
|
+
readonly projectDir: string;
|
|
13
|
+
readonly toolCallCount: number;
|
|
14
|
+
|
|
15
|
+
readonly agentType?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface AccumulatorSnapshot {
|
|
19
|
+
|
|
20
|
+
readonly agentBuckets?: Record<string, AgentBucketSnapshot>;
|
|
21
|
+
|
|
22
|
+
readonly fileOffsets: Record<string, number>;
|
|
23
|
+
readonly days?: Record<string, DaySnapshot>;
|
|
24
|
+
readonly models?: Record<string, ModelState>;
|
|
25
|
+
readonly hourCounts?: Record<string, number>;
|
|
26
|
+
readonly sessions?: Record<string, SessionSnapshot>;
|
|
27
|
+
readonly totalMessages?: number;
|
|
28
|
+
readonly allSessionFiles?: string[];
|
|
29
|
+
readonly agentTypes?: Record<string, {
|
|
30
|
+
sessionFiles: string[];
|
|
31
|
+
totalMessages: number;
|
|
32
|
+
totalTokens: number;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
export interface StatsAccumulator {
|
|
36
|
+
addMessage(point: MessageDataPoint): void;
|
|
37
|
+
getStatsOverview(): StatsOverview;
|
|
38
|
+
serialize(fileOffsets: ReadonlyMap<string, number>): AccumulatorSnapshot;
|
|
39
|
+
|
|
40
|
+
prune(cutoffDate: string): string[];
|
|
41
|
+
|
|
42
|
+
getHealthMetrics(): {
|
|
43
|
+
statsDays: number;
|
|
44
|
+
statsMessages: number;
|
|
45
|
+
agentTypes: string[];
|
|
46
|
+
};
|
|
47
|
+
readonly messageCount: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export declare function createStatsAccumulator(snapshot?: AccumulatorSnapshot): StatsAccumulator;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{createEmptyBucket as C,restoreBucket as f,serializeBucket as B,buildStatsFromBuckets as k}from"./statsBuckets.js";export function createStatsAccumulator(u){const c=new Map;if(u){if(u.agentBuckets)for(const[e,s]of Object.entries(u.agentBuckets))c.set(e,f(s));else if(u.days){const e={days:u.days,models:u.models??{},hourCounts:u.hourCounts??{},sessions:u.sessions??{},allSessionFiles:u.allSessionFiles??[],totalMessages:u.totalMessages??0};c.set("claude",f(e))}}function g(e){let s=c.get(e);return s||(s=C(),c.set(e,s)),s}function m(e){const s=e.agentType??"claude",t=g(s),o=e.timestamp.slice(0,10),a=String(new Date(e.timestamp).getHours()),n=e.inputTokens+e.outputTokens+e.cacheReadInputTokens+e.cacheCreationInputTokens;t.totalMessages++,t.allSessionFiles.add(e.filePath);let r=t.dayMap.get(o);r||(r={messageCount:0,sessionFiles:new Set,toolCallCount:0,tokensByModel:{}},t.dayMap.set(o,r)),r.messageCount++,r.sessionFiles.add(e.filePath),r.toolCallCount+=e.toolCallCount,r.tokensByModel[e.model]=(r.tokensByModel[e.model]??0)+n;let i=t.modelMap.get(e.model);i||(i={inputTokens:0,outputTokens:0,cacheReadInputTokens:0,cacheCreationInputTokens:0},t.modelMap.set(e.model,i)),i.inputTokens+=e.inputTokens,i.outputTokens+=e.outputTokens,i.cacheReadInputTokens+=e.cacheReadInputTokens,i.cacheCreationInputTokens+=e.cacheCreationInputTokens,t.hourCounts[a]=(t.hourCounts[a]??0)+1;let l=t.sessionMap.get(e.filePath);l||(l={totalTokens:0,messageCount:0,startDate:null,projectDir:e.projectDir},t.sessionMap.set(e.filePath,l)),l.totalTokens+=n,l.messageCount++,(!l.startDate||o<l.startDate)&&(l.startDate=o)}function M(){const e=[...c.values()],{stats:s,projects:t}=k(e),o=[...c.entries()].map(([a,n])=>{const{stats:r,projects:i}=k([n]);let l=0;for(const d of n.modelMap.values())l+=d.inputTokens+d.outputTokens+d.cacheReadInputTokens+d.cacheCreationInputTokens;return{agentType:a,totalSessions:n.allSessionFiles.size,totalMessages:n.totalMessages,totalTokens:l,stats:r??void 0,projects:i}}).sort((a,n)=>n.totalTokens-a.totalTokens);return{stats:s,projects:t,agentTypeUsage:o}}function T(e){const s={};for(const[t,o]of c.entries())s[t]=B(o);return{agentBuckets:s,fileOffsets:Object.fromEntries(e)}}function p(e){const s=new Set;for(const t of c.values()){for(const[a,n]of t.dayMap)a<e&&(t.totalMessages-=n.messageCount,t.dayMap.delete(a));const o=new Set;for(const a of t.dayMap.values())for(const n of a.sessionFiles)o.add(n);for(const[a]of t.sessionMap)o.has(a)||(t.sessionMap.delete(a),t.allSessionFiles.delete(a),s.add(a))}return[...s]}function y(){const e=[];let s=0,t=0;for(const[o,a]of c.entries())e.push(o),t+=a.totalMessages,a.dayMap.size>s&&(s=a.dayMap.size);return{statsDays:s,statsMessages:t,agentTypes:e}}return{addMessage:m,getStatsOverview:M,serialize:T,prune:p,getHealthMetrics:y,get messageCount(){let e=0;for(const s of c.values())e+=s.totalMessages;return e}}}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ClaudeStatsData, ProjectSummary } from './ingest/types.js';
|
|
2
|
+
export interface DayState {
|
|
3
|
+
messageCount: number;
|
|
4
|
+
sessionFiles: Set<string>;
|
|
5
|
+
toolCallCount: number;
|
|
6
|
+
tokensByModel: Record<string, number>;
|
|
7
|
+
}
|
|
8
|
+
export interface ModelState {
|
|
9
|
+
inputTokens: number;
|
|
10
|
+
outputTokens: number;
|
|
11
|
+
cacheReadInputTokens: number;
|
|
12
|
+
cacheCreationInputTokens: number;
|
|
13
|
+
}
|
|
14
|
+
export interface SessionState {
|
|
15
|
+
totalTokens: number;
|
|
16
|
+
messageCount: number;
|
|
17
|
+
startDate: string | null;
|
|
18
|
+
projectDir: string;
|
|
19
|
+
}
|
|
20
|
+
export interface AgentBucket {
|
|
21
|
+
dayMap: Map<string, DayState>;
|
|
22
|
+
modelMap: Map<string, ModelState>;
|
|
23
|
+
hourCounts: Record<string, number>;
|
|
24
|
+
sessionMap: Map<string, SessionState>;
|
|
25
|
+
allSessionFiles: Set<string>;
|
|
26
|
+
totalMessages: number;
|
|
27
|
+
}
|
|
28
|
+
export interface DaySnapshot {
|
|
29
|
+
messageCount: number;
|
|
30
|
+
sessionFiles: string[];
|
|
31
|
+
toolCallCount: number;
|
|
32
|
+
tokensByModel: Record<string, number>;
|
|
33
|
+
}
|
|
34
|
+
export interface SessionSnapshot {
|
|
35
|
+
totalTokens: number;
|
|
36
|
+
messageCount: number;
|
|
37
|
+
startDate: string | null;
|
|
38
|
+
projectDir: string;
|
|
39
|
+
}
|
|
40
|
+
export interface AgentBucketSnapshot {
|
|
41
|
+
days: Record<string, DaySnapshot>;
|
|
42
|
+
models: Record<string, ModelState>;
|
|
43
|
+
hourCounts: Record<string, number>;
|
|
44
|
+
sessions: Record<string, SessionSnapshot>;
|
|
45
|
+
allSessionFiles: string[];
|
|
46
|
+
totalMessages: number;
|
|
47
|
+
}
|
|
48
|
+
export declare function createEmptyBucket(): AgentBucket;
|
|
49
|
+
export declare function restoreBucket(snap: AgentBucketSnapshot): AgentBucket;
|
|
50
|
+
export declare function serializeBucket(bucket: AgentBucket): AgentBucketSnapshot;
|
|
51
|
+
|
|
52
|
+
export declare function buildStatsFromBuckets(buckets: readonly AgentBucket[]): {
|
|
53
|
+
stats: ClaudeStatsData | null;
|
|
54
|
+
projects: ProjectSummary[];
|
|
55
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export function createEmptyBucket(){return{dayMap:new Map,modelMap:new Map,hourCounts:{},sessionMap:new Map,allSessionFiles:new Set,totalMessages:0}}export function restoreBucket(n){const a=createEmptyBucket();a.totalMessages=n.totalMessages;for(const i of n.allSessionFiles)a.allSessionFiles.add(i);for(const[i,l]of Object.entries(n.days))a.dayMap.set(i,{messageCount:l.messageCount,sessionFiles:new Set(l.sessionFiles),toolCallCount:l.toolCallCount,tokensByModel:{...l.tokensByModel}});for(const[i,l]of Object.entries(n.models))a.modelMap.set(i,{...l});Object.assign(a.hourCounts,n.hourCounts);for(const[i,l]of Object.entries(n.sessions))a.sessionMap.set(i,{...l});return a}export function serializeBucket(n){const a={};for(const[u,r]of n.dayMap.entries())a[u]={messageCount:r.messageCount,sessionFiles:[...r.sessionFiles],toolCallCount:r.toolCallCount,tokensByModel:{...r.tokensByModel}};const i={};for(const[u,r]of n.modelMap.entries())i[u]={...r};const l={};for(const[u,r]of n.sessionMap.entries())l[u]={...r};return{days:a,models:i,hourCounts:{...n.hourCounts},sessions:l,allSessionFiles:[...n.allSessionFiles],totalMessages:n.totalMessages}}export function buildStatsFromBuckets(n){const a=new Map,i=new Map,l={},u=new Map;let r=0;const d=new Set;for(const e of n){r+=e.totalMessages;for(const s of e.allSessionFiles)d.add(s);for(const[s,o]of e.dayMap.entries()){const t=a.get(s);if(t){t.messageCount+=o.messageCount;for(const c of o.sessionFiles)t.sessionFiles.add(c);t.toolCallCount+=o.toolCallCount;for(const[c,g]of Object.entries(o.tokensByModel))t.tokensByModel[c]=(t.tokensByModel[c]??0)+g}else a.set(s,{messageCount:o.messageCount,sessionFiles:new Set(o.sessionFiles),toolCallCount:o.toolCallCount,tokensByModel:{...o.tokensByModel}})}for(const[s,o]of e.modelMap.entries()){const t=i.get(s);t?(t.inputTokens+=o.inputTokens,t.outputTokens+=o.outputTokens,t.cacheReadInputTokens+=o.cacheReadInputTokens,t.cacheCreationInputTokens+=o.cacheCreationInputTokens):i.set(s,{...o})}for(const[s,o]of Object.entries(e.hourCounts))l[s]=(l[s]??0)+o;for(const[s,o]of e.sessionMap.entries()){const t=u.get(s);t?(t.totalTokens+=o.totalTokens,t.messageCount+=o.messageCount,o.startDate&&(!t.startDate||o.startDate<t.startDate)&&(t.startDate=o.startDate)):u.set(s,{...o})}}const f=[...a.entries()].sort(([e],[s])=>e.localeCompare(s)).map(([e,s])=>({date:e,messageCount:s.messageCount,sessionCount:s.sessionFiles.size,toolCallCount:s.toolCallCount})),M=[...a.entries()].sort(([e],[s])=>e.localeCompare(s)).map(([e,s])=>({date:e,tokensByModel:{...s.tokensByModel}})),p={};for(const[e,s]of i.entries())p[e]={...s};const C=new Map;for(const[,e]of u.entries()){const s=C.get(e.projectDir)??{sessionCount:0,totalTokens:0};s.sessionCount++,s.totalTokens+=e.totalTokens,C.set(e.projectDir,s)}const m=[...C.entries()].map(([e,s])=>({projectPath:e,sessionCount:s.sessionCount,subagentSessionCount:0,totalTokens:s.totalTokens})).sort((e,s)=>s.sessionCount-e.sessionCount);return{stats:r>0?{version:2,totalSessions:d.size,totalMessages:r,dailyActivity:f,dailyModelTokens:M,modelUsage:p,longestSession:null,firstSessionDate:f[0]?.date??null,hourCounts:{...l}}:null,projects:m}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function makeStableSubagentId(providerSubagentId: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{createHash as t}from"node:crypto";export function makeStableSubagentId(e){return`c${t("sha1").update(e).digest("hex").slice(0,23)}`}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function withOpenCodeInstructions<T>(userPrompt: string | undefined, isScheduled: boolean, start: () => Promise<T>): Promise<T>;
|
|
2
|
+
|
|
3
|
+
export declare const REMOTE_ENVIRONMENT_PROMPT: string;
|
|
4
|
+
export declare const SUGGESTED_OPTIONS_PROMPT: string;
|
|
5
|
+
|
|
6
|
+
export declare function buildAppendedSystemPrompt(additionalPrompt?: string, includeOptions?: boolean): string;
|
|
7
|
+
|
|
8
|
+
export declare function writeAppendedSystemPromptFile(additionalPrompt?: string, includeOptions?: boolean): Promise<string>;
|
|
9
|
+
|
|
10
|
+
export declare function writeUserOnlySystemPromptFile(userPrompt?: string): Promise<string | undefined>;
|
|
11
|
+
|
|
12
|
+
export declare function cleanupSystemPromptFile(filePath: string): Promise<void>;
|
|
13
|
+
|
|
14
|
+
export declare function getOpenCodeInstructionsPath(): string;
|
|
15
|
+
|
|
16
|
+
export declare function writeOpenCodeInstructionsFile(userPrompt?: string, isScheduled?: boolean): Promise<string>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";import i from"node:fs/promises";import l from"node:crypto";import m from"node:os";import r from"node:path";import{getDaemonDir as u}from"./paths.js";let p=Promise.resolve();export async function withOpenCodeInstructions(t,n,e){const o=p;let a;p=new Promise(c=>{a=c}),await o;try{return await writeOpenCodeInstructionsFile(t,n),await e()}finally{a?.()}}export const REMOTE_ENVIRONMENT_PROMPT=`## Environment
|
|
2
|
+
|
|
3
|
+
You are running as a headless subprocess behind the AgentDock web console \u2014 there is no terminal, no keyboard shortcuts, and no TUI. Do not use interactive terminal behaviors, e.g. numbered lists waiting for keypress, "press Enter to continue", or cursor navigation.`,SUGGESTED_OPTIONS_PROMPT=["# Options","","You have a way to give a user an easy way to answer your questions or continue the conversation.","To provide this, output in the very end of your response an XML block:","","<options>"," <option>Option 1</option>"," <option>Option N</option>","</options>","","Rules:","- Output this at the very end of your response, not inside any other text.","- Do not wrap it into a codeblock.","- Always put <options> and </options> on dedicated lines.",`- Each option is a message the USER will send to you, so write it in the user's voice (first person as the user). E.g. "Help me read the hermes source", NOT "I'll read the hermes source for you".`,'- Never output a "custom" option \u2014 the user always has the option to send a custom message.',"- Do not enumerate options in both text and the options block.","- Always prefer to use the options mode. Try to keep options minimal (2-4), better to clarify in next steps.","- When there is a decision point, you must use options to give the user an easy way to choose."].join(`
|
|
4
|
+
`);export function buildAppendedSystemPrompt(t,n=!0){const e=[REMOTE_ENVIRONMENT_PROMPT];return n&&e.push(SUGGESTED_OPTIONS_PROMPT),t&&e.push(t),e.join(`
|
|
5
|
+
|
|
6
|
+
`)}export async function writeAppendedSystemPromptFile(t,n=!0){const e=buildAppendedSystemPrompt(t,n);return h(e)}export async function writeUserOnlySystemPromptFile(t){if(t)return h(t)}async function h(t){const n=r.join(u(),"tmp");await i.mkdir(n,{recursive:!0});const e=l.createHash("sha256").update(t).digest("hex").slice(0,12),o=r.join(n,`system-prompt-${e}.txt`);try{await i.access(o)}catch{await i.writeFile(o,t,"utf-8")}return o}export async function cleanupSystemPromptFile(t){try{await i.unlink(t)}catch{}}export function getOpenCodeInstructionsPath(){return r.join(u(),"opencode","instructions.txt")}function f(){return r.join(m.homedir(),".config","opencode","opencode.json")}function y(t){return t.endsWith(`${r.sep}opencode${r.sep}instructions.txt`)}async function w(){const t=f(),n=getOpenCodeInstructionsPath();let e={};try{const s=await i.readFile(t,"utf-8");e=JSON.parse(s)}catch{}const o=Array.isArray(e.instructions)?e.instructions.filter(s=>typeof s=="string"):[],a=o.filter(s=>!y(s)||s===n),c=a.includes(n)?a:[...a,n];(c.length!==o.length||c.some((s,d)=>s!==o[d]))&&(e.instructions=c,await i.mkdir(r.dirname(t),{recursive:!0}),await i.writeFile(t,JSON.stringify(e,null,2)+`
|
|
7
|
+
`,"utf-8"))}export async function writeOpenCodeInstructionsFile(t,n=!1){const e=buildAppendedSystemPrompt(t,!n),o=getOpenCodeInstructionsPath();return await i.mkdir(r.dirname(o),{recursive:!0}),await i.writeFile(o,e,"utf-8"),await w(),o}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{isRecord as i}from"./typeGuards.js";export function pickTaskTitle(e){if(!i(e))return;const t=e;if(typeof t.description=="string"&&t.description.trim().length>0){const r=t.description.trim();return r.length>80?`${r.slice(0,77)}...`:r}if(typeof t.name=="string"&&t.name.trim().length>0)return t.name.trim();if(typeof t.title=="string"&&t.title.trim().length>0)return t.title.trim();if(typeof t.subagent_type=="string"&&t.subagent_type.trim().length>0)return t.subagent_type.trim()}export function pickTaskPrompt(e){if(!i(e))return;const t=e;if(typeof t.prompt=="string"&&t.prompt.trim().length>0)return t.prompt.trim();if(typeof t.description=="string"&&t.description.trim().length>0)return t.description.trim()}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TelemetryEventStrict, TelemetryReportPayload } from '@agentdock/wire';
|
|
2
|
+
export interface TelemetryCollectorOpts {
|
|
3
|
+
send: (payload: TelemetryReportPayload) => void;
|
|
4
|
+
machineId: string;
|
|
5
|
+
daemonVersion: string;
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface TelemetryCollector {
|
|
9
|
+
emit(event: Omit<TelemetryEventStrict, 'daemonVersion' | 'timestamp'>): void;
|
|
10
|
+
flush(): void;
|
|
11
|
+
destroy(): void;
|
|
12
|
+
|
|
13
|
+
setEnabled(enabled: boolean): void;
|
|
14
|
+
}
|
|
15
|
+
export declare function createTelemetryCollector(opts: TelemetryCollectorOpts): TelemetryCollector;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{sanitizeContext as M}from"@agentdock/wire";import{isRecord as x}from"./typeGuards.js";const A=100,R=6e4,y=5*6e4,b=3;function F(f){let s=5381;for(let c=0;c<f.length;c++)s=s*33^f.charCodeAt(c);return s>>>0}export function createTelemetryCollector(f){const{send:s,machineId:c,daemonVersion:g,enabled:T=!0}=f;let u=T;const n=[],a=new Map,h=new Set;let i=null;function m(){i===null&&(i=setInterval(()=>d(),R),i.unref?.())}function p(){i!==null&&(clearInterval(i),i=null)}u&&m();function _(t,e,o){return`${t}::${F(e)}::${o??""}`}function I(t,e,o){const r=_(t,e,o),w=Date.now(),l=a.get(r);return!l||w-l.windowStart>y?(a.set(r,{count:1,windowStart:w}),!1):l.count>=b?!0:(l.count++,!1)}function S(t){if(!u||I(t.code,t.message,t.agentType))return;if(t.type==="scanner.version_unknown"&&t.agentType&&t.agentVersion){const r=`${t.agentType}:${t.agentVersion}`;if(h.has(r))return;h.add(r)}const e=M(t.type,x(t.context)?t.context:void 0),o={...t,daemonVersion:g,timestamp:new Date().toISOString(),context:e};n.length>=A&&n.shift(),n.push(o)}function E(t){t!==u&&(u=t,u?m():(p(),n.length=0))}function d(){const t=Date.now();for(const[o,r]of a)t-r.windowStart>y&&a.delete(o);if(n.length===0)return;const e=n.splice(0,n.length);try{s({machineId:c,events:e})}catch{}}function L(){p(),d()}return{emit:S,flush:d,destroy:L,setEnabled:E}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resetTerminalMouse(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const t="\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l";export function resetTerminalMouse(){for(const s of[process.stdout,process.stderr])try{s.isTTY&&s.write(t)}catch{}}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type ServerStatus = 'connected' | 'disconnected' | 'connecting' | 'error' | 'offline';
|
|
2
|
+
export interface TitleUpdater {
|
|
3
|
+
|
|
4
|
+
setServerStatus(status: ServerStatus): void;
|
|
5
|
+
|
|
6
|
+
setDaemonAlive(alive: boolean): void;
|
|
7
|
+
|
|
8
|
+
setUpgradeAvailable(available: boolean): void;
|
|
9
|
+
|
|
10
|
+
refresh(): void;
|
|
11
|
+
|
|
12
|
+
stop(): void;
|
|
13
|
+
}
|
|
14
|
+
export interface TitleUpdaterOptions {
|
|
15
|
+
|
|
16
|
+
readonly daemonHttpPort?: number;
|
|
17
|
+
|
|
18
|
+
readonly statePath?: string;
|
|
19
|
+
|
|
20
|
+
readonly pollIntervalMs?: number;
|
|
21
|
+
|
|
22
|
+
readonly healthTimeoutMs?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function createTitleUpdater(options?: TitleUpdaterOptions): TitleUpdater;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{VERSION as f}from"./version.js";import{readDaemonState as v}from"./state.js";import{compareVersions as p}from"@agentdock/wire";import{getBrand as h}from"./brand.js";const A={connected:"\u25CF",disconnected:"\u25CB",connecting:"\u25D0",error:"\u2717",offline:"\u2013"},g={connected:"Server",disconnected:"Disconnected",connecting:"Connecting",error:"Error",offline:"Offline"};function S(e){const a=`${A[e.serverStatus]} ${g[e.serverStatus]}`,i=`Daemon ${e.daemonAlive?"\u2713":"\u2717"}`,t=`v${e.version}${e.upgradeAvailable?" \u2191":""}`;return`${h().description} | ${a} | ${i} | ${t}`}function d(e){process.stdout.isTTY&&process.stdout.write(`\x1B]0;${e}\x07`)}async function $(e,a){try{return(await fetch(`http://127.0.0.1:${e}/health`,{signal:AbortSignal.timeout(a)})).ok}catch{return!1}}export function createTitleUpdater(e={}){const a=e.pollIntervalMs??1e4,i=e.healthTimeoutMs??3e3,t={serverStatus:"offline",daemonAlive:e.daemonHttpPort!=null,version:f,upgradeAvailable:!1};let n=null;function o(){d(S(t))}if(o(),e.daemonHttpPort!=null){const r=e.daemonHttpPort,l=e.statePath;n=setInterval(()=>{$(r,i).then(s=>{const m=t.daemonAlive!==s;if(t.daemonAlive=s,l){const c=v(l),u=c?.latestVersion!=null&&p(f,c.latestVersion)<0;if(t.upgradeAvailable!==u){t.upgradeAvailable=u,o();return}}m&&o()})},a),n&&typeof n=="object"&&"unref"in n&&n.unref()}return{setServerStatus(r){t.serverStatus!==r&&(t.serverStatus=r,o())},setDaemonAlive(r){t.daemonAlive!==r&&(t.daemonAlive=r,o())},setUpgradeAvailable(r){t.upgradeAvailable!==r&&(t.upgradeAvailable=r,o())},refresh(){o()},stop(){n&&(clearInterval(n),n=null),d("")}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{randomUUID as o}from"node:crypto";export function loadTokenCredentials(){const e=process.env.ACCESS_TOKEN;if(!e)throw new Error("ACCESS_TOKEN environment variable is required for enterprise edition");const r=process.env.MACHINE_ID||`ent-${o()}`,n=process.env.SERVER_URL||process.env.AGENTDOCK_SERVER_URL||"http://server:3005";return{token:e,machineId:r,serverEndpoint:n}}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";export const MAX_TOOL_RESULT_LEN=1e4,TOOL_RESULT_HEAD_TAIL_KEEP=500;export function truncateToolResult(_){if(_.length<=1e4)return _;const E=_.slice(0,500),L=_.slice(-500),T=_.length-500*2;return`${E}
|
|
2
|
+
|
|
3
|
+
\u2026 [\u7701\u7565 ${T} \u5B57\u7B26] \u2026
|
|
4
|
+
|
|
5
|
+
${L}`}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type AgentName = 'claude' | 'copilot' | 'codex' | 'gemini' | 'generic';
|
|
2
|
+
|
|
3
|
+
export interface TransportHandler {
|
|
4
|
+
readonly agentName: string;
|
|
5
|
+
|
|
6
|
+
getInitTimeout(): number;
|
|
7
|
+
|
|
8
|
+
filterStdoutLine(line: string): string | null;
|
|
9
|
+
|
|
10
|
+
getToolCallTimeout(toolCallId: string): number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export declare function createTransportHandler(agentName: AgentName): TransportHandler;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const n={claude:1e4,copilot:15e3,codex:3e4,gemini:12e4,generic:6e4},i=12e4;function o(r){const t=r.trim();if(!t||!t.startsWith("{")&&!t.startsWith("["))return null;try{return JSON.parse(t),t}catch{return null}}export function createTransportHandler(r){const t=n[r]??n.generic;return{agentName:r,getInitTimeout(){return t},filterStdoutLine(e){return o(e)},getToolCallTimeout(e){return i}}}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function isRecord(v: unknown): v is Record<string, unknown>;
|
|
2
|
+
|
|
3
|
+
export declare function optRecord(v: unknown): Record<string, unknown> | undefined;
|
|
4
|
+
|
|
5
|
+
export declare function optionalStringParam(params: Readonly<Record<string, unknown>>, key: string): string | undefined;
|
|
6
|
+
|
|
7
|
+
export declare function errnoCode(err: unknown): string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export function isRecord(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}export function optRecord(n){return isRecord(n)?n:void 0}export function optionalStringParam(n,e){const r=n[e];return typeof r=="string"?r:void 0}export function errnoCode(n){if(!isRecord(n))return;const e=n.code;return typeof e=="string"?e:void 0}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import f from"node:path";import{getDaemonDir as u}from"./paths.js";import{readJsonFile as a,writeJsonFile as c}from"./jsonFileUtils.js";import{isRecord as s}from"./typeGuards.js";const m="config.json";function t(){return f.join(u(),m)}export function readConfig(){const o=a(t(),{});return s(o)?o:{}}export function isAutoUpgradeEnabled(o){return!(o.autoUpgradeDaemon==="0"||o.autoUpgradeDaemon===0)}export function writeConfig(o){const i=readConfig(),r={};for(const[n,e]of Object.entries(i))(!(n in o)||o[n]!==null)&&(r[n]=e);for(const[n,e]of Object.entries(o))e!==null&&(r[n]=e);c(t(),r)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { VERSION } from './version.g.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const VERSION = "0.0.97";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export const VERSION="0.0.97";
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export{VERSION}from"./version.g.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export function waitForConnection(t,o){return new Promise((n,r)=>{if(t.getStatus()==="connected"){n();return}const i=setTimeout(()=>{e(),r(new Error("Connection timeout"))},o),e=t.onStatusChange(u=>{u==="connected"&&(clearTimeout(i),e(),n())})})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";function e(o){return"'"+o.replace(/'/g,"''")+"'"}export function buildWindowsCommandShim(o,n){return{command:"powershell.exe",args:["-NoLogo","-NoProfile","-ExecutionPolicy","Bypass","-Command",`${"& "+[o,...n].map(i=>e(i)).join(" ")}; if ($null -ne $LASTEXITCODE) { exit $LASTEXITCODE }`]}}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { killProcessTreeByPid } from './processTree.js';
|
|
2
|
+
import type { SessionRegistry } from './sessionRegistry.js';
|
|
3
|
+
import type { Logger } from './logger.js';
|
|
4
|
+
|
|
5
|
+
export interface ReaperResult {
|
|
6
|
+
|
|
7
|
+
readonly killed: number;
|
|
8
|
+
|
|
9
|
+
readonly killedPids: readonly number[];
|
|
10
|
+
|
|
11
|
+
readonly deferredGens: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ProcessSnapshot {
|
|
15
|
+
readonly pid: number;
|
|
16
|
+
readonly commandLine: string;
|
|
17
|
+
readonly creationDate: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type ReaperVerdict = {
|
|
21
|
+
readonly action: 'skip';
|
|
22
|
+
readonly reason: string;
|
|
23
|
+
} | {
|
|
24
|
+
readonly action: 'kill';
|
|
25
|
+
readonly pid: number;
|
|
26
|
+
};
|
|
27
|
+
export declare function parseWmicCliProcessCsv(out: string): ProcessSnapshot[];
|
|
28
|
+
|
|
29
|
+
export declare function parseWmicCreationMs(raw: string): number;
|
|
30
|
+
export declare function classifyProcess(snap: ProcessSnapshot, daemonGen: string, registry: Pick<SessionRegistry, 'list'>, nowMs: number, targetGens?: ReadonlySet<string>): ReaperVerdict;
|
|
31
|
+
|
|
32
|
+
export declare function reapOrphanCliProcesses(log: Logger, daemonGen: string, registry: SessionRegistry, targetGens?: readonly string[]): ReaperResult;
|
|
33
|
+
|
|
34
|
+
export declare function reapCliProcessSnapshots(log: Logger, daemonGen: string, registry: Pick<SessionRegistry, 'list'>, snapshots: readonly ProcessSnapshot[], targetGens?: readonly string[], nowMs?: number, kill?: typeof killProcessTreeByPid): ReaperResult;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{execSync as h}from"node:child_process";import{killProcessTreeByPid as g}from"./processTree.js";const k=process.platform==="win32";function C(){return k?P():[]}export function parseWmicCliProcessCsv(e){const n=e.split(/\r?\n/).filter(r=>r.trim()),o=n.shift();if(!o)return[];if(o.trim()!=="Node,CommandLine,CreationDate,ProcessId")return[];const t=[];for(const r of n){const i=r.match(/^[^,]*,(.*),(\d{14}(?:\.\d+)?[+-]\d+),(\d+)$/);if(!i)continue;const c=(i[1]??"").replace(/^"|"$/g,""),s=i[2]??"",a=Number(i[3]);!Number.isInteger(a)||a<=0||!c.includes("cli.ts start")&&!c.includes("cli.js start")||t.push({pid:a,commandLine:c,creationDate:s})}return t}function P(){try{const e=h(`wmic process where "name='node.exe'" get ProcessId,CommandLine,CreationDate /format:csv`,{encoding:"utf8",timeout:1e4,windowsHide:!0});return parseWmicCliProcessCsv(e)}catch{return[]}}const I=120*1e3;export function parseWmicCreationMs(e){const n=e.match(/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(?:\.\d+)?([+-]\d+)?/);if(!n)return NaN;const o=n[1],t=n[2],r=n[3],i=n[4],c=n[5],s=n[6];if(!o||!t||!r||!i||!c||!s)return NaN;const a=Date.UTC(+o,+t-1,+r,+i,+c,+s),d=n[7],p=d?parseInt(d,10):0;return a-p*6e4}function m(e){const n=e.indexOf("--daemon-gen");if(n===-1)return;const t=e.slice(n+12).trim().split(/\s+/)[0];if(!(!t||t.startsWith("-")))return t}export function classifyProcess(e,n,o,t,r){for(const s of o.list())if(s.pid===e.pid)return{action:"skip",reason:"registered in sessionRegistry"};const i=m(e.commandLine);if(!i)return{action:"skip",reason:"no --daemon-gen (legacy CLI)"};if(i===n)return{action:"skip",reason:"gen matches current daemon"};if(!r)return{action:"skip",reason:"no targetGen (periodic scan)"};if(!r.has(i))return{action:"skip",reason:"gen belongs to a different daemon"};const c=t-parseWmicCreationMs(e.creationDate);return isNaN(c)||c<I?{action:"skip",reason:`age ${Math.round(c/1e3)}s < 120s`}:{action:"kill",pid:e.pid}}export function reapOrphanCliProcesses(e,n,o,t){const r=C();return r.length===0?(e.debug({module:"daemon:reaper"},"no CLI processes found during scan"),{killed:0,killedPids:[],deferredGens:[]}):reapCliProcessSnapshots(e,n,o,r,t)}export function reapCliProcessSnapshots(e,n,o,t,r,i=Date.now(),c=g){if(t.length===0)return{killed:0,killedPids:[],deferredGens:[]};const s=[],a=new Set,d=[],p=r&&r.length>0?new Set(r):void 0;for(const u of t){const f=classifyProcess(u,n,o,i,p);if(f.action==="skip"){const l=m(u.commandLine);l&&p?.has(l)&&f.reason.startsWith("age ")&&a.add(l),d.push({pid:u.pid,reason:f.reason});continue}e.warn({pid:u.pid,age:Math.round((i-parseWmicCreationMs(u.creationDate))/1e3),module:"daemon:reaper"},"zombie reaper: killing orphan CLI process"),c(u.pid),s.push(u.pid)}return s.length>0?e.warn({count:s.length,pids:s,module:"daemon:reaper"},"zombie reaper: killed orphan CLI processes"):d.length>0&&p&&e.debug({skipped:d.length,module:"daemon:reaper"},`zombie reaper: ${d.length} CLI processes skipped`),{killed:s.length,killedPids:s,deferredGens:[...a]}}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentdock/agent-runtime-core",
|
|
3
|
+
"version": "0.0.97",
|
|
4
|
+
"description": "Edition-agnostic Agent runtime core shared by the personal daemon and the enterprise Agent Host",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"author": "CCPark",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"source": "./src/index.ts",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./*": {
|
|
17
|
+
"source": "./src/*.ts",
|
|
18
|
+
"types": "./dist/*.d.ts",
|
|
19
|
+
"default": "./dist/*.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"pino": "^10.3.1",
|
|
27
|
+
"@agentdock/wire": "0.0.97",
|
|
28
|
+
"@agentdock/agent-runtime-contract": "0.0.97",
|
|
29
|
+
"@agentdock/sdk": "0.0.97"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.3.2",
|
|
33
|
+
"typescript": "^5.7.0",
|
|
34
|
+
"vitest": "^3.0.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "node -e \"const{writeFileSync:W}=require('fs');const{version:v}=require('./package.json');const ts='// generated at build time — do not edit\\nexport const VERSION=\\''+v+'\\';\\n';W('src/version.g.ts',ts);W('src/version.g.js',ts);\" && tsc",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"lint": "eslint src/ test/ && tsc --noEmit",
|
|
40
|
+
"typecheck": "tsc --noEmit"
|
|
41
|
+
}
|
|
42
|
+
}
|