@nervekit/orchestrator 0.1.0 → 0.2.0

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 (271) hide show
  1. package/dist/domains/agents/run/agent-run-session.d.ts.map +1 -1
  2. package/dist/domains/agents/run/agent-run-session.js +25 -2
  3. package/dist/domains/agents/run/agent-run-session.js.map +1 -1
  4. package/dist/domains/agents/run/agent-runner.d.ts +12 -1
  5. package/dist/domains/agents/run/agent-runner.d.ts.map +1 -1
  6. package/dist/domains/agents/run/agent-runner.js +166 -1
  7. package/dist/domains/agents/run/agent-runner.js.map +1 -1
  8. package/dist/domains/agents/run/inline-command-results.d.ts +8 -0
  9. package/dist/domains/agents/run/inline-command-results.d.ts.map +1 -0
  10. package/dist/domains/agents/run/inline-command-results.js +109 -0
  11. package/dist/domains/agents/run/inline-command-results.js.map +1 -0
  12. package/dist/domains/tasks/task-manager-foreground.d.ts.map +1 -1
  13. package/dist/domains/tasks/task-manager-foreground.js +4 -1
  14. package/dist/domains/tasks/task-manager-foreground.js.map +1 -1
  15. package/dist/domains/tasks/task-manager.d.ts +2 -1
  16. package/dist/domains/tasks/task-manager.d.ts.map +1 -1
  17. package/dist/domains/tasks/task-manager.js.map +1 -1
  18. package/dist/domains/tasks/task-supervisor.d.ts.map +1 -1
  19. package/dist/domains/tasks/task-supervisor.js +12 -1
  20. package/dist/domains/tasks/task-supervisor.js.map +1 -1
  21. package/dist/domains/tools/orchestration-tool-dispatcher.d.ts.map +1 -1
  22. package/dist/domains/tools/orchestration-tool-dispatcher.js +2 -1
  23. package/dist/domains/tools/orchestration-tool-dispatcher.js.map +1 -1
  24. package/dist/domains/tools/tool-service.d.ts +2 -0
  25. package/dist/domains/tools/tool-service.d.ts.map +1 -1
  26. package/dist/domains/tools/tool-service.js.map +1 -1
  27. package/dist/registry.d.ts +11 -11
  28. package/dist/runtime/runtime-state.d.ts +2 -2
  29. package/dist/web/assets/{dist-DVpGQCt0.js → dist-BaA_eB0I.js} +1 -1
  30. package/dist/web/assets/{index-DFKLdj_D.css → index-C45Kmr75.css} +1 -1
  31. package/dist/web/assets/index-DHfIkEia.js +167 -0
  32. package/dist/web/index.html +2 -2
  33. package/dist/web/sw.js +1 -1
  34. package/package.json +4 -4
  35. package/dist/agent-process.d.ts +0 -32
  36. package/dist/agent-process.d.ts.map +0 -1
  37. package/dist/agent-process.js +0 -129
  38. package/dist/agent-process.js.map +0 -1
  39. package/dist/agent-runner/agent-runner.d.ts +0 -65
  40. package/dist/agent-runner/agent-runner.d.ts.map +0 -1
  41. package/dist/agent-runner/agent-runner.js +0 -802
  42. package/dist/agent-runner/agent-runner.js.map +0 -1
  43. package/dist/agent-runner/index.d.ts +0 -6
  44. package/dist/agent-runner/index.d.ts.map +0 -1
  45. package/dist/agent-runner/index.js +0 -4
  46. package/dist/agent-runner/index.js.map +0 -1
  47. package/dist/agent-runner/message-mirror.d.ts +0 -44
  48. package/dist/agent-runner/message-mirror.d.ts.map +0 -1
  49. package/dist/agent-runner/message-mirror.js +0 -154
  50. package/dist/agent-runner/message-mirror.js.map +0 -1
  51. package/dist/agent-runner/run-state.d.ts +0 -12
  52. package/dist/agent-runner/run-state.d.ts.map +0 -1
  53. package/dist/agent-runner/run-state.js +0 -2
  54. package/dist/agent-runner/run-state.js.map +0 -1
  55. package/dist/agent-runner/subagent-runner.d.ts +0 -29
  56. package/dist/agent-runner/subagent-runner.d.ts.map +0 -1
  57. package/dist/agent-runner/subagent-runner.js +0 -84
  58. package/dist/agent-runner/subagent-runner.js.map +0 -1
  59. package/dist/agent-runner/system-prompt-builder.d.ts +0 -19
  60. package/dist/agent-runner/system-prompt-builder.d.ts.map +0 -1
  61. package/dist/agent-runner/system-prompt-builder.js +0 -35
  62. package/dist/agent-runner/system-prompt-builder.js.map +0 -1
  63. package/dist/agent-runner/tool-draft-streaming.d.ts +0 -2
  64. package/dist/agent-runner/tool-draft-streaming.d.ts.map +0 -1
  65. package/dist/agent-runner/tool-draft-streaming.js +0 -5
  66. package/dist/agent-runner/tool-draft-streaming.js.map +0 -1
  67. package/dist/agent-suspension-service.d.ts +0 -44
  68. package/dist/agent-suspension-service.d.ts.map +0 -1
  69. package/dist/agent-suspension-service.js +0 -96
  70. package/dist/agent-suspension-service.js.map +0 -1
  71. package/dist/agent-tool-adapter.d.ts +0 -20
  72. package/dist/agent-tool-adapter.d.ts.map +0 -1
  73. package/dist/agent-tool-adapter.js +0 -215
  74. package/dist/agent-tool-adapter.js.map +0 -1
  75. package/dist/agents/agent-authority.d.ts +0 -5
  76. package/dist/agents/agent-authority.d.ts.map +0 -1
  77. package/dist/agents/agent-authority.js +0 -28
  78. package/dist/agents/agent-authority.js.map +0 -1
  79. package/dist/agents/agent-budget.d.ts +0 -3
  80. package/dist/agents/agent-budget.d.ts.map +0 -1
  81. package/dist/agents/agent-budget.js +0 -17
  82. package/dist/agents/agent-budget.js.map +0 -1
  83. package/dist/agents/agent-status.d.ts +0 -4
  84. package/dist/agents/agent-status.d.ts.map +0 -1
  85. package/dist/agents/agent-status.js +0 -10
  86. package/dist/agents/agent-status.js.map +0 -1
  87. package/dist/conversation-operations/compaction-service.d.ts +0 -37
  88. package/dist/conversation-operations/compaction-service.d.ts.map +0 -1
  89. package/dist/conversation-operations/compaction-service.js +0 -102
  90. package/dist/conversation-operations/compaction-service.js.map +0 -1
  91. package/dist/conversation-operations/export-service.d.ts +0 -22
  92. package/dist/conversation-operations/export-service.d.ts.map +0 -1
  93. package/dist/conversation-operations/export-service.js +0 -79
  94. package/dist/conversation-operations/export-service.js.map +0 -1
  95. package/dist/conversation-operations/import-service.d.ts +0 -20
  96. package/dist/conversation-operations/import-service.d.ts.map +0 -1
  97. package/dist/conversation-operations/import-service.js +0 -97
  98. package/dist/conversation-operations/import-service.js.map +0 -1
  99. package/dist/conversation-operations/index.d.ts +0 -8
  100. package/dist/conversation-operations/index.d.ts.map +0 -1
  101. package/dist/conversation-operations/index.js +0 -6
  102. package/dist/conversation-operations/index.js.map +0 -1
  103. package/dist/conversation-operations/navigation-service.d.ts +0 -18
  104. package/dist/conversation-operations/navigation-service.d.ts.map +0 -1
  105. package/dist/conversation-operations/navigation-service.js +0 -102
  106. package/dist/conversation-operations/navigation-service.js.map +0 -1
  107. package/dist/conversation-operations/summary.d.ts +0 -11
  108. package/dist/conversation-operations/summary.d.ts.map +0 -1
  109. package/dist/conversation-operations/summary.js +0 -29
  110. package/dist/conversation-operations/summary.js.map +0 -1
  111. package/dist/conversation-runtime.d.ts +0 -96
  112. package/dist/conversation-runtime.d.ts.map +0 -1
  113. package/dist/conversation-runtime.js +0 -363
  114. package/dist/conversation-runtime.js.map +0 -1
  115. package/dist/conversation-service.d.ts +0 -17
  116. package/dist/conversation-service.d.ts.map +0 -1
  117. package/dist/conversation-service.js +0 -56
  118. package/dist/conversation-service.js.map +0 -1
  119. package/dist/domains/processes/index.d.ts +0 -10
  120. package/dist/domains/processes/index.d.ts.map +0 -1
  121. package/dist/domains/processes/index.js +0 -7
  122. package/dist/domains/processes/index.js.map +0 -1
  123. package/dist/domains/processes/process-launch-config.store.d.ts +0 -21
  124. package/dist/domains/processes/process-launch-config.store.d.ts.map +0 -1
  125. package/dist/domains/processes/process-launch-config.store.js +0 -49
  126. package/dist/domains/processes/process-launch-config.store.js.map +0 -1
  127. package/dist/domains/processes/process-log.service.d.ts +0 -25
  128. package/dist/domains/processes/process-log.service.d.ts.map +0 -1
  129. package/dist/domains/processes/process-log.service.js +0 -155
  130. package/dist/domains/processes/process-log.service.js.map +0 -1
  131. package/dist/domains/processes/process-manager.d.ts +0 -107
  132. package/dist/domains/processes/process-manager.d.ts.map +0 -1
  133. package/dist/domains/processes/process-manager.js +0 -814
  134. package/dist/domains/processes/process-manager.js.map +0 -1
  135. package/dist/domains/processes/process-readiness.service.d.ts +0 -7
  136. package/dist/domains/processes/process-readiness.service.d.ts.map +0 -1
  137. package/dist/domains/processes/process-readiness.service.js +0 -26
  138. package/dist/domains/processes/process-readiness.service.js.map +0 -1
  139. package/dist/domains/processes/process-status.d.ts +0 -5
  140. package/dist/domains/processes/process-status.d.ts.map +0 -1
  141. package/dist/domains/processes/process-status.js +0 -13
  142. package/dist/domains/processes/process-status.js.map +0 -1
  143. package/dist/domains/processes/process-supervisor.d.ts +0 -34
  144. package/dist/domains/processes/process-supervisor.d.ts.map +0 -1
  145. package/dist/domains/processes/process-supervisor.js +0 -211
  146. package/dist/domains/processes/process-supervisor.js.map +0 -1
  147. package/dist/domains/processes/process.repository.d.ts +0 -11
  148. package/dist/domains/processes/process.repository.d.ts.map +0 -1
  149. package/dist/domains/processes/process.repository.js +0 -31
  150. package/dist/domains/processes/process.repository.js.map +0 -1
  151. package/dist/domains/tasks/task-completion.service.d.ts +0 -31
  152. package/dist/domains/tasks/task-completion.service.d.ts.map +0 -1
  153. package/dist/domains/tasks/task-completion.service.js +0 -147
  154. package/dist/domains/tasks/task-completion.service.js.map +0 -1
  155. package/dist/domains/tasks/task-legacy-migration.d.ts +0 -15
  156. package/dist/domains/tasks/task-legacy-migration.d.ts.map +0 -1
  157. package/dist/domains/tasks/task-legacy-migration.js +0 -191
  158. package/dist/domains/tasks/task-legacy-migration.js.map +0 -1
  159. package/dist/events.d.ts +0 -2
  160. package/dist/events.d.ts.map +0 -1
  161. package/dist/events.js +0 -2
  162. package/dist/events.js.map +0 -1
  163. package/dist/git/git-service.d.ts +0 -51
  164. package/dist/git/git-service.d.ts.map +0 -1
  165. package/dist/git/git-service.js +0 -716
  166. package/dist/git/git-service.js.map +0 -1
  167. package/dist/git/git-status.d.ts +0 -24
  168. package/dist/git/git-status.d.ts.map +0 -1
  169. package/dist/git/git-status.js +0 -133
  170. package/dist/git/git-status.js.map +0 -1
  171. package/dist/harness-manager.d.ts +0 -21
  172. package/dist/harness-manager.d.ts.map +0 -1
  173. package/dist/harness-manager.js +0 -105
  174. package/dist/harness-manager.js.map +0 -1
  175. package/dist/index-store.d.ts +0 -2
  176. package/dist/index-store.d.ts.map +0 -1
  177. package/dist/index-store.js +0 -2
  178. package/dist/index-store.js.map +0 -1
  179. package/dist/plan-paths.d.ts +0 -6
  180. package/dist/plan-paths.d.ts.map +0 -1
  181. package/dist/plan-paths.js +0 -30
  182. package/dist/plan-paths.js.map +0 -1
  183. package/dist/plan-service.d.ts +0 -61
  184. package/dist/plan-service.d.ts.map +0 -1
  185. package/dist/plan-service.js +0 -255
  186. package/dist/plan-service.js.map +0 -1
  187. package/dist/policy.d.ts +0 -14
  188. package/dist/policy.d.ts.map +0 -1
  189. package/dist/policy.js +0 -247
  190. package/dist/policy.js.map +0 -1
  191. package/dist/process-manager.d.ts +0 -72
  192. package/dist/process-manager.d.ts.map +0 -1
  193. package/dist/process-manager.js +0 -376
  194. package/dist/process-manager.js.map +0 -1
  195. package/dist/registry/agent-lifecycle-service.d.ts +0 -38
  196. package/dist/registry/agent-lifecycle-service.d.ts.map +0 -1
  197. package/dist/registry/agent-lifecycle-service.js +0 -199
  198. package/dist/registry/agent-lifecycle-service.js.map +0 -1
  199. package/dist/registry/conversation-lifecycle-service.d.ts +0 -35
  200. package/dist/registry/conversation-lifecycle-service.d.ts.map +0 -1
  201. package/dist/registry/conversation-lifecycle-service.js +0 -136
  202. package/dist/registry/conversation-lifecycle-service.js.map +0 -1
  203. package/dist/registry/pinned-command-service.d.ts +0 -11
  204. package/dist/registry/pinned-command-service.d.ts.map +0 -1
  205. package/dist/registry/pinned-command-service.js +0 -40
  206. package/dist/registry/pinned-command-service.js.map +0 -1
  207. package/dist/registry/project-lifecycle-service.d.ts +0 -22
  208. package/dist/registry/project-lifecycle-service.d.ts.map +0 -1
  209. package/dist/registry/project-lifecycle-service.js +0 -87
  210. package/dist/registry/project-lifecycle-service.js.map +0 -1
  211. package/dist/repositories/agent-repository.d.ts +0 -12
  212. package/dist/repositories/agent-repository.d.ts.map +0 -1
  213. package/dist/repositories/agent-repository.js +0 -33
  214. package/dist/repositories/agent-repository.js.map +0 -1
  215. package/dist/repositories/conversation-repository.d.ts +0 -13
  216. package/dist/repositories/conversation-repository.d.ts.map +0 -1
  217. package/dist/repositories/conversation-repository.js +0 -39
  218. package/dist/repositories/conversation-repository.js.map +0 -1
  219. package/dist/repositories/entry-repository.d.ts +0 -15
  220. package/dist/repositories/entry-repository.d.ts.map +0 -1
  221. package/dist/repositories/entry-repository.js +0 -81
  222. package/dist/repositories/entry-repository.js.map +0 -1
  223. package/dist/repositories/index.d.ts +0 -7
  224. package/dist/repositories/index.d.ts.map +0 -1
  225. package/dist/repositories/index.js +0 -7
  226. package/dist/repositories/index.js.map +0 -1
  227. package/dist/repositories/pinned-command-repository.d.ts +0 -10
  228. package/dist/repositories/pinned-command-repository.d.ts.map +0 -1
  229. package/dist/repositories/pinned-command-repository.js +0 -28
  230. package/dist/repositories/pinned-command-repository.js.map +0 -1
  231. package/dist/repositories/project-repository.d.ts +0 -12
  232. package/dist/repositories/project-repository.d.ts.map +0 -1
  233. package/dist/repositories/project-repository.js +0 -33
  234. package/dist/repositories/project-repository.js.map +0 -1
  235. package/dist/repositories/prompt-queue-repository.d.ts +0 -28
  236. package/dist/repositories/prompt-queue-repository.d.ts.map +0 -1
  237. package/dist/repositories/prompt-queue-repository.js +0 -88
  238. package/dist/repositories/prompt-queue-repository.js.map +0 -1
  239. package/dist/routes/process-routes.d.ts +0 -4
  240. package/dist/routes/process-routes.d.ts.map +0 -1
  241. package/dist/routes/process-routes.js +0 -43
  242. package/dist/routes/process-routes.js.map +0 -1
  243. package/dist/storage.d.ts +0 -2
  244. package/dist/storage.d.ts.map +0 -1
  245. package/dist/storage.js +0 -2
  246. package/dist/storage.js.map +0 -1
  247. package/dist/tool-service.d.ts +0 -82
  248. package/dist/tool-service.d.ts.map +0 -1
  249. package/dist/tool-service.js +0 -409
  250. package/dist/tool-service.js.map +0 -1
  251. package/dist/transcription-service.d.ts +0 -15
  252. package/dist/transcription-service.d.ts.map +0 -1
  253. package/dist/transcription-service.js +0 -128
  254. package/dist/transcription-service.js.map +0 -1
  255. package/dist/usage/anthropic-client.d.ts +0 -9
  256. package/dist/usage/anthropic-client.d.ts.map +0 -1
  257. package/dist/usage/anthropic-client.js +0 -207
  258. package/dist/usage/anthropic-client.js.map +0 -1
  259. package/dist/usage/codex-client.d.ts +0 -18
  260. package/dist/usage/codex-client.d.ts.map +0 -1
  261. package/dist/usage/codex-client.js +0 -316
  262. package/dist/usage/codex-client.js.map +0 -1
  263. package/dist/usage/subscription-usage-service.d.ts +0 -42
  264. package/dist/usage/subscription-usage-service.d.ts.map +0 -1
  265. package/dist/usage/subscription-usage-service.js +0 -131
  266. package/dist/usage/subscription-usage-service.js.map +0 -1
  267. package/dist/web/assets/index-DP6SGqvJ.js +0 -165
  268. package/dist/worker-manager.d.ts +0 -51
  269. package/dist/worker-manager.d.ts.map +0 -1
  270. package/dist/worker-manager.js +0 -116
  271. package/dist/worker-manager.js.map +0 -1
@@ -1,814 +0,0 @@
1
- import { mkdir } from "node:fs/promises";
2
- import { join, resolve } from "node:path";
3
- import { setTimeout as delay } from "node:timers/promises";
4
- import { createId, } from "@nerve/shared";
5
- import { createProcessLogCursor, defaultProcessSupervisor, isActiveProcessStatus, ProcessLogService, ProcessReadinessService, ProcessRepository, } from "./index.js";
6
- import { UnconfiguredProcessLaunchConfigStore, } from "./process-launch-config.store.js";
7
- export class ProcessManager {
8
- events;
9
- index;
10
- logger;
11
- processes = new Map();
12
- managed = new Map();
13
- processRepository;
14
- processLogs;
15
- processReadiness = new ProcessReadinessService();
16
- supervisor;
17
- launchConfigs;
18
- constructor(storage, events, index, logger, options = {}) {
19
- this.events = events;
20
- this.index = index;
21
- this.logger = logger;
22
- this.supervisor = options.supervisor ?? defaultProcessSupervisor;
23
- this.launchConfigs =
24
- options.launchConfigs ?? new UnconfiguredProcessLaunchConfigStore();
25
- this.processRepository = new ProcessRepository(storage);
26
- this.processLogs = new ProcessLogService(events);
27
- }
28
- async hydrate() {
29
- for (const persisted of await this.processRepository.hydrate()) {
30
- const wasActive = isActiveProcessStatus(persisted.status);
31
- const record = wasActive
32
- ? this.markHydratedRecordOrphaned(persisted)
33
- : persisted;
34
- await this.upsertProcess(record);
35
- if (wasActive) {
36
- await this.events.publish("process.orphaned", { process: record });
37
- await this.logger?.warn("Process supervision lost after daemon restart", {
38
- processId: record.id,
39
- projectId: record.projectId,
40
- conversationId: record.conversationId,
41
- agentId: record.agentId,
42
- context: {
43
- pid: record.runtime?.childPid,
44
- processGroupId: record.runtime?.processGroupId,
45
- platform: record.runtime?.platform,
46
- },
47
- });
48
- }
49
- }
50
- }
51
- listProcesses() {
52
- return [...this.processes.values()].sort((a, b) => b.startedAt.localeCompare(a.startedAt));
53
- }
54
- getProcess(processId) {
55
- const process = this.processes.get(processId);
56
- if (!process)
57
- throw new Error("Process not found.");
58
- return process;
59
- }
60
- findProcessByName(name) {
61
- return this.listProcesses().find((process) => process.name === name);
62
- }
63
- async startProcess(request) {
64
- const now = new Date().toISOString();
65
- const id = createId("proc");
66
- const dir = this.processDir(id);
67
- await mkdir(dir, { recursive: true, mode: 0o755 });
68
- const envInfo = buildProcessEnvInfo(request.env);
69
- if (envInfo) {
70
- await this.launchConfigs.write(id, {
71
- version: 1,
72
- env: request.env,
73
- createdAt: now,
74
- updatedAt: now,
75
- });
76
- }
77
- const readiness = this.processReadiness.buildReadiness(request);
78
- const record = {
79
- id,
80
- name: request.name,
81
- workerId: request.workerId,
82
- projectId: request.projectId,
83
- conversationId: request.conversationId,
84
- agentId: request.agentId,
85
- cwd: resolve(request.cwd),
86
- command: request.command,
87
- envInfo,
88
- status: "starting",
89
- readiness,
90
- stdoutPath: join(dir, "stdout.log"),
91
- stderrPath: join(dir, "stderr.log"),
92
- logsPath: join(dir, "logs.jsonl"),
93
- startedAt: now,
94
- updatedAt: now,
95
- restartedFromProcessId: request.restartedFromProcessId,
96
- };
97
- const readinessPattern = this.processReadiness.compilePattern(request.readyPattern);
98
- await this.upsertProcess(record);
99
- await this.events.publish("process.created", { process: record });
100
- await this.logger?.info("Process created", {
101
- processId: record.id,
102
- projectId: record.projectId,
103
- conversationId: record.conversationId,
104
- agentId: record.agentId,
105
- context: {
106
- name: record.name,
107
- cwd: record.cwd,
108
- command: record.command,
109
- envKeyCount: record.envInfo?.keys.length ?? 0,
110
- },
111
- });
112
- const spawned = this.supervisor.spawn(request.command, {
113
- cwd: record.cwd,
114
- env: request.env,
115
- });
116
- const { child, runtime } = spawned;
117
- await this.updateProcess(record.id, { runtime });
118
- const closePromise = new Promise((resolveClose) => {
119
- child.once("close", (exitCode, signal) => {
120
- resolveClose({ exitCode, signal });
121
- });
122
- });
123
- const managed = {
124
- child,
125
- ...createProcessLogCursor(await this.processLogs.latestLogSeq(record.logsPath)),
126
- stopping: false,
127
- finalized: false,
128
- closePromise,
129
- readinessPattern,
130
- };
131
- managed.finalizationPromise = closePromise
132
- .then(({ exitCode, signal }) => this.markProcessExited(record.id, exitCode, signal))
133
- .catch(async (error) => {
134
- if (this.logger) {
135
- await this.logger
136
- .error("Process finalization failed", {
137
- processId: record.id,
138
- projectId: record.projectId,
139
- conversationId: record.conversationId,
140
- agentId: record.agentId,
141
- error,
142
- })
143
- .catch(() => undefined);
144
- }
145
- return undefined;
146
- });
147
- this.managed.set(record.id, managed);
148
- child.stdout?.on("data", (chunk) => {
149
- void this.captureOutput(record.id, "stdout", chunk);
150
- });
151
- child.stderr?.on("data", (chunk) => {
152
- void this.captureOutput(record.id, "stderr", chunk);
153
- });
154
- child.on("error", (error) => {
155
- void this.markProcessError(record.id, error.message);
156
- });
157
- await this.updateProcess(record.id, { status: "running" });
158
- await this.events.publish("process.started", {
159
- process: this.getProcess(record.id),
160
- pid: runtime.childPid,
161
- runtime,
162
- });
163
- await this.logger?.info("Process started", {
164
- processId: record.id,
165
- projectId: record.projectId,
166
- conversationId: record.conversationId,
167
- agentId: record.agentId,
168
- context: {
169
- pid: runtime.childPid,
170
- processGroupId: runtime.processGroupId,
171
- platform: runtime.platform,
172
- },
173
- });
174
- await this.waitForReadiness(record.id);
175
- return this.getProcess(record.id);
176
- }
177
- async stopProcess(processId, request = {}) {
178
- const record = this.getProcess(processId);
179
- if (record.status === "orphaned") {
180
- return this.cleanupOrphanedProcess(record.id, request);
181
- }
182
- const managed = this.managed.get(record.id);
183
- if (!managed?.child || !isActiveProcessStatus(record.status))
184
- return record;
185
- const signal = request.signal ?? "SIGTERM";
186
- managed.stopping = true;
187
- const stopping = await this.updateProcess(record.id, {
188
- status: "stopping",
189
- });
190
- await this.events.publish("process.stop_requested", {
191
- processId: record.id,
192
- signal,
193
- });
194
- await this.logger?.info("Process stop requested", {
195
- processId: record.id,
196
- projectId: record.projectId,
197
- conversationId: record.conversationId,
198
- agentId: record.agentId,
199
- context: { signal },
200
- });
201
- void this.requestTermination(stopping, managed.child, signal, "stop requested");
202
- const timeoutMs = request.timeoutMs ?? 5000;
203
- const timeoutResult = Symbol("process-stop-timeout");
204
- let timeout;
205
- const finalized = await Promise.race([
206
- managed.finalizationPromise ?? Promise.resolve(undefined),
207
- new Promise((resolveTimeout) => {
208
- timeout = setTimeout(() => resolveTimeout(timeoutResult), timeoutMs);
209
- }),
210
- ]).finally(() => {
211
- if (timeout)
212
- clearTimeout(timeout);
213
- });
214
- if (finalized !== timeoutResult) {
215
- return finalized ?? this.getProcess(processId);
216
- }
217
- void this.requestTermination(this.processes.get(processId) ?? stopping, managed.child, "SIGKILL", `stop timed out after ${timeoutMs}ms`);
218
- return this.forceFinalizeStoppedProcess(processId, "SIGKILL", `Process did not close within ${timeoutMs}ms after stop was requested.`);
219
- }
220
- async restartProcess(processId) {
221
- const record = this.getProcess(processId);
222
- const env = await this.envForRestart(record);
223
- if (record.status === "orphaned") {
224
- await this.cleanupOrphanedProcess(record.id, { timeoutMs: 5000 });
225
- }
226
- else if (isActiveProcessStatus(record.status)) {
227
- await this.stopProcess(processId);
228
- }
229
- return this.startProcess({
230
- name: record.name,
231
- workerId: record.workerId,
232
- projectId: record.projectId,
233
- conversationId: record.conversationId,
234
- agentId: record.agentId,
235
- cwd: record.cwd,
236
- command: record.command,
237
- env,
238
- readyOnUrl: record.readiness.readyOnUrl,
239
- readyPattern: record.readiness.readyPattern,
240
- readyTimeoutMs: record.readiness.timeoutMs,
241
- restartedFromProcessId: record.id,
242
- });
243
- }
244
- async removeProcess(processId) {
245
- const record = this.getProcess(processId);
246
- if (isActiveProcessStatus(record.status)) {
247
- throw new Error("Stop the process before removing it.");
248
- }
249
- await this.launchConfigs.remove(record.id);
250
- const managed = this.managed.get(record.id);
251
- if (managed?.readinessTimer)
252
- clearTimeout(managed.readinessTimer);
253
- this.managed.delete(record.id);
254
- this.processes.delete(record.id);
255
- this.index.deleteProcess(record.id);
256
- await this.processRepository.remove(record.id);
257
- await this.events.publish("process.removed", { processId: record.id });
258
- await this.logger?.info("Process removed", {
259
- processId: record.id,
260
- projectId: record.projectId,
261
- conversationId: record.conversationId,
262
- agentId: record.agentId,
263
- });
264
- }
265
- async pruneProcesses() {
266
- const removed = [];
267
- for (const record of this.listProcesses()) {
268
- if (isActiveProcessStatus(record.status))
269
- continue;
270
- try {
271
- await this.removeProcess(record.id);
272
- removed.push(record.id);
273
- }
274
- catch {
275
- // Best-effort: skip processes that can't be removed right now.
276
- }
277
- }
278
- return removed;
279
- }
280
- activeProcessesForConversations(conversationIds) {
281
- const conversations = new Set(conversationIds);
282
- if (conversations.size === 0)
283
- return [];
284
- return this.listProcesses().filter((record) => record.conversationId !== undefined &&
285
- conversations.has(record.conversationId) &&
286
- isActiveProcessStatus(record.status));
287
- }
288
- async removeInactiveProcessesForConversations(conversationIds) {
289
- const conversations = new Set(conversationIds);
290
- if (conversations.size === 0)
291
- return [];
292
- const removed = [];
293
- for (const record of this.listProcesses()) {
294
- if (!record.conversationId || !conversations.has(record.conversationId)) {
295
- continue;
296
- }
297
- if (isActiveProcessStatus(record.status))
298
- continue;
299
- try {
300
- await this.removeProcess(record.id);
301
- removed.push(record.id);
302
- }
303
- catch {
304
- // Best-effort: skip processes that can't be removed right now.
305
- }
306
- }
307
- return removed;
308
- }
309
- async queryLogs(processId, query = {}) {
310
- return this.processLogs.queryLogs(this.getProcess(processId), query);
311
- }
312
- async envForRestart(record) {
313
- if (!record.envInfo?.persisted)
314
- return undefined;
315
- const config = await this.launchConfigs.read(record.id);
316
- if (!config) {
317
- throw new Error("Process was started with persisted env metadata, but launch env is missing; refusing to restart without env.");
318
- }
319
- const env = config.env;
320
- const missingKeys = record.envInfo.keys.filter((key) => !env || !Object.hasOwn(env, key));
321
- if (missingKeys.length > 0) {
322
- throw new Error(`Process launch env is missing persisted keys (${missingKeys.join(", ")}); refusing to restart without env.`);
323
- }
324
- return env ? { ...env } : undefined;
325
- }
326
- async captureOutput(processId, stream, chunk) {
327
- const record = this.processes.get(processId);
328
- const managed = this.managed.get(processId);
329
- if (!record || !managed)
330
- return;
331
- await this.processLogs.captureOutput(record, managed, stream, chunk, async (event) => this.checkReadiness(record.id, event));
332
- }
333
- async flushProcessOutputBuffers(processId) {
334
- const record = this.processes.get(processId);
335
- const managed = this.managed.get(processId);
336
- if (!record || !managed)
337
- return;
338
- try {
339
- await this.processLogs.flushOutputBuffers(record, managed, async (event) => this.checkReadiness(record.id, event));
340
- }
341
- catch (error) {
342
- await this.logger
343
- ?.warn("Process output flush failed", {
344
- processId: record.id,
345
- projectId: record.projectId,
346
- conversationId: record.conversationId,
347
- agentId: record.agentId,
348
- error,
349
- })
350
- .catch(() => undefined);
351
- }
352
- }
353
- async checkReadiness(processId, log) {
354
- const record = this.processes.get(processId);
355
- const managed = this.managed.get(processId);
356
- if (!record || !managed || record.readiness.outcome !== "pending")
357
- return;
358
- const matched = this.processReadiness.match(record, managed.readinessPattern, log);
359
- if (!matched)
360
- return;
361
- if (managed.readinessTimer)
362
- clearTimeout(managed.readinessTimer);
363
- const ready = await this.updateProcess(processId, {
364
- status: "ready",
365
- readiness: {
366
- ...record.readiness,
367
- outcome: "ready",
368
- matched,
369
- readyAt: new Date().toISOString(),
370
- },
371
- });
372
- await this.events.publish("process.ready", { process: ready, matched });
373
- await this.logger?.info("Process ready", {
374
- processId: ready.id,
375
- projectId: ready.projectId,
376
- conversationId: ready.conversationId,
377
- agentId: ready.agentId,
378
- context: { matched },
379
- });
380
- }
381
- async waitForReadiness(processId) {
382
- const record = this.getProcess(processId);
383
- if (record.readiness.outcome !== "pending")
384
- return;
385
- const managed = this.managed.get(processId);
386
- const timeoutMs = record.readiness.timeoutMs ?? 3000;
387
- if (!managed || timeoutMs <= 0)
388
- return;
389
- await new Promise((resolveWait) => {
390
- let unsubscribe = () => undefined;
391
- const resolveOnce = () => {
392
- unsubscribe();
393
- resolveWait();
394
- };
395
- managed.readinessTimer = setTimeout(() => {
396
- void this.markReadinessTimeout(processId).finally(resolveOnce);
397
- }, timeoutMs);
398
- unsubscribe = this.events.subscribe((event) => {
399
- if (event.type !== "process.ready" && event.type !== "process.exited")
400
- return;
401
- const data = event.data;
402
- if (data.process?.id !== processId)
403
- return;
404
- resolveOnce();
405
- });
406
- });
407
- }
408
- async markReadinessTimeout(processId) {
409
- const record = this.processes.get(processId);
410
- if (!record || record.readiness.outcome !== "pending")
411
- return;
412
- const updated = await this.updateProcess(processId, {
413
- readiness: { ...record.readiness, outcome: "timeout" },
414
- });
415
- await this.events.publish("process.ready_timeout", { process: updated });
416
- await this.logger?.warn("Process readiness timed out", {
417
- processId: updated.id,
418
- projectId: updated.projectId,
419
- conversationId: updated.conversationId,
420
- agentId: updated.agentId,
421
- context: { timeoutMs: updated.readiness.timeoutMs },
422
- });
423
- }
424
- async requestTermination(record, child, signal, reason) {
425
- try {
426
- const result = await this.supervisor.terminate(child, signal);
427
- if (!result.error)
428
- return;
429
- if (this.logger) {
430
- await this.logger
431
- .warn("Process termination reported an error", {
432
- processId: record.id,
433
- projectId: record.projectId,
434
- conversationId: record.conversationId,
435
- agentId: record.agentId,
436
- context: {
437
- signal,
438
- reason,
439
- method: result.method,
440
- error: result.error,
441
- },
442
- })
443
- .catch(() => undefined);
444
- }
445
- }
446
- catch (error) {
447
- if (this.logger) {
448
- await this.logger
449
- .warn("Process termination failed", {
450
- processId: record.id,
451
- projectId: record.projectId,
452
- conversationId: record.conversationId,
453
- agentId: record.agentId,
454
- error,
455
- context: { signal, reason },
456
- })
457
- .catch(() => undefined);
458
- }
459
- }
460
- }
461
- markHydratedRecordOrphaned(record) {
462
- return {
463
- ...record,
464
- status: "orphaned",
465
- error: this.orphanedHydrateMessage(record.runtime),
466
- updatedAt: new Date().toISOString(),
467
- };
468
- }
469
- orphanedHydrateMessage(runtime) {
470
- if (runtime?.childPid) {
471
- return `Process supervision was lost after daemon restart. Use process_stop to attempt cleanup of PID ${runtime.childPid}.`;
472
- }
473
- if (runtime?.processGroupId) {
474
- return `Process supervision was lost after daemon restart. Use process_stop to attempt cleanup of process group ${runtime.processGroupId}.`;
475
- }
476
- return "Process supervision was lost after daemon restart, and no PID metadata was captured.";
477
- }
478
- async cleanupOrphanedProcess(processId, request) {
479
- const record = this.getProcess(processId);
480
- if (record.status !== "orphaned")
481
- return record;
482
- const validationError = this.orphanCleanupValidationError(record.runtime);
483
- if (validationError) {
484
- await this.failOrphanCleanup(record, validationError);
485
- }
486
- const runtime = record.runtime;
487
- const initialSignal = request.signal ?? "SIGTERM";
488
- const timeoutMs = request.timeoutMs ?? 5000;
489
- await this.events.publish("process.stop_requested", {
490
- processId: record.id,
491
- signal: initialSignal,
492
- orphaned: true,
493
- });
494
- await this.logger?.info("Orphaned process cleanup requested", {
495
- processId: record.id,
496
- projectId: record.projectId,
497
- conversationId: record.conversationId,
498
- agentId: record.agentId,
499
- context: this.runtimeLogContext(runtime, { signal: initialSignal }),
500
- });
501
- if (runtime.platform === "win32") {
502
- const result = await this.terminateRuntimeForCleanup(record, runtime, "SIGKILL");
503
- if (!result.attempted || result.error) {
504
- await this.failOrphanCleanup(record, result.error ?? "Could not clean up orphaned process runtime target.", { method: result.method, signal: "SIGKILL" });
505
- }
506
- return this.finalizeOrphanCleanup(record.id, "SIGKILL", runtime, {
507
- method: result.method,
508
- });
509
- }
510
- const initialResult = await this.terminateRuntimeForCleanup(record, runtime, initialSignal);
511
- if (!initialResult.attempted || initialResult.method === "none") {
512
- await this.failOrphanCleanup(record, initialResult.error ??
513
- "Could not signal orphaned process runtime target.", { method: initialResult.method, signal: initialSignal });
514
- }
515
- if (initialResult.error) {
516
- await this.logger?.warn("Orphaned process cleanup signal reported an error", {
517
- processId: record.id,
518
- projectId: record.projectId,
519
- conversationId: record.conversationId,
520
- agentId: record.agentId,
521
- context: this.runtimeLogContext(runtime, {
522
- signal: initialSignal,
523
- method: initialResult.method,
524
- error: initialResult.error,
525
- }),
526
- });
527
- }
528
- let finalSignal = initialSignal;
529
- if (!(await this.waitForRuntimeTargetExit(runtime, timeoutMs))) {
530
- finalSignal = "SIGKILL";
531
- const killResult = await this.terminateRuntimeForCleanup(record, runtime, finalSignal);
532
- if (!killResult.attempted || killResult.method === "none") {
533
- await this.failOrphanCleanup(record, killResult.error ??
534
- "Could not force-kill orphaned process runtime target.", { method: killResult.method, signal: finalSignal });
535
- }
536
- if (killResult.error && (await this.isRuntimeTargetAlive(runtime))) {
537
- await this.failOrphanCleanup(record, killResult.error, {
538
- method: killResult.method,
539
- signal: finalSignal,
540
- });
541
- }
542
- }
543
- return this.finalizeOrphanCleanup(record.id, finalSignal, runtime);
544
- }
545
- orphanCleanupValidationError(runtime) {
546
- if (!runtime) {
547
- return "Cannot clean up orphaned process because no PID metadata was captured.";
548
- }
549
- if (runtime.platform !== process.platform) {
550
- return `Cannot clean up process spawned on ${runtime.platform} from ${process.platform}.`;
551
- }
552
- if (runtime.platform === "win32" && !runtime.childPid) {
553
- return "Cannot clean up orphaned process because no child PID metadata was captured.";
554
- }
555
- if (runtime.platform !== "win32" &&
556
- !runtime.processGroupId &&
557
- !runtime.childPid) {
558
- return "Cannot clean up orphaned process because no process-group or child PID metadata was captured.";
559
- }
560
- return undefined;
561
- }
562
- async terminateRuntimeForCleanup(record, runtime, signal) {
563
- try {
564
- return await this.supervisor.terminateRuntime(runtime, signal);
565
- }
566
- catch (error) {
567
- await this.logger?.warn("Orphaned process cleanup termination threw", {
568
- processId: record.id,
569
- projectId: record.projectId,
570
- conversationId: record.conversationId,
571
- agentId: record.agentId,
572
- error,
573
- context: this.runtimeLogContext(runtime, { signal }),
574
- });
575
- return {
576
- attempted: false,
577
- method: "none",
578
- error: this.errorMessage(error),
579
- };
580
- }
581
- }
582
- async waitForRuntimeTargetExit(runtime, timeoutMs) {
583
- const deadline = Date.now() + Math.max(0, timeoutMs);
584
- while (true) {
585
- if (!(await this.isRuntimeTargetAlive(runtime)))
586
- return true;
587
- const remaining = deadline - Date.now();
588
- if (remaining <= 0)
589
- return false;
590
- await delay(Math.min(50, remaining));
591
- }
592
- }
593
- async isRuntimeTargetAlive(runtime) {
594
- try {
595
- return await this.supervisor.isRuntimeTargetAlive(runtime);
596
- }
597
- catch (error) {
598
- await this.logger?.warn("Orphaned process liveness check failed", {
599
- error,
600
- context: this.runtimeLogContext(runtime),
601
- });
602
- return true;
603
- }
604
- }
605
- async finalizeOrphanCleanup(processId, finalSignal, runtime, context = {}) {
606
- const record = this.getProcess(processId);
607
- if (record.status !== "orphaned")
608
- return record;
609
- const managed = this.managed.get(processId);
610
- if (managed?.readinessTimer)
611
- clearTimeout(managed.readinessTimer);
612
- const readiness = record.readiness.outcome === "pending"
613
- ? { ...record.readiness, outcome: "exited" }
614
- : record.readiness;
615
- const updated = await this.updateProcess(processId, {
616
- status: "stopped",
617
- readiness,
618
- exitedAt: new Date().toISOString(),
619
- exitCode: null,
620
- signal: finalSignal,
621
- error: undefined,
622
- });
623
- this.managed.delete(processId);
624
- await this.events.publish("process.exited", { process: updated });
625
- await this.events.publish("process.orphan_cleanup_succeeded", {
626
- process: updated,
627
- runtime,
628
- signal: finalSignal,
629
- ...context,
630
- });
631
- await this.logger?.info("Orphaned process cleanup completed", {
632
- processId: updated.id,
633
- projectId: updated.projectId,
634
- conversationId: updated.conversationId,
635
- agentId: updated.agentId,
636
- context: this.runtimeLogContext(runtime, {
637
- signal: finalSignal,
638
- ...context,
639
- }),
640
- });
641
- return updated;
642
- }
643
- async failOrphanCleanup(record, message, context = {}) {
644
- const updated = await this.updateProcess(record.id, { error: message });
645
- await this.events.publish("process.cleanup_failed", {
646
- process: updated,
647
- error: message,
648
- orphaned: true,
649
- ...context,
650
- });
651
- await this.logger?.warn("Orphaned process cleanup failed", {
652
- processId: updated.id,
653
- projectId: updated.projectId,
654
- conversationId: updated.conversationId,
655
- agentId: updated.agentId,
656
- context: this.runtimeLogContext(updated.runtime, {
657
- error: message,
658
- ...context,
659
- }),
660
- });
661
- throw new Error(message);
662
- }
663
- runtimeLogContext(runtime, extra = {}) {
664
- return {
665
- pid: runtime?.childPid,
666
- processGroupId: runtime?.processGroupId,
667
- platform: runtime?.platform,
668
- detached: runtime?.detached,
669
- shell: runtime?.shell,
670
- spawnedAt: runtime?.spawnedAt,
671
- ...extra,
672
- };
673
- }
674
- errorMessage(error) {
675
- return error instanceof Error ? error.message : String(error);
676
- }
677
- async forceFinalizeStoppedProcess(processId, signal, reason) {
678
- const record = this.getProcess(processId);
679
- if (!isActiveProcessStatus(record.status))
680
- return record;
681
- const managed = this.managed.get(processId);
682
- if (managed?.readinessTimer)
683
- clearTimeout(managed.readinessTimer);
684
- if (managed)
685
- managed.finalized = true;
686
- await this.flushProcessOutputBuffers(processId);
687
- const freshRecord = this.processes.get(processId) ?? record;
688
- const readiness = freshRecord.readiness.outcome === "pending"
689
- ? { ...freshRecord.readiness, outcome: "exited" }
690
- : freshRecord.readiness;
691
- const updated = await this.updateProcess(processId, {
692
- status: "stopped",
693
- readiness,
694
- exitedAt: new Date().toISOString(),
695
- exitCode: null,
696
- signal,
697
- });
698
- this.managed.delete(processId);
699
- await this.events.publish("process.exited", { process: updated });
700
- await this.logger?.warn("Process stop force-finalized", {
701
- processId: updated.id,
702
- projectId: updated.projectId,
703
- conversationId: updated.conversationId,
704
- agentId: updated.agentId,
705
- context: { signal, reason },
706
- });
707
- return updated;
708
- }
709
- async markProcessExited(processId, exitCode, signal) {
710
- const record = this.processes.get(processId);
711
- const managed = this.managed.get(processId);
712
- if (!record)
713
- return undefined;
714
- if (!isActiveProcessStatus(record.status))
715
- return record;
716
- if (managed?.finalized)
717
- return record;
718
- if (managed?.readinessTimer)
719
- clearTimeout(managed.readinessTimer);
720
- if (managed)
721
- managed.finalized = true;
722
- await this.flushProcessOutputBuffers(processId);
723
- const freshRecord = this.processes.get(processId);
724
- if (!freshRecord)
725
- return undefined;
726
- if (!isActiveProcessStatus(freshRecord.status))
727
- return freshRecord;
728
- const status = managed?.stopping
729
- ? "stopped"
730
- : exitCode === 0
731
- ? "exited"
732
- : "error";
733
- const readiness = freshRecord.readiness.outcome === "pending"
734
- ? { ...freshRecord.readiness, outcome: "exited" }
735
- : freshRecord.readiness;
736
- const updated = await this.updateProcess(processId, {
737
- status,
738
- readiness,
739
- exitedAt: new Date().toISOString(),
740
- exitCode,
741
- signal,
742
- });
743
- this.managed.delete(processId);
744
- await this.events.publish("process.exited", { process: updated });
745
- await this.logger?.[status === "error" ? "error" : "info"]("Process exited", {
746
- processId: updated.id,
747
- projectId: updated.projectId,
748
- conversationId: updated.conversationId,
749
- agentId: updated.agentId,
750
- context: { exitCode, signal, status },
751
- });
752
- return updated;
753
- }
754
- async markProcessError(processId, message) {
755
- const record = this.processes.get(processId);
756
- const managed = this.managed.get(processId);
757
- if (!record || !isActiveProcessStatus(record.status))
758
- return;
759
- if (managed?.finalized)
760
- return;
761
- if (managed?.readinessTimer)
762
- clearTimeout(managed.readinessTimer);
763
- if (managed)
764
- managed.finalized = true;
765
- await this.flushProcessOutputBuffers(processId);
766
- const freshRecord = this.processes.get(processId);
767
- if (!freshRecord || !isActiveProcessStatus(freshRecord.status))
768
- return;
769
- const updated = await this.updateProcess(processId, {
770
- status: "error",
771
- error: message,
772
- });
773
- this.managed.delete(processId);
774
- await this.events.publish("process.error", { process: updated, message });
775
- await this.logger?.error("Process error", {
776
- processId: updated.id,
777
- projectId: updated.projectId,
778
- conversationId: updated.conversationId,
779
- agentId: updated.agentId,
780
- context: { message },
781
- });
782
- }
783
- async updateProcess(processId, patch) {
784
- const current = this.getProcess(processId);
785
- const updated = {
786
- ...current,
787
- ...patch,
788
- updatedAt: new Date().toISOString(),
789
- };
790
- await this.upsertProcess(updated);
791
- return updated;
792
- }
793
- async upsertProcess(record) {
794
- this.processes.set(record.id, record);
795
- this.index.upsertProcess(record);
796
- await this.writeProcess(record);
797
- }
798
- async writeProcess(record) {
799
- await this.processRepository.write(record);
800
- }
801
- processDir(processId) {
802
- return this.processRepository.processDir(processId);
803
- }
804
- }
805
- function buildProcessEnvInfo(env) {
806
- const keys = Object.keys(env ?? {})
807
- .filter((key) => key.length > 0)
808
- .sort();
809
- if (keys.length === 0)
810
- return undefined;
811
- return { keys, persisted: true, redacted: true };
812
- }
813
- export { isActiveProcessStatus } from "./index.js";
814
- //# sourceMappingURL=process-manager.js.map