@felan-ai/daemon 0.0.0-stage → 0.0.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 (288) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +69 -0
  3. package/README.md +61 -2
  4. package/dist/client.d.ts +5 -0
  5. package/dist/client.d.ts.map +1 -0
  6. package/dist/client.js +4 -0
  7. package/dist/client.js.map +1 -0
  8. package/dist/daemon/admission.d.ts +39 -0
  9. package/dist/daemon/admission.d.ts.map +1 -0
  10. package/dist/daemon/admission.js +175 -0
  11. package/dist/daemon/admission.js.map +1 -0
  12. package/dist/daemon/agent-logs.d.ts +11 -0
  13. package/dist/daemon/agent-logs.d.ts.map +1 -0
  14. package/dist/daemon/agent-logs.js +31 -0
  15. package/dist/daemon/agent-logs.js.map +1 -0
  16. package/dist/daemon/bootstrap.d.ts +7 -0
  17. package/dist/daemon/bootstrap.d.ts.map +1 -0
  18. package/dist/daemon/bootstrap.js +4 -0
  19. package/dist/daemon/bootstrap.js.map +1 -0
  20. package/dist/daemon/broker.d.ts +94 -0
  21. package/dist/daemon/broker.d.ts.map +1 -0
  22. package/dist/daemon/broker.js +374 -0
  23. package/dist/daemon/broker.js.map +1 -0
  24. package/dist/daemon/commands.d.ts +47 -0
  25. package/dist/daemon/commands.d.ts.map +1 -0
  26. package/dist/daemon/commands.js +639 -0
  27. package/dist/daemon/commands.js.map +1 -0
  28. package/dist/daemon/control-recovery.d.ts +9 -0
  29. package/dist/daemon/control-recovery.d.ts.map +1 -0
  30. package/dist/daemon/control-recovery.js +68 -0
  31. package/dist/daemon/control-recovery.js.map +1 -0
  32. package/dist/daemon/control-state.d.ts +1915 -0
  33. package/dist/daemon/control-state.d.ts.map +1 -0
  34. package/dist/daemon/control-state.js +154 -0
  35. package/dist/daemon/control-state.js.map +1 -0
  36. package/dist/daemon/control-store.d.ts +113 -0
  37. package/dist/daemon/control-store.d.ts.map +1 -0
  38. package/dist/daemon/control-store.js +901 -0
  39. package/dist/daemon/control-store.js.map +1 -0
  40. package/dist/daemon/execution-policy.d.ts +15 -0
  41. package/dist/daemon/execution-policy.d.ts.map +1 -0
  42. package/dist/daemon/execution-policy.js +42 -0
  43. package/dist/daemon/execution-policy.js.map +1 -0
  44. package/dist/daemon/execution-services.d.ts +5 -0
  45. package/dist/daemon/execution-services.d.ts.map +1 -0
  46. package/dist/daemon/execution-services.js +73 -0
  47. package/dist/daemon/execution-services.js.map +1 -0
  48. package/dist/daemon/executions.d.ts +134 -0
  49. package/dist/daemon/executions.d.ts.map +1 -0
  50. package/dist/daemon/executions.js +486 -0
  51. package/dist/daemon/executions.js.map +1 -0
  52. package/dist/daemon/extension-ui.d.ts +24 -0
  53. package/dist/daemon/extension-ui.d.ts.map +1 -0
  54. package/dist/daemon/extension-ui.js +161 -0
  55. package/dist/daemon/extension-ui.js.map +1 -0
  56. package/dist/daemon/fanout.d.ts +40 -0
  57. package/dist/daemon/fanout.d.ts.map +1 -0
  58. package/dist/daemon/fanout.js +304 -0
  59. package/dist/daemon/fanout.js.map +1 -0
  60. package/dist/daemon/headless-json.d.ts +3 -0
  61. package/dist/daemon/headless-json.d.ts.map +1 -0
  62. package/dist/daemon/headless-json.js +20 -0
  63. package/dist/daemon/headless-json.js.map +1 -0
  64. package/dist/daemon/host-config.d.ts +61 -0
  65. package/dist/daemon/host-config.d.ts.map +1 -0
  66. package/dist/daemon/host-config.js +167 -0
  67. package/dist/daemon/host-config.js.map +1 -0
  68. package/dist/daemon/host-services.d.ts +61 -0
  69. package/dist/daemon/host-services.d.ts.map +1 -0
  70. package/dist/daemon/host-services.js +2 -0
  71. package/dist/daemon/host-services.js.map +1 -0
  72. package/dist/daemon/ipc.d.ts +14 -0
  73. package/dist/daemon/ipc.d.ts.map +1 -0
  74. package/dist/daemon/ipc.js +233 -0
  75. package/dist/daemon/ipc.js.map +1 -0
  76. package/dist/daemon/legacy-sessions.d.ts +48 -0
  77. package/dist/daemon/legacy-sessions.d.ts.map +1 -0
  78. package/dist/daemon/legacy-sessions.js +328 -0
  79. package/dist/daemon/legacy-sessions.js.map +1 -0
  80. package/dist/daemon/lifecycle.d.ts +44 -0
  81. package/dist/daemon/lifecycle.d.ts.map +1 -0
  82. package/dist/daemon/lifecycle.js +164 -0
  83. package/dist/daemon/lifecycle.js.map +1 -0
  84. package/dist/daemon/main.d.ts +3 -0
  85. package/dist/daemon/main.d.ts.map +1 -0
  86. package/dist/daemon/main.js +83 -0
  87. package/dist/daemon/main.js.map +1 -0
  88. package/dist/daemon/message-display.d.ts +4 -0
  89. package/dist/daemon/message-display.d.ts.map +1 -0
  90. package/dist/daemon/message-display.js +20 -0
  91. package/dist/daemon/message-display.js.map +1 -0
  92. package/dist/daemon/native-ownership.d.ts +13 -0
  93. package/dist/daemon/native-ownership.d.ts.map +1 -0
  94. package/dist/daemon/native-ownership.js +173 -0
  95. package/dist/daemon/native-ownership.js.map +1 -0
  96. package/dist/daemon/operational-log.d.ts +23 -0
  97. package/dist/daemon/operational-log.d.ts.map +1 -0
  98. package/dist/daemon/operational-log.js +79 -0
  99. package/dist/daemon/operational-log.js.map +1 -0
  100. package/dist/daemon/ownership.d.ts +35 -0
  101. package/dist/daemon/ownership.d.ts.map +1 -0
  102. package/dist/daemon/ownership.js +395 -0
  103. package/dist/daemon/ownership.js.map +1 -0
  104. package/dist/daemon/persistence.d.ts +110 -0
  105. package/dist/daemon/persistence.d.ts.map +1 -0
  106. package/dist/daemon/persistence.js +540 -0
  107. package/dist/daemon/persistence.js.map +1 -0
  108. package/dist/daemon/process-adapter.d.ts +23 -0
  109. package/dist/daemon/process-adapter.d.ts.map +1 -0
  110. package/dist/daemon/process-adapter.js +2 -0
  111. package/dist/daemon/process-adapter.js.map +1 -0
  112. package/dist/daemon/processes.d.ts +102 -0
  113. package/dist/daemon/processes.d.ts.map +1 -0
  114. package/dist/daemon/processes.js +691 -0
  115. package/dist/daemon/processes.js.map +1 -0
  116. package/dist/daemon/profile-storage.d.ts +16 -0
  117. package/dist/daemon/profile-storage.d.ts.map +1 -0
  118. package/dist/daemon/profile-storage.js +148 -0
  119. package/dist/daemon/profile-storage.js.map +1 -0
  120. package/dist/daemon/projection.d.ts +110 -0
  121. package/dist/daemon/projection.d.ts.map +1 -0
  122. package/dist/daemon/projection.js +661 -0
  123. package/dist/daemon/projection.js.map +1 -0
  124. package/dist/daemon/provider-loader.d.ts +28 -0
  125. package/dist/daemon/provider-loader.d.ts.map +1 -0
  126. package/dist/daemon/provider-loader.js +376 -0
  127. package/dist/daemon/provider-loader.js.map +1 -0
  128. package/dist/daemon/provider.d.ts +92 -0
  129. package/dist/daemon/provider.d.ts.map +1 -0
  130. package/dist/daemon/provider.js +31 -0
  131. package/dist/daemon/provider.js.map +1 -0
  132. package/dist/daemon/registry.d.ts +209 -0
  133. package/dist/daemon/registry.d.ts.map +1 -0
  134. package/dist/daemon/registry.js +1591 -0
  135. package/dist/daemon/registry.js.map +1 -0
  136. package/dist/daemon/runtime-dependencies.d.ts +5 -0
  137. package/dist/daemon/runtime-dependencies.d.ts.map +1 -0
  138. package/dist/daemon/runtime-dependencies.js +31 -0
  139. package/dist/daemon/runtime-dependencies.js.map +1 -0
  140. package/dist/daemon/server.d.ts +110 -0
  141. package/dist/daemon/server.d.ts.map +1 -0
  142. package/dist/daemon/server.js +556 -0
  143. package/dist/daemon/server.js.map +1 -0
  144. package/dist/daemon/service.d.ts +38 -0
  145. package/dist/daemon/service.d.ts.map +1 -0
  146. package/dist/daemon/service.js +275 -0
  147. package/dist/daemon/service.js.map +1 -0
  148. package/dist/daemon/session-cursor.d.ts +3 -0
  149. package/dist/daemon/session-cursor.d.ts.map +1 -0
  150. package/dist/daemon/session-cursor.js +4 -0
  151. package/dist/daemon/session-cursor.js.map +1 -0
  152. package/dist/daemon/session-execution.d.ts +88 -0
  153. package/dist/daemon/session-execution.d.ts.map +1 -0
  154. package/dist/daemon/session-execution.js +2 -0
  155. package/dist/daemon/session-execution.js.map +1 -0
  156. package/dist/daemon/session-executions.d.ts +5 -0
  157. package/dist/daemon/session-executions.d.ts.map +1 -0
  158. package/dist/daemon/session-executions.js +146 -0
  159. package/dist/daemon/session-executions.js.map +1 -0
  160. package/dist/daemon/session-files.d.ts +28 -0
  161. package/dist/daemon/session-files.d.ts.map +1 -0
  162. package/dist/daemon/session-files.js +189 -0
  163. package/dist/daemon/session-files.js.map +1 -0
  164. package/dist/daemon/session-lifecycle-contracts.d.ts +104 -0
  165. package/dist/daemon/session-lifecycle-contracts.d.ts.map +1 -0
  166. package/dist/daemon/session-lifecycle-contracts.js +2 -0
  167. package/dist/daemon/session-lifecycle-contracts.js.map +1 -0
  168. package/dist/daemon/session-lifecycle.d.ts +26 -0
  169. package/dist/daemon/session-lifecycle.d.ts.map +1 -0
  170. package/dist/daemon/session-lifecycle.js +246 -0
  171. package/dist/daemon/session-lifecycle.js.map +1 -0
  172. package/dist/daemon/session-runtime.d.ts +64 -0
  173. package/dist/daemon/session-runtime.d.ts.map +1 -0
  174. package/dist/daemon/session-runtime.js +3 -0
  175. package/dist/daemon/session-runtime.js.map +1 -0
  176. package/dist/daemon/session-services.d.ts +6 -0
  177. package/dist/daemon/session-services.d.ts.map +1 -0
  178. package/dist/daemon/session-services.js +144 -0
  179. package/dist/daemon/session-services.js.map +1 -0
  180. package/dist/daemon/shutdown-error.d.ts +12 -0
  181. package/dist/daemon/shutdown-error.d.ts.map +1 -0
  182. package/dist/daemon/shutdown-error.js +51 -0
  183. package/dist/daemon/shutdown-error.js.map +1 -0
  184. package/dist/daemon/supervisor.d.ts +28 -0
  185. package/dist/daemon/supervisor.d.ts.map +1 -0
  186. package/dist/daemon/supervisor.js +159 -0
  187. package/dist/daemon/supervisor.js.map +1 -0
  188. package/dist/daemon/target.d.ts +55 -0
  189. package/dist/daemon/target.d.ts.map +1 -0
  190. package/dist/daemon/target.js +191 -0
  191. package/dist/daemon/target.js.map +1 -0
  192. package/dist/daemon/tree.d.ts +7 -0
  193. package/dist/daemon/tree.d.ts.map +1 -0
  194. package/dist/daemon/tree.js +126 -0
  195. package/dist/daemon/tree.js.map +1 -0
  196. package/dist/daemon/ui-vocabulary.d.ts +29 -0
  197. package/dist/daemon/ui-vocabulary.d.ts.map +1 -0
  198. package/dist/daemon/ui-vocabulary.js +323 -0
  199. package/dist/daemon/ui-vocabulary.js.map +1 -0
  200. package/dist/daemon/worker.d.ts +5 -0
  201. package/dist/daemon/worker.d.ts.map +1 -0
  202. package/dist/daemon/worker.js +49 -0
  203. package/dist/daemon/worker.js.map +1 -0
  204. package/dist/index.d.ts +4 -0
  205. package/dist/index.d.ts.map +1 -0
  206. package/dist/index.js +12 -0
  207. package/dist/index.js.map +1 -0
  208. package/dist/lock.d.ts +27 -0
  209. package/dist/lock.d.ts.map +1 -0
  210. package/dist/lock.js +432 -0
  211. package/dist/lock.js.map +1 -0
  212. package/dist/logger.d.ts +9 -0
  213. package/dist/logger.d.ts.map +1 -0
  214. package/dist/logger.js +56 -0
  215. package/dist/logger.js.map +1 -0
  216. package/dist/remote/backoff.d.ts +17 -0
  217. package/dist/remote/backoff.d.ts.map +1 -0
  218. package/dist/remote/backoff.js +18 -0
  219. package/dist/remote/backoff.js.map +1 -0
  220. package/dist/remote/batch.d.ts +3 -0
  221. package/dist/remote/batch.d.ts.map +1 -0
  222. package/dist/remote/batch.js +27 -0
  223. package/dist/remote/batch.js.map +1 -0
  224. package/dist/remote/command-journal.d.ts +30 -0
  225. package/dist/remote/command-journal.d.ts.map +1 -0
  226. package/dist/remote/command-journal.js +72 -0
  227. package/dist/remote/command-journal.js.map +1 -0
  228. package/dist/remote/commands.d.ts +48 -0
  229. package/dist/remote/commands.d.ts.map +1 -0
  230. package/dist/remote/commands.js +145 -0
  231. package/dist/remote/commands.js.map +1 -0
  232. package/dist/remote/connector.d.ts +135 -0
  233. package/dist/remote/connector.d.ts.map +1 -0
  234. package/dist/remote/connector.js +1069 -0
  235. package/dist/remote/connector.js.map +1 -0
  236. package/dist/remote/content.d.ts +17 -0
  237. package/dist/remote/content.d.ts.map +1 -0
  238. package/dist/remote/content.js +116 -0
  239. package/dist/remote/content.js.map +1 -0
  240. package/dist/remote/outbox.d.ts +52 -0
  241. package/dist/remote/outbox.d.ts.map +1 -0
  242. package/dist/remote/outbox.js +321 -0
  243. package/dist/remote/outbox.js.map +1 -0
  244. package/dist/remote/platform.d.ts +53 -0
  245. package/dist/remote/platform.d.ts.map +1 -0
  246. package/dist/remote/platform.js +231 -0
  247. package/dist/remote/platform.js.map +1 -0
  248. package/dist/remote/realtime.d.ts +45 -0
  249. package/dist/remote/realtime.d.ts.map +1 -0
  250. package/dist/remote/realtime.js +265 -0
  251. package/dist/remote/realtime.js.map +1 -0
  252. package/dist/remote/sharing.d.ts +16 -0
  253. package/dist/remote/sharing.d.ts.map +1 -0
  254. package/dist/remote/sharing.js +24 -0
  255. package/dist/remote/sharing.js.map +1 -0
  256. package/dist/remote/state.d.ts +52 -0
  257. package/dist/remote/state.d.ts.map +1 -0
  258. package/dist/remote/state.js +156 -0
  259. package/dist/remote/state.js.map +1 -0
  260. package/dist/remote/text.d.ts +11 -0
  261. package/dist/remote/text.d.ts.map +1 -0
  262. package/dist/remote/text.js +188 -0
  263. package/dist/remote/text.js.map +1 -0
  264. package/dist/remote/token.d.ts +39 -0
  265. package/dist/remote/token.d.ts.map +1 -0
  266. package/dist/remote/token.js +238 -0
  267. package/dist/remote/token.js.map +1 -0
  268. package/dist/runtime-factory.d.ts +12 -0
  269. package/dist/runtime-factory.d.ts.map +1 -0
  270. package/dist/runtime-factory.js +12 -0
  271. package/dist/runtime-factory.js.map +1 -0
  272. package/dist/session-history.d.ts +29 -0
  273. package/dist/session-history.d.ts.map +1 -0
  274. package/dist/session-history.js +374 -0
  275. package/dist/session-history.js.map +1 -0
  276. package/dist/setup/dependencies.d.ts +15 -0
  277. package/dist/setup/dependencies.d.ts.map +1 -0
  278. package/dist/setup/dependencies.js +2 -0
  279. package/dist/setup/dependencies.js.map +1 -0
  280. package/dist/setup/open.d.ts +8 -0
  281. package/dist/setup/open.d.ts.map +1 -0
  282. package/dist/setup/open.js +16 -0
  283. package/dist/setup/open.js.map +1 -0
  284. package/dist/version.d.ts +2 -0
  285. package/dist/version.d.ts.map +1 -0
  286. package/dist/version.js +4 -0
  287. package/dist/version.js.map +1 -0
  288. package/package.json +66 -4
@@ -0,0 +1,328 @@
1
+ import { constants } from 'node:fs';
2
+ import { open, readdir, stat } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { createInterface } from 'node:readline';
5
+ import { canonicalPath } from './profile-storage.js';
6
+ import { parseSchema } from '@felan-ai/session-protocol';
7
+ import { isConversationEntry, sessionHeaderSchema } from './session-files.js';
8
+ const sessionId = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/u;
9
+ const EMPTY = Object.freeze({ title: '', preview: '' });
10
+ const HEADER_CHUNK = 4096;
11
+ const HEADER_BYTES = 64 * 1024;
12
+ const INDEX_CONCURRENCY = 16;
13
+ const SUMMARY_READS = 4;
14
+ const WARM_READS = 2;
15
+ // Pi's default per-cwd directory name under agentDir/sessions, as written by pre-daemon Felan.
16
+ export function legacySessionDirectoryName(cwd) {
17
+ return `--${cwd.replace(/^[/\\]/u, '').replace(/[/\\:]/gu, '-')}--`;
18
+ }
19
+ /**
20
+ * Finds unregistered Pi transcripts in the pre-daemon layouts of the owned stores: the per-cwd
21
+ * directories under agentDir/sessions and the top level of each store root (custom session
22
+ * directories). Discovery reads only header lines. A summary needs the whole file, like Pi's
23
+ * session list, so it is read on request. Both are cached until the file changes.
24
+ */
25
+ export class LegacySessionIndex {
26
+ owner;
27
+ headers = new Map();
28
+ summaries = new Map();
29
+ reading = new Map();
30
+ // Listing pages and the warm-up share these, so neither can flood the file system.
31
+ reads = new Slots(SUMMARY_READS);
32
+ constructor(owner) {
33
+ this.owner = owner;
34
+ }
35
+ /** Newest first. Malformed and registered files are skipped; a duplicated ID keeps only its newest file. */
36
+ async discover(registered, options = {}) {
37
+ const { cwd, signal } = options;
38
+ const sessions = join(this.owner.target.agentDir, 'sessions');
39
+ // A transcript written under a symlinked project path lives in that path's directory, so a cwd filter cannot narrow the scan.
40
+ const nested = (await entries(sessions)).filter(entry => !entry.isFile() && /^--.+--$/u.test(entry.name)).map(entry => join(sessions, entry.name));
41
+ const directories = [sessions, ...nested, ...this.owner.target.rootSet.filter(root => root !== this.owner.target.agentDir && root !== sessions)];
42
+ const listings = await limited(directories, INDEX_CONCURRENCY, signal, async (directory) => (await entries(directory)).filter(entry => entry.name.endsWith('.jsonl')).map(entry => join(directory, entry.name)));
43
+ const skipped = new Set(registered.map(row => row.piPath));
44
+ const paths = [...new Set(listings.flat())].filter(path => !skipped.has(path));
45
+ const canonical = new Map();
46
+ const files = (await limited(paths, INDEX_CONCURRENCY, signal, async (path) => {
47
+ let info;
48
+ try {
49
+ info = await stat(path);
50
+ }
51
+ catch {
52
+ return undefined;
53
+ }
54
+ if (!info.isFile())
55
+ return undefined;
56
+ const header = await this.header(path, info);
57
+ if (!header)
58
+ return undefined;
59
+ let resolved = canonical.get(header.cwd);
60
+ if (!resolved)
61
+ canonical.set(header.cwd, resolved = canonicalPath(header.cwd).catch(() => header.cwd));
62
+ return { id: header.id, cwd: await resolved, path, mtimeMs: info.mtimeMs };
63
+ })).filter((file) => file !== undefined);
64
+ const present = new Set(paths);
65
+ for (const cache of [this.headers, this.summaries])
66
+ for (const path of cache.keys())
67
+ if (!present.has(path))
68
+ cache.delete(path);
69
+ files.sort((a, b) => a.mtimeMs === b.mtimeMs ? a.path.localeCompare(b.path) : b.mtimeMs - a.mtimeMs);
70
+ const ids = new Set(registered.map(row => row.id));
71
+ const found = [];
72
+ for (const file of files) {
73
+ if (ids.has(file.id))
74
+ continue;
75
+ ids.add(file.id);
76
+ if (cwd === undefined || file.cwd === cwd)
77
+ found.push({ id: file.id, cwd: file.cwd, path: file.path, modifiedAt: Math.floor(file.mtimeMs) });
78
+ }
79
+ return found;
80
+ }
81
+ /** Empty when the file is gone, unreadable or no longer holds this session. */
82
+ async summary(session) {
83
+ let info;
84
+ try {
85
+ info = await stat(session.path);
86
+ }
87
+ catch {
88
+ return EMPTY;
89
+ }
90
+ const version = fileVersion(info);
91
+ const cached = this.summaries.get(session.path);
92
+ if (cached?.version === version)
93
+ return cached.id === session.id ? cached.summary : EMPTY;
94
+ const key = `${version}:${session.path}`;
95
+ let read = this.reading.get(key);
96
+ if (!read) {
97
+ read = this.reads.run(() => readTranscript(session.path, false)).then(result => {
98
+ if (result)
99
+ this.summaries.set(session.path, { version, id: result.id, summary: { title: result.title, preview: result.preview } });
100
+ return result;
101
+ }).finally(() => this.reading.delete(key));
102
+ this.reading.set(key, read);
103
+ }
104
+ const result = await read;
105
+ return result?.id === session.id ? { title: result.title, preview: result.preview } : EMPTY;
106
+ }
107
+ /** Reads summaries in the given order, a few at a time, so listings rarely wait for a whole transcript. */
108
+ async warm(sessions, signal) {
109
+ await limited(sessions, WARM_READS, signal, session => this.summary(session));
110
+ }
111
+ async header(path, info) {
112
+ const version = fileVersion(info);
113
+ const cached = this.headers.get(path);
114
+ if (cached?.version === version)
115
+ return cached.header;
116
+ let header;
117
+ // A read failure may be transient, so only a parsed or rejected header is remembered.
118
+ try {
119
+ header = await readHeader(path);
120
+ }
121
+ catch {
122
+ return undefined;
123
+ }
124
+ this.headers.set(path, { version, header });
125
+ return header;
126
+ }
127
+ }
128
+ /** Whether a transcript holds a conversation message. Unreadable files count as conversations, so they are kept. */
129
+ export async function transcriptHasConversation(path) {
130
+ try {
131
+ const handle = await open(path, constants.O_RDONLY | constants.O_NONBLOCK);
132
+ const input = handle.createReadStream({ encoding: 'utf8', autoClose: false });
133
+ try {
134
+ for await (const line of createInterface({ input, crlfDelay: Infinity })) {
135
+ try {
136
+ if (isConversationEntry(JSON.parse(line)))
137
+ return true;
138
+ }
139
+ catch { /* Partial lines are not entries. */ }
140
+ }
141
+ return false;
142
+ }
143
+ finally {
144
+ input.destroy();
145
+ await handle.close();
146
+ }
147
+ }
148
+ catch {
149
+ return true;
150
+ }
151
+ }
152
+ /** First user message of a transcript file; empty when absent or unreadable. */
153
+ export async function readTranscriptPreview(path) {
154
+ return (await readTranscript(path, true))?.preview ?? '';
155
+ }
156
+ /** First user message among in-memory Pi session entries. */
157
+ export function transcriptPreview(entries) {
158
+ const summary = summarizer();
159
+ for (const entry of entries)
160
+ summary.add(entry);
161
+ return summary.result().preview;
162
+ }
163
+ function fileVersion(info) {
164
+ return `${info.dev}:${info.ino}:${info.size}:${info.mtimeMs}`;
165
+ }
166
+ async function entries(directory) {
167
+ try {
168
+ return await readdir(directory, { withFileTypes: true });
169
+ }
170
+ catch {
171
+ return [];
172
+ }
173
+ }
174
+ /** Undefined when the file is not a Pi session; I/O failures throw. */
175
+ async function readHeader(path) {
176
+ // Non-blocking open keeps a FIFO named *.jsonl from stalling discovery.
177
+ const handle = await open(path, constants.O_RDONLY | constants.O_NONBLOCK);
178
+ try {
179
+ if (!(await handle.stat()).isFile())
180
+ return undefined;
181
+ const buffer = Buffer.alloc(HEADER_BYTES);
182
+ let length = 0;
183
+ let end = -1;
184
+ while (end < 0 && length < buffer.length) {
185
+ const { bytesRead } = await handle.read(buffer, length, Math.min(HEADER_CHUNK, buffer.length - length), length);
186
+ if (!bytesRead)
187
+ break;
188
+ end = buffer.indexOf(10, length);
189
+ length += bytesRead;
190
+ }
191
+ if (end < 0 && length === buffer.length)
192
+ return undefined;
193
+ return parseHeader(buffer.toString('utf8', 0, end < 0 ? length : end));
194
+ }
195
+ finally {
196
+ await handle.close();
197
+ }
198
+ }
199
+ function parseHeader(line) {
200
+ try {
201
+ const header = parseSchema(sessionHeaderSchema, JSON.parse(line));
202
+ return sessionId.test(header.id) ? { id: header.id, cwd: header.cwd } : undefined;
203
+ }
204
+ catch {
205
+ return undefined;
206
+ }
207
+ }
208
+ async function readTranscript(path, previewOnly) {
209
+ try {
210
+ const handle = await open(path, constants.O_RDONLY | constants.O_NONBLOCK);
211
+ const input = handle.createReadStream({ encoding: 'utf8', autoClose: false });
212
+ try {
213
+ if (!(await handle.stat()).isFile())
214
+ return undefined;
215
+ let header;
216
+ const summary = summarizer();
217
+ for await (const line of createInterface({ input, crlfDelay: Infinity })) {
218
+ if (!header) {
219
+ header = parseHeader(line);
220
+ if (!header)
221
+ return undefined;
222
+ continue;
223
+ }
224
+ summary.line(line);
225
+ if (previewOnly && summary.hasPreview())
226
+ break;
227
+ }
228
+ return header && { ...header, ...summary.result() };
229
+ }
230
+ finally {
231
+ input.destroy();
232
+ await handle.close();
233
+ }
234
+ }
235
+ catch {
236
+ return undefined;
237
+ }
238
+ }
239
+ // Latest Pi session name and first user message.
240
+ function summarizer() {
241
+ let name;
242
+ let message;
243
+ const add = (entry) => {
244
+ if (!entry || typeof entry !== 'object')
245
+ return;
246
+ const row = entry;
247
+ if (row.type === 'session_info')
248
+ name = typeof row.name === 'string' ? row.name : undefined;
249
+ else if (!message?.trim() && row.type === 'message' && row.message?.role === 'user')
250
+ message = textOf(row.message.content);
251
+ };
252
+ return {
253
+ add,
254
+ line(text) {
255
+ // Pi writes entries with JSON.stringify, so a relevant entry always contains its quoted type or role; other lines are not parsed.
256
+ if (!text.includes('"session_info"') && (message?.trim() || !text.includes('"user"')))
257
+ return;
258
+ try {
259
+ add(JSON.parse(text));
260
+ }
261
+ catch { /* Partial or foreign lines are not entries. */ }
262
+ },
263
+ hasPreview: () => !!message?.trim(),
264
+ result: () => ({ title: snippet(name?.trim() ?? ''), preview: snippet(message ?? '') }),
265
+ };
266
+ }
267
+ function textOf(content) {
268
+ if (typeof content === 'string')
269
+ return content;
270
+ if (!Array.isArray(content))
271
+ return undefined;
272
+ return content.map(part => part && typeof part === 'object' && part.type === 'text' && typeof part.text === 'string' ? part.text : '').join(' ');
273
+ }
274
+ function snippet(text) {
275
+ const flat = text.replace(/[\p{Cc}\p{Cf}\s]+/gu, ' ').trim();
276
+ const points = [...flat];
277
+ return points.length > 120 ? `${points.slice(0, 119).join('').trimEnd()}…` : flat;
278
+ }
279
+ /** Maps in order with at most `limit` calls in flight. Once aborted it starts no more calls and rejects after the running ones settle. */
280
+ async function limited(items, limit, signal, map) {
281
+ const results = new Array(items.length);
282
+ let next = 0;
283
+ let failed = false;
284
+ const worker = async () => {
285
+ try {
286
+ while (!failed && next < items.length) {
287
+ signal?.throwIfAborted();
288
+ const index = next++;
289
+ results[index] = await map(items[index]);
290
+ }
291
+ }
292
+ catch (error) {
293
+ failed = true;
294
+ throw error;
295
+ }
296
+ };
297
+ for (const result of await Promise.allSettled(Array.from({ length: Math.min(limit, items.length) }, worker)))
298
+ if (result.status === 'rejected')
299
+ throw result.reason;
300
+ signal?.throwIfAborted();
301
+ return results;
302
+ }
303
+ /** A counting semaphore; a released slot passes directly to the next waiter. */
304
+ class Slots {
305
+ size;
306
+ active = 0;
307
+ waiting = [];
308
+ constructor(size) {
309
+ this.size = size;
310
+ }
311
+ async run(work) {
312
+ if (this.active < this.size)
313
+ this.active++;
314
+ else
315
+ await new Promise(resolve => this.waiting.push(resolve));
316
+ try {
317
+ return await work();
318
+ }
319
+ finally {
320
+ const next = this.waiting.shift();
321
+ if (next)
322
+ next();
323
+ else
324
+ this.active--;
325
+ }
326
+ }
327
+ }
328
+ //# sourceMappingURL=legacy-sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-sessions.js","sourceRoot":"","sources":["../../src/daemon/legacy-sessions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import type { DaemonIdentity, HostBlocked, OperationParams, OperationResult } from '@felan-ai/session-protocol';
2
+ import type { AdmittedCommand, AdmissionOutcome } from './admission.js';
3
+ import { type ResolvedDaemonTarget } from './target.js';
4
+ import { type ShutdownStep } from './shutdown-error.js';
5
+ export type HostState = OperationResult<'host.status'>['state'];
6
+ export type HostAction = 'stop' | 'restart';
7
+ export type HostMode = OperationParams<'host.stop'>['mode'];
8
+ export interface HostLifecycleOptions {
9
+ target: ResolvedDaemonTarget;
10
+ identity: DaemonIdentity;
11
+ beginDrain(): void;
12
+ /** Reopens admission after a drain was abandoned; throws when the daemon can no longer resume. */
13
+ endDrain(): void;
14
+ /** Settlement must stop before releasing anything once `signal` aborts. */
15
+ settle(mode: HostMode, signal: AbortSignal): Promise<void>;
16
+ complete(action: HostAction): Promise<void>;
17
+ timeoutMs?: number;
18
+ canRetry?(): boolean;
19
+ onBlocked?(blocked: HostBlocked, error: unknown): void;
20
+ record?(event: 'stop_requested' | 'restart_requested' | 'drain_blocked' | 'drain_cancelled' | 'releasing'): void;
21
+ }
22
+ export declare class HostLifecycle {
23
+ private readonly options;
24
+ private current;
25
+ private generation;
26
+ private completing;
27
+ private pending;
28
+ private blockedRecord;
29
+ private readonly timeout;
30
+ constructor(options: HostLifecycleOptions);
31
+ get state(): HostState;
32
+ get blocked(): HostBlocked | undefined;
33
+ block(error?: unknown, step?: ShutdownStep, retryable?: boolean): void;
34
+ blockedError(work?: boolean): Error & {
35
+ code: string;
36
+ };
37
+ prepare(command: AdmittedCommand): AdmissionOutcome;
38
+ afterResponse(id: string, accepted?: boolean): void;
39
+ private finish;
40
+ private resume;
41
+ private settle;
42
+ private setState;
43
+ }
44
+ //# sourceMappingURL=lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/daemon/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAChH,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAExE,OAAO,EAAwB,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAkD,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExG,MAAM,MAAM,SAAS,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC;AAChE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAC5C,MAAM,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5D,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,QAAQ,EAAE,cAAc,CAAC;IACzB,UAAU,IAAI,IAAI,CAAC;IACnB,kGAAkG;IAClG,QAAQ,IAAI,IAAI,CAAC;IACjB,2EAA2E;IAC3E,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,IAAI,OAAO,CAAC;IACrB,SAAS,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACvD,MAAM,CAAC,CAAC,KAAK,EAAE,gBAAgB,GAAG,mBAAmB,GAAG,eAAe,GAAG,iBAAiB,GAAG,WAAW,GAAG,IAAI,CAAC;CAClH;AAID,qBAAa,aAAa;IAQZ,OAAO,CAAC,QAAQ,CAAC,OAAO;IAPpC,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAEJ,OAAO,EAAE,oBAAoB;IAK1D,IAAI,KAAK,IAAI,SAAS,CAAyB;IAC/C,IAAI,OAAO,IAAI,WAAW,GAAG,SAAS,CAAqG;IAE3I,KAAK,CAAC,KAAK,GAAE,OAAiD,EAAE,IAAI,GAAE,YAA+B,EAAE,SAAS,UAAQ,GAAG,IAAI;IAY/H,YAAY,CAAC,IAAI,UAAQ,GAAG,KAAK,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAQpD,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,gBAAgB;IA0BnD,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,UAAO,GAAG,IAAI;YAQlC,MAAM;IAkBpB,OAAO,CAAC,MAAM;YAQA,MAAM;IASpB,OAAO,CAAC,QAAQ;CACjB"}
@@ -0,0 +1,164 @@
1
+ import { accepted, commandError } from './commands.js';
2
+ import { assertTargetIdentity } from './target.js';
3
+ import { ShutdownError, shutdownDetail, shutdownMessage } from './shutdown-error.js';
4
+ export class HostLifecycle {
5
+ options;
6
+ current = 'ready';
7
+ generation = 0;
8
+ completing = false;
9
+ pending;
10
+ blockedRecord;
11
+ timeout;
12
+ constructor(options) {
13
+ this.options = options;
14
+ this.timeout = options.timeoutMs ?? 30_000;
15
+ if (!Number.isInteger(this.timeout) || this.timeout < 1 || this.timeout > 120_000)
16
+ throw new Error('Invalid drain deadline.');
17
+ }
18
+ get state() { return this.current; }
19
+ get blocked() { return this.current === 'blocked' && this.blockedRecord ? { ...this.blockedRecord } : undefined; }
20
+ block(error = new Error('Daemon ownership was lost.'), step = 'ownership-lost', retryable = false) {
21
+ this.generation++;
22
+ this.pending?.abort.abort();
23
+ this.pending = undefined;
24
+ let recoverable = false;
25
+ try {
26
+ recoverable = retryable && (this.options.canRetry?.() ?? false);
27
+ }
28
+ catch { }
29
+ const detail = shutdownDetail(error);
30
+ this.blockedRecord = { recoverable, since: Date.now(), message: shutdownMessage(error), step: detail?.step ?? step,
31
+ ...(detail?.session ? { session: detail.session } : {}), pid: process.pid };
32
+ this.current = 'blocked';
33
+ try {
34
+ this.options.onBlocked?.(this.blockedRecord, error);
35
+ }
36
+ catch { }
37
+ try {
38
+ this.options.record?.('drain_blocked');
39
+ }
40
+ catch { }
41
+ }
42
+ blockedError(work = false) {
43
+ const blocked = this.blockedRecord;
44
+ const recovery = blocked?.recoverable ? work ? 'Retry the stop or restart with force.' : 'Retry with force to finish cleanup.'
45
+ : `Cleanup cannot be retried safely; force-terminate the daemon process ${forceTermination(blocked?.pid ?? process.pid)}.`;
46
+ return commandError('host_blocked', work ? `The daemon is blocked after an incomplete shutdown and refuses new work. ${recovery}`
47
+ : `The daemon is blocked after an incomplete shutdown at ${blocked?.step ?? 'settlement'}: ${blocked?.message ?? 'Shutdown failed.'} ${recovery}`);
48
+ }
49
+ prepare(command) {
50
+ const request = command.request;
51
+ if (request.op !== 'host.stop' && request.op !== 'host.restart')
52
+ throw commandError('invalid_request');
53
+ assertTargetIdentity(this.options.target, request.params.expected, this.options.identity);
54
+ if (this.current === 'stopped')
55
+ throw commandError('unavailable');
56
+ if (this.current === 'blocked' && request.params.mode === 'force' && this.blockedRecord?.recoverable) {
57
+ let retryable = false;
58
+ try {
59
+ retryable = this.options.canRetry?.() ?? false;
60
+ }
61
+ catch { }
62
+ if (!retryable)
63
+ this.blockedRecord = { ...this.blockedRecord, recoverable: false };
64
+ }
65
+ if (this.current === 'blocked' && (request.params.mode !== 'force' || !this.blockedRecord?.recoverable))
66
+ throw this.blockedError();
67
+ if (this.completing)
68
+ throw commandError('busy');
69
+ const action = request.op === 'host.stop' ? 'stop' : 'restart';
70
+ if (this.current === 'draining' && this.pending && (this.pending.action !== action || this.pending.mode === 'force' && request.params.mode !== 'force'))
71
+ throw commandError('busy');
72
+ command.dispatch(() => {
73
+ try {
74
+ this.options.beginDrain();
75
+ }
76
+ catch (error) {
77
+ this.block(error, 'begin-drain');
78
+ throw error;
79
+ }
80
+ if (this.current === 'draining' && this.pending?.action === action && this.pending.mode === request.params.mode)
81
+ return;
82
+ this.pending?.abort.abort();
83
+ this.pending = { id: request.id, action, mode: request.params.mode, generation: ++this.generation, abort: new AbortController() };
84
+ this.setState('draining');
85
+ try {
86
+ this.options.record?.(action === 'stop' ? 'stop_requested' : 'restart_requested');
87
+ }
88
+ catch (error) {
89
+ this.block(error, 'begin-drain');
90
+ throw error;
91
+ }
92
+ });
93
+ return { response: accepted(request, { state: this.current }) };
94
+ }
95
+ afterResponse(id, accepted = true) {
96
+ const pending = this.pending;
97
+ if (this.current !== 'draining' || !pending || pending.id !== id)
98
+ return;
99
+ if (!accepted) {
100
+ if (!this.resume())
101
+ this.block(new Error('Management outcome could not be committed.'), 'management-response');
102
+ return;
103
+ }
104
+ this.pending = { ...pending, id: '' };
105
+ void this.finish(pending);
106
+ }
107
+ async finish(pending) {
108
+ let releasing = false;
109
+ try {
110
+ await this.settle(pending);
111
+ if (pending.generation !== this.generation || this.current !== 'draining')
112
+ return;
113
+ releasing = true;
114
+ this.completing = true;
115
+ this.options.record?.('releasing');
116
+ await this.options.complete(pending.action);
117
+ this.setState('stopped');
118
+ }
119
+ catch (error) {
120
+ if (pending.generation !== this.generation)
121
+ return;
122
+ this.completing = false;
123
+ // A drain can reopen admission only before registry shutdown has made resumption unsafe.
124
+ if (!releasing && pending.mode === 'drain' && this.resume())
125
+ return;
126
+ this.block(error, releasing ? 'release' : 'settlement', !releasing && !(error instanceof ShutdownError && error.step === 'settlement-deadline'));
127
+ }
128
+ }
129
+ resume() {
130
+ this.pending?.abort.abort();
131
+ try {
132
+ this.options.endDrain();
133
+ }
134
+ catch {
135
+ return false;
136
+ }
137
+ this.generation++;
138
+ this.pending = undefined;
139
+ this.setState('ready');
140
+ try {
141
+ this.options.record?.('drain_cancelled');
142
+ }
143
+ catch { /* The daemon keeps serving even if diagnostics fail. */ }
144
+ return true;
145
+ }
146
+ async settle(pending) {
147
+ let timer;
148
+ try {
149
+ await Promise.race([Promise.resolve().then(() => this.options.settle(pending.mode, pending.abort.signal)), new Promise((_resolve, reject) => {
150
+ timer = setTimeout(() => { pending.abort.abort(); reject(new ShutdownError('settlement-deadline', new Error('Settlement deadline exceeded.'))); }, this.timeout);
151
+ })]);
152
+ }
153
+ finally {
154
+ clearTimeout(timer);
155
+ }
156
+ }
157
+ setState(state) { this.current = state; if (state !== 'blocked')
158
+ this.blockedRecord = undefined; }
159
+ }
160
+ /** A blocked daemon answers SIGTERM with a drain request, which it refuses, so only a forced termination ends it. */
161
+ function forceTermination(pid) {
162
+ return `${pid} (${process.platform === 'win32' ? `taskkill /F /PID ${pid}` : `kill -9 ${pid}`})`;
163
+ }
164
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/daemon/lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { HostManager } from './host-config.js';
2
+ export declare function runDaemonProcess(args: readonly string[], manager?: HostManager): Promise<void>;
3
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/daemon/main.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuCpG"}