trove-cli 0.0.0-stage → 0.3.2

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 (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +202 -2
  3. package/dist/adapters/file-source.d.ts +31 -0
  4. package/dist/adapters/file-source.js +97 -0
  5. package/dist/adapters/file-source.js.map +1 -0
  6. package/dist/adapters/index.d.ts +34 -0
  7. package/dist/adapters/index.js +146 -0
  8. package/dist/adapters/index.js.map +1 -0
  9. package/dist/adapters/opencode.d.ts +30 -0
  10. package/dist/adapters/opencode.js +135 -0
  11. package/dist/adapters/opencode.js.map +1 -0
  12. package/dist/cli.d.ts +58 -0
  13. package/dist/cli.js +974 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/config.d.ts +81 -0
  16. package/dist/config.js +99 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/core/archive.d.ts +27 -0
  19. package/dist/core/archive.js +101 -0
  20. package/dist/core/archive.js.map +1 -0
  21. package/dist/core/chunker.d.ts +28 -0
  22. package/dist/core/chunker.js +67 -0
  23. package/dist/core/chunker.js.map +1 -0
  24. package/dist/core/clean.d.ts +36 -0
  25. package/dist/core/clean.js +182 -0
  26. package/dist/core/clean.js.map +1 -0
  27. package/dist/core/collect.d.ts +39 -0
  28. package/dist/core/collect.js +194 -0
  29. package/dist/core/collect.js.map +1 -0
  30. package/dist/core/concurrency.d.ts +2 -0
  31. package/dist/core/concurrency.js +16 -0
  32. package/dist/core/concurrency.js.map +1 -0
  33. package/dist/core/cursor.d.ts +31 -0
  34. package/dist/core/cursor.js +31 -0
  35. package/dist/core/cursor.js.map +1 -0
  36. package/dist/core/events/claude.d.ts +7 -0
  37. package/dist/core/events/claude.js +287 -0
  38. package/dist/core/events/claude.js.map +1 -0
  39. package/dist/core/events/codex.d.ts +6 -0
  40. package/dist/core/events/codex.js +149 -0
  41. package/dist/core/events/codex.js.map +1 -0
  42. package/dist/core/events/doubao.d.ts +9 -0
  43. package/dist/core/events/doubao.js +151 -0
  44. package/dist/core/events/doubao.js.map +1 -0
  45. package/dist/core/events/index.d.ts +6 -0
  46. package/dist/core/events/index.js +20 -0
  47. package/dist/core/events/index.js.map +1 -0
  48. package/dist/core/events/opencode.d.ts +7 -0
  49. package/dist/core/events/opencode.js +189 -0
  50. package/dist/core/events/opencode.js.map +1 -0
  51. package/dist/core/events/schema.d.ts +83 -0
  52. package/dist/core/events/schema.js +35 -0
  53. package/dist/core/events/schema.js.map +1 -0
  54. package/dist/core/layout.d.ts +26 -0
  55. package/dist/core/layout.js +122 -0
  56. package/dist/core/layout.js.map +1 -0
  57. package/dist/core/lessons/analyze.d.ts +40 -0
  58. package/dist/core/lessons/analyze.js +107 -0
  59. package/dist/core/lessons/analyze.js.map +1 -0
  60. package/dist/core/lessons/audit.d.ts +51 -0
  61. package/dist/core/lessons/audit.js +57 -0
  62. package/dist/core/lessons/audit.js.map +1 -0
  63. package/dist/core/lessons/compaction.d.ts +5 -0
  64. package/dist/core/lessons/compaction.js +58 -0
  65. package/dist/core/lessons/compaction.js.map +1 -0
  66. package/dist/core/lessons/config.d.ts +15 -0
  67. package/dist/core/lessons/config.js +31 -0
  68. package/dist/core/lessons/config.js.map +1 -0
  69. package/dist/core/lessons/existing.d.ts +4 -0
  70. package/dist/core/lessons/existing.js +22 -0
  71. package/dist/core/lessons/existing.js.map +1 -0
  72. package/dist/core/lessons/extract.d.ts +21 -0
  73. package/dist/core/lessons/extract.js +106 -0
  74. package/dist/core/lessons/extract.js.map +1 -0
  75. package/dist/core/lessons/frontmatter.d.ts +29 -0
  76. package/dist/core/lessons/frontmatter.js +87 -0
  77. package/dist/core/lessons/frontmatter.js.map +1 -0
  78. package/dist/core/lessons/graph.d.ts +256 -0
  79. package/dist/core/lessons/graph.js +86 -0
  80. package/dist/core/lessons/graph.js.map +1 -0
  81. package/dist/core/lessons/jev.d.ts +36 -0
  82. package/dist/core/lessons/jev.js +100 -0
  83. package/dist/core/lessons/jev.js.map +1 -0
  84. package/dist/core/lessons/layout.d.ts +2 -0
  85. package/dist/core/lessons/layout.js +56 -0
  86. package/dist/core/lessons/layout.js.map +1 -0
  87. package/dist/core/lessons/learn.d.ts +38 -0
  88. package/dist/core/lessons/learn.js +190 -0
  89. package/dist/core/lessons/learn.js.map +1 -0
  90. package/dist/core/lessons/llm.d.ts +42 -0
  91. package/dist/core/lessons/llm.js +106 -0
  92. package/dist/core/lessons/llm.js.map +1 -0
  93. package/dist/core/lessons/memo.d.ts +19 -0
  94. package/dist/core/lessons/memo.js +170 -0
  95. package/dist/core/lessons/memo.js.map +1 -0
  96. package/dist/core/lessons/merge.d.ts +39 -0
  97. package/dist/core/lessons/merge.js +79 -0
  98. package/dist/core/lessons/merge.js.map +1 -0
  99. package/dist/core/lessons/queue.d.ts +6 -0
  100. package/dist/core/lessons/queue.js +52 -0
  101. package/dist/core/lessons/queue.js.map +1 -0
  102. package/dist/core/lessons/recent.d.ts +21 -0
  103. package/dist/core/lessons/recent.js +111 -0
  104. package/dist/core/lessons/recent.js.map +1 -0
  105. package/dist/core/lessons/schema.d.ts +26 -0
  106. package/dist/core/lessons/schema.js +64 -0
  107. package/dist/core/lessons/schema.js.map +1 -0
  108. package/dist/core/lessons/select.d.ts +19 -0
  109. package/dist/core/lessons/select.js +55 -0
  110. package/dist/core/lessons/select.js.map +1 -0
  111. package/dist/core/lessons/sidecar.d.ts +23 -0
  112. package/dist/core/lessons/sidecar.js +171 -0
  113. package/dist/core/lessons/sidecar.js.map +1 -0
  114. package/dist/core/lessons/storage.d.ts +21 -0
  115. package/dist/core/lessons/storage.js +65 -0
  116. package/dist/core/lessons/storage.js.map +1 -0
  117. package/dist/core/lessons/usage.d.ts +31 -0
  118. package/dist/core/lessons/usage.js +91 -0
  119. package/dist/core/lessons/usage.js.map +1 -0
  120. package/dist/core/lessons/write.d.ts +18 -0
  121. package/dist/core/lessons/write.js +131 -0
  122. package/dist/core/lessons/write.js.map +1 -0
  123. package/dist/core/library/build.d.ts +22 -0
  124. package/dist/core/library/build.js +163 -0
  125. package/dist/core/library/build.js.map +1 -0
  126. package/dist/core/library/group.d.ts +14 -0
  127. package/dist/core/library/group.js +129 -0
  128. package/dist/core/library/group.js.map +1 -0
  129. package/dist/core/library/index-file.d.ts +7 -0
  130. package/dist/core/library/index-file.js +250 -0
  131. package/dist/core/library/index-file.js.map +1 -0
  132. package/dist/core/library/schema.d.ts +78 -0
  133. package/dist/core/library/schema.js +37 -0
  134. package/dist/core/library/schema.js.map +1 -0
  135. package/dist/core/library/skills.d.ts +26 -0
  136. package/dist/core/library/skills.js +168 -0
  137. package/dist/core/library/skills.js.map +1 -0
  138. package/dist/core/library/sync.d.ts +48 -0
  139. package/dist/core/library/sync.js +271 -0
  140. package/dist/core/library/sync.js.map +1 -0
  141. package/dist/core/lock.d.ts +6 -0
  142. package/dist/core/lock.js +56 -0
  143. package/dist/core/lock.js.map +1 -0
  144. package/dist/core/pull.d.ts +23 -0
  145. package/dist/core/pull.js +147 -0
  146. package/dist/core/pull.js.map +1 -0
  147. package/dist/core/push.d.ts +29 -0
  148. package/dist/core/push.js +170 -0
  149. package/dist/core/push.js.map +1 -0
  150. package/dist/core/remote-layout.d.ts +67 -0
  151. package/dist/core/remote-layout.js +94 -0
  152. package/dist/core/remote-layout.js.map +1 -0
  153. package/dist/core/sessions.d.ts +29 -0
  154. package/dist/core/sessions.js +96 -0
  155. package/dist/core/sessions.js.map +1 -0
  156. package/dist/core/state.d.ts +94 -0
  157. package/dist/core/state.js +62 -0
  158. package/dist/core/state.js.map +1 -0
  159. package/dist/core/sync.d.ts +48 -0
  160. package/dist/core/sync.js +140 -0
  161. package/dist/core/sync.js.map +1 -0
  162. package/dist/core/time-window.d.ts +8 -0
  163. package/dist/core/time-window.js +36 -0
  164. package/dist/core/time-window.js.map +1 -0
  165. package/dist/daemon.d.ts +73 -0
  166. package/dist/daemon.js +272 -0
  167. package/dist/daemon.js.map +1 -0
  168. package/dist/format.d.ts +4 -0
  169. package/dist/format.js +28 -0
  170. package/dist/format.js.map +1 -0
  171. package/dist/main.d.ts +2 -0
  172. package/dist/main.js +9 -0
  173. package/dist/main.js.map +1 -0
  174. package/dist/paths.d.ts +19 -0
  175. package/dist/paths.js +19 -0
  176. package/dist/paths.js.map +1 -0
  177. package/dist/progress-console.d.ts +12 -0
  178. package/dist/progress-console.js +42 -0
  179. package/dist/progress-console.js.map +1 -0
  180. package/dist/progress.d.ts +7 -0
  181. package/dist/progress.js +6 -0
  182. package/dist/progress.js.map +1 -0
  183. package/dist/remote/create-remote.d.ts +20 -0
  184. package/dist/remote/create-remote.js +86 -0
  185. package/dist/remote/create-remote.js.map +1 -0
  186. package/dist/remote/prompt.d.ts +17 -0
  187. package/dist/remote/prompt.js +111 -0
  188. package/dist/remote/prompt.js.map +1 -0
  189. package/dist/remote/s3-sigv4.d.ts +28 -0
  190. package/dist/remote/s3-sigv4.js +100 -0
  191. package/dist/remote/s3-sigv4.js.map +1 -0
  192. package/dist/remote/s3-store.d.ts +75 -0
  193. package/dist/remote/s3-store.js +438 -0
  194. package/dist/remote/s3-store.js.map +1 -0
  195. package/dist/remote/s3-vendors.d.ts +31 -0
  196. package/dist/remote/s3-vendors.js +47 -0
  197. package/dist/remote/s3-vendors.js.map +1 -0
  198. package/dist/remote/store.d.ts +44 -0
  199. package/dist/remote/store.js +2 -0
  200. package/dist/remote/store.js.map +1 -0
  201. package/dist/remote/webdav-store.d.ts +41 -0
  202. package/dist/remote/webdav-store.js +285 -0
  203. package/dist/remote/webdav-store.js.map +1 -0
  204. package/dist/sqlite.d.ts +3 -0
  205. package/dist/sqlite.js +12 -0
  206. package/dist/sqlite.js.map +1 -0
  207. package/dist/status.d.ts +82 -0
  208. package/dist/status.js +162 -0
  209. package/dist/status.js.map +1 -0
  210. package/package.json +43 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-layout.js","sourceRoot":"","sources":["../../src/core/remote-layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export interface SessionSummary {
2
+ /** canonical 变体所属设备(并集时为 merged) */
3
+ device: string;
4
+ harness: string;
5
+ session: string;
6
+ title?: string;
7
+ firstText?: string;
8
+ cwd?: string;
9
+ model?: string;
10
+ startedAt?: string;
11
+ /** canonical 事件文件绝对路径 */
12
+ path: string;
13
+ bytes: number;
14
+ events: number;
15
+ /** 其他内容不同的设备版本数 */
16
+ variants: number;
17
+ devices: string[];
18
+ }
19
+ export interface ListSessionsOptions {
20
+ device?: string;
21
+ harness?: string;
22
+ /** 标题/摘要/目录/模型/正文的模糊匹配 */
23
+ grep?: string;
24
+ }
25
+ /**
26
+ * 列出 library 里的会话(canonical 视图)。
27
+ * 索引缺失时按分片重建;--grep 只读命中的 canonical 文件。
28
+ */
29
+ export declare function listSessions(vaultRoot: string, opts?: ListSessionsOptions): Promise<SessionSummary[]>;
@@ -0,0 +1,96 @@
1
+ import { createReadStream } from 'node:fs';
2
+ import { stat } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { createInterface } from 'node:readline';
5
+ import { libraryDir } from './layout.js';
6
+ import { loadLibraryIndex, rebuildUnifiedIndex } from './library/index-file.js';
7
+ function headerMatches(s, needle) {
8
+ return [s.title, s.firstText, s.cwd, s.model, s.session, s.harness]
9
+ .filter((v) => Boolean(v))
10
+ .some((v) => v.toLowerCase().includes(needle));
11
+ }
12
+ function eventMatches(e, needle) {
13
+ const parts = [
14
+ e.text,
15
+ e.title,
16
+ e.cwd,
17
+ e.model?.id,
18
+ e.tool?.name,
19
+ e.tool?.input === undefined ? undefined : JSON.stringify(e.tool.input),
20
+ typeof e.result?.output === 'string' ? e.result.output : undefined,
21
+ ];
22
+ return parts.some((v) => typeof v === 'string' && v.toLowerCase().includes(needle));
23
+ }
24
+ /** 在 canonical 事件文件里找关键词;命中即停。 */
25
+ async function bodyMatches(path, needle) {
26
+ const stream = createReadStream(path, { encoding: 'utf8' });
27
+ const rl = createInterface({ input: stream, crlfDelay: Infinity });
28
+ try {
29
+ for await (const line of rl) {
30
+ if (!line.trim())
31
+ continue;
32
+ let e;
33
+ try {
34
+ e = JSON.parse(line);
35
+ }
36
+ catch {
37
+ continue;
38
+ }
39
+ if (eventMatches(e, needle))
40
+ return true;
41
+ }
42
+ return false;
43
+ }
44
+ finally {
45
+ rl.close();
46
+ stream.destroy();
47
+ }
48
+ }
49
+ /**
50
+ * 列出 library 里的会话(canonical 视图)。
51
+ * 索引缺失时按分片重建;--grep 只读命中的 canonical 文件。
52
+ */
53
+ export async function listSessions(vaultRoot, opts = {}) {
54
+ const index = (await loadLibraryIndex(vaultRoot)) ?? (await rebuildUnifiedIndex(vaultRoot));
55
+ const needle = opts.grep?.toLowerCase();
56
+ const out = [];
57
+ for (const s of Object.values(index.sessions)) {
58
+ if (opts.harness && s.harness !== opts.harness)
59
+ continue;
60
+ if (opts.device && !s.sources.includes(opts.device))
61
+ continue;
62
+ if (needle && !headerMatches(s, needle)) {
63
+ const path = join(libraryDir(vaultRoot), ...s.canonical.path.split('/'));
64
+ if (!(await bodyMatches(path, needle)))
65
+ continue;
66
+ }
67
+ const path = join(libraryDir(vaultRoot), ...s.canonical.path.split('/'));
68
+ let bytes = 0;
69
+ try {
70
+ bytes = (await stat(path)).size;
71
+ }
72
+ catch {
73
+ // 索引指向的文件缺失:仍然列出,便于发现不一致
74
+ }
75
+ out.push({
76
+ device: s.canonical.device,
77
+ harness: s.harness,
78
+ session: s.session,
79
+ ...(s.title ? { title: s.title } : {}),
80
+ ...(s.firstText ? { firstText: s.firstText } : {}),
81
+ ...(s.cwd ? { cwd: s.cwd } : {}),
82
+ ...(s.model ? { model: s.model } : {}),
83
+ ...(s.startedAt ? { startedAt: s.startedAt } : {}),
84
+ path,
85
+ bytes,
86
+ events: s.canonical.events,
87
+ variants: s.variants.length,
88
+ devices: s.sources,
89
+ });
90
+ }
91
+ out.sort((a, b) => (b.startedAt ?? '').localeCompare(a.startedAt ?? '') ||
92
+ a.harness.localeCompare(b.harness) ||
93
+ a.session.localeCompare(b.session));
94
+ return out;
95
+ }
96
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/core/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA6BhF,SAAS,aAAa,CAAC,CAAgB,EAAE,MAAc;IACrD,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC;SAChE,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;SACtC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,YAAY,CAAC,CAAQ,EAAE,MAAc;IAC5C,MAAM,KAAK,GAAG;QACZ,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,KAAK,EAAE,EAAE;QACX,CAAC,CAAC,IAAI,EAAE,IAAI;QACZ,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QACtE,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;KACnE,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACtF,CAAC;AAED,kCAAkC;AAClC,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,MAAc;IACrD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5D,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IACnE,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS;YAC3B,IAAI,CAAQ,CAAC;YACb,IAAI,CAAC;gBACH,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAU,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,IAAI,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC3C,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,SAAiB,EACjB,OAA4B,EAAE;IAE9B,MAAM,KAAK,GAAG,CAAC,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,mBAAmB,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5F,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;IACxC,MAAM,GAAG,GAAqB,EAAE,CAAC;IAEjC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9C,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO;YAAE,SAAS;QACzD,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,SAAS;QAC9D,IAAI,MAAM,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YACzE,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAAE,SAAS;QACnD,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACzE,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,CAAC;YACH,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;QACD,GAAG,CAAC,IAAI,CAAC;YACP,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM;YAC1B,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,IAAI;YACJ,KAAK;YACL,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM;YAC1B,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM;YAC3B,OAAO,EAAE,CAAC,CAAC,OAAO;SACnB,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,IAAI,CACN,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;QACpD,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC;QAClC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CACrC,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,94 @@
1
+ import type { ChunkRef } from './chunker.js';
2
+ import type { FileCursor } from './cursor.js';
3
+ /** 源文件已归档状态(游标 + 会话归属)。 */
4
+ export interface SourceEntry extends FileCursor {
5
+ /** 会话 id:同一次对话的多个文件共享(豆包目录/多文件会话) */
6
+ sessionKey: string;
7
+ /** 会话最近变更时间,用于 --since 过滤 */
8
+ sessionMtimeMs: number;
9
+ /** SQLite 类数据源的导出格式版本;变化时强制重新导出 */
10
+ formatVersion?: number;
11
+ }
12
+ /** 已推送到远端的快照;size 是提交点,chunks 只增不改。 */
13
+ export interface PushedEntry {
14
+ generation: string;
15
+ size: number;
16
+ chunks: ChunkRef[];
17
+ /** chunks 数组的 sha256,与索引项比对,判断远端是否已是最新 */
18
+ chunksHash: string;
19
+ }
20
+ /** 已从某个远端设备拉取的快照。 */
21
+ export interface PulledEntry {
22
+ generation: string;
23
+ size: number;
24
+ chunksHash: string;
25
+ }
26
+ export interface DaemonStatus {
27
+ pid: number;
28
+ startedAt: number;
29
+ intervalSeconds: number;
30
+ since: string;
31
+ lastRunAt?: number;
32
+ lastDurationMs?: number;
33
+ lastError?: string;
34
+ nextRunAt?: number;
35
+ }
36
+ /** 本设备已构建的会话(增量判断用)。 */
37
+ export interface BuiltEntry {
38
+ sig: string;
39
+ hash: string;
40
+ events: number;
41
+ path: string;
42
+ /** 写入后的事件文件大小与 mtime,用于跳过未变化的文件 */
43
+ size?: number;
44
+ mtimeMs?: number;
45
+ /** 映射后得到的会话 id(可能不同于路径推导值) */
46
+ session?: string;
47
+ title?: string;
48
+ firstText?: string;
49
+ cwd?: string;
50
+ model?: string;
51
+ startedAt?: string;
52
+ }
53
+ export interface LibraryState {
54
+ built: Record<string, BuiltEntry>;
55
+ /** 已推送的 library 文件: path → {size, hash} */
56
+ pushed: Record<string, {
57
+ size: number;
58
+ mtimeMs?: number;
59
+ hash?: string;
60
+ }>;
61
+ /** 已拉取的 library 文件: device → path → hash */
62
+ pulled: Record<string, Record<string, string>>;
63
+ /**
64
+ * library.pushed 记录所属的远端身份。
65
+ * 换后端后旧记录对新远端无效,否则会整体跳过上传,只剩索引分片指向不存在的文件。
66
+ */
67
+ remoteId?: string;
68
+ }
69
+ export interface State {
70
+ v: 1;
71
+ /** harness → 本地文件(或 SQLite 会话) → 游标 */
72
+ sources: Record<string, Record<string, SourceEntry>>;
73
+ /** harness → 本地文件 key → 已推送快照 */
74
+ pushed: Record<string, Record<string, PushedEntry>>;
75
+ /** 远端设备 id → "harness:key" → 已拉取快照 */
76
+ pulled: Record<string, Record<string, PulledEntry>>;
77
+ library: LibraryState;
78
+ daemon?: DaemonStatus;
79
+ /**
80
+ * pushed/pulled 记录所属的远端身份指纹。
81
+ * 换后端(WebDAV → S3)后这些记录对新远端无效,必须整份重推。
82
+ */
83
+ remoteId?: string;
84
+ }
85
+ export declare function emptyLibraryState(): LibraryState;
86
+ export declare function emptyState(): State;
87
+ /** 读取状态;不存在返回空状态。损坏 JSON 抛出可定位的错误。 */
88
+ export declare function loadState(path: string): Promise<State>;
89
+ /** 原子写入:临时文件 + rename,避免进程中断留下半个 JSON。 */
90
+ export declare function saveState(path: string, state: State): Promise<void>;
91
+ /** 取(或创建)某个 harness 的源状态表。 */
92
+ export declare function sourceBucket(state: State, harness: string): Record<string, SourceEntry>;
93
+ export declare function pushedBucket(state: State, harness: string): Record<string, PushedEntry>;
94
+ export declare function pulledBucket(state: State, deviceId: string): Record<string, PulledEntry>;
@@ -0,0 +1,62 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
3
+ import { dirname, join } from 'node:path';
4
+ export function emptyLibraryState() {
5
+ return { built: {}, pushed: {}, pulled: {} };
6
+ }
7
+ export function emptyState() {
8
+ return { v: 1, sources: {}, pushed: {}, pulled: {}, library: emptyLibraryState() };
9
+ }
10
+ /** 读取状态;不存在返回空状态。损坏 JSON 抛出可定位的错误。 */
11
+ export async function loadState(path) {
12
+ let raw;
13
+ try {
14
+ raw = await readFile(path, 'utf8');
15
+ }
16
+ catch (err) {
17
+ if (err.code === 'ENOENT')
18
+ return emptyState();
19
+ throw err;
20
+ }
21
+ let parsed;
22
+ try {
23
+ parsed = JSON.parse(raw);
24
+ }
25
+ catch {
26
+ throw new Error(`state 损坏,无法解析 JSON: ${path}`);
27
+ }
28
+ // 旧版对话层挂在 raw 下(_events/),已迁到 library:读入时清掉遗留条目
29
+ for (const bucket of Object.values(parsed.sources ?? {})) {
30
+ for (const key of Object.keys(bucket)) {
31
+ if (key.startsWith('_events/'))
32
+ delete bucket[key];
33
+ }
34
+ }
35
+ return {
36
+ v: 1,
37
+ sources: parsed.sources ?? {},
38
+ pushed: parsed.pushed ?? {},
39
+ pulled: parsed.pulled ?? {},
40
+ library: parsed.library ?? emptyLibraryState(),
41
+ ...(parsed.daemon ? { daemon: parsed.daemon } : {}),
42
+ ...(parsed.remoteId ? { remoteId: parsed.remoteId } : {}),
43
+ };
44
+ }
45
+ /** 原子写入:临时文件 + rename,避免进程中断留下半个 JSON。 */
46
+ export async function saveState(path, state) {
47
+ await mkdir(dirname(path), { recursive: true });
48
+ const tmp = join(dirname(path), `.state.tmp-${randomUUID()}`);
49
+ await writeFile(tmp, JSON.stringify(state), 'utf8');
50
+ await rename(tmp, path);
51
+ }
52
+ /** 取(或创建)某个 harness 的源状态表。 */
53
+ export function sourceBucket(state, harness) {
54
+ return (state.sources[harness] ??= {});
55
+ }
56
+ export function pushedBucket(state, harness) {
57
+ return (state.pushed[harness] ??= {});
58
+ }
59
+ export function pulledBucket(state, deviceId) {
60
+ return (state.pulled[deviceId] ??= {});
61
+ }
62
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { type CollectResult } from './collect.js';
2
+ import { type PullResult } from './pull.js';
3
+ import { type PushResult } from './push.js';
4
+ import { type PullLibraryResult, type PushLibraryResult } from './library/sync.js';
5
+ import { type Progress } from '../progress.js';
6
+ import type { Adapter } from '../adapters/index.js';
7
+ import type { RemoteStore } from '../remote/store.js';
8
+ export interface SyncOptions {
9
+ adapters: Adapter[];
10
+ deviceId: string;
11
+ deviceName: string;
12
+ vaultRoot: string;
13
+ statePath: string;
14
+ /** null = 本地模式(未配置远端),只归档到本地 vault,不做远端拉/推 */
15
+ remote: RemoteStore | null;
16
+ /** 远端身份指纹;换后端时本地推送水位作废,历史数据整份重推。 */
17
+ remoteId?: string;
18
+ /** 0 = 全量;否则只收集最近变更的会话 */
19
+ cutoff: number;
20
+ tmpDir?: string;
21
+ chunkSize?: number;
22
+ concurrency?: number;
23
+ progress?: Progress;
24
+ now?: () => number;
25
+ pullOnly?: boolean;
26
+ pushOnly?: boolean;
27
+ /** false 时只同步对话层(_events/),raw 只归档到本地 */
28
+ rawSync?: boolean;
29
+ signal?: AbortSignal;
30
+ }
31
+ export interface SyncReport {
32
+ collected: CollectResult;
33
+ pulled: PullResult;
34
+ pushed: PushResult;
35
+ library: {
36
+ pulled: PullLibraryResult;
37
+ pushed: PushLibraryResult;
38
+ };
39
+ /** 本轮开始时检测到远端身份变化(切换后端/换桶)。 */
40
+ remoteChanged: boolean;
41
+ durationMs: number;
42
+ }
43
+ /**
44
+ * 一次完整同步:collect(本机 → vault)→ pull(远端 → vault)→ push(vault → 远端)。
45
+ * 每个阶段结束都落状态,长同步被打断也不必从头再来。
46
+ */
47
+ /** 同一份 vault/state 只允许一个进程写:daemon 与手动 sync 共用此锁。 */
48
+ export declare function sync(opts: SyncOptions): Promise<SyncReport>;
@@ -0,0 +1,140 @@
1
+ import { collect } from './collect.js';
2
+ import { pullRemote } from './pull.js';
3
+ import { pushLocal } from './push.js';
4
+ import { pullLibrary, pushLibrary } from './library/sync.js';
5
+ import { acquireLock } from './lock.js';
6
+ import { loadState, saveState } from './state.js';
7
+ import { metaPath } from './remote-layout.js';
8
+ import { silentProgress } from '../progress.js';
9
+ const emptyCollect = {
10
+ discovered: 0,
11
+ archived: 0,
12
+ appended: 0,
13
+ skipped: 0,
14
+ outOfWindow: 0,
15
+ bytesCopied: 0,
16
+ sessions: 0,
17
+ changedSessions: [],
18
+ };
19
+ const emptyPull = {
20
+ downloadedChunks: 0,
21
+ downloadedBytes: 0,
22
+ downloadedItems: 0,
23
+ skippedItems: 0,
24
+ };
25
+ const emptyPush = {
26
+ uploadedChunks: 0,
27
+ uploadedBytes: 0,
28
+ uploadedItems: 0,
29
+ skippedItems: 0,
30
+ };
31
+ /**
32
+ * 一次完整同步:collect(本机 → vault)→ pull(远端 → vault)→ push(vault → 远端)。
33
+ * 每个阶段结束都落状态,长同步被打断也不必从头再来。
34
+ */
35
+ /** 同一份 vault/state 只允许一个进程写:daemon 与手动 sync 共用此锁。 */
36
+ export async function sync(opts) {
37
+ const release = await acquireLock(`${opts.statePath}.lock`);
38
+ try {
39
+ return await syncUnlocked(opts);
40
+ }
41
+ finally {
42
+ await release();
43
+ }
44
+ }
45
+ async function syncUnlocked(opts) {
46
+ const now = opts.now ?? Date.now;
47
+ const started = now();
48
+ const progress = opts.progress ?? silentProgress;
49
+ const state = await loadState(opts.statePath);
50
+ // 本轮开始时判断是否换了远端;push 阶段会更新 state.remoteId,所以必须提前算
51
+ const remoteChanged = Boolean(opts.remoteId && state.remoteId && opts.remoteId !== state.remoteId);
52
+ let collected = emptyCollect;
53
+ if (!opts.pullOnly) {
54
+ collected = await collect({
55
+ adapters: opts.adapters,
56
+ deviceId: opts.deviceId,
57
+ vaultRoot: opts.vaultRoot,
58
+ state,
59
+ cutoff: opts.cutoff,
60
+ progress,
61
+ tmpDir: opts.tmpDir,
62
+ signal: opts.signal,
63
+ });
64
+ await saveState(opts.statePath, state);
65
+ }
66
+ const emptyLibrary = {
67
+ pulled: { downloaded: 0, bytes: 0, skipped: 0 },
68
+ pushed: { uploaded: 0, bytes: 0, skipped: 0 },
69
+ };
70
+ let pulled = emptyPull;
71
+ let libraryPulled = emptyLibrary.pulled;
72
+ if (!opts.pushOnly) {
73
+ if (opts.remote) {
74
+ if (opts.rawSync !== false)
75
+ pulled = await pullRemote({
76
+ remote: opts.remote,
77
+ deviceId: opts.deviceId,
78
+ vaultRoot: opts.vaultRoot,
79
+ state,
80
+ progress,
81
+ signal: opts.signal,
82
+ });
83
+ libraryPulled = await pullLibrary({
84
+ remote: opts.remote,
85
+ vaultRoot: opts.vaultRoot,
86
+ deviceId: opts.deviceId,
87
+ state,
88
+ progress,
89
+ signal: opts.signal,
90
+ });
91
+ }
92
+ await saveState(opts.statePath, state);
93
+ }
94
+ let pushed = emptyPush;
95
+ let libraryPushed = emptyLibrary.pushed;
96
+ if (!opts.pullOnly) {
97
+ if (opts.remote) {
98
+ if (opts.rawSync !== false)
99
+ pushed = await pushLocal({
100
+ remote: opts.remote,
101
+ deviceId: opts.deviceId,
102
+ vaultRoot: opts.vaultRoot,
103
+ state,
104
+ remoteId: opts.remoteId,
105
+ now,
106
+ chunkSize: opts.chunkSize,
107
+ concurrency: opts.concurrency,
108
+ progress,
109
+ signal: opts.signal,
110
+ });
111
+ libraryPushed = await pushLibrary({
112
+ remote: opts.remote,
113
+ vaultRoot: opts.vaultRoot,
114
+ deviceId: opts.deviceId,
115
+ state,
116
+ remoteId: opts.remoteId,
117
+ statePath: opts.statePath,
118
+ progress,
119
+ signal: opts.signal,
120
+ });
121
+ if (opts.rawSync !== false) {
122
+ await opts.remote.writeJson(metaPath(opts.deviceId), {
123
+ id: opts.deviceId,
124
+ name: opts.deviceName,
125
+ lastSeen: now(),
126
+ });
127
+ }
128
+ }
129
+ await saveState(opts.statePath, state);
130
+ }
131
+ return {
132
+ collected,
133
+ pulled,
134
+ pushed,
135
+ library: { pulled: libraryPulled, pushed: libraryPushed },
136
+ remoteChanged,
137
+ durationMs: now() - started,
138
+ };
139
+ }
140
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/core/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 同步时间窗:只收集「最近变更」的会话,避免首次全量过大。
3
+ * 单位支持 m/h/d/w;all 表示不限制;也接受 YYYY-MM-DD(本地零点)。
4
+ */
5
+ /** 返回截止时间(ms);0 表示不限制。非法输入抛错。 */
6
+ export declare function parseSince(input: string, now?: number): number;
7
+ /** 展示用:0 显示 all,其它显示本地日期时间。 */
8
+ export declare function formatSince(cutoff: number): string;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * 同步时间窗:只收集「最近变更」的会话,避免首次全量过大。
3
+ * 单位支持 m/h/d/w;all 表示不限制;也接受 YYYY-MM-DD(本地零点)。
4
+ */
5
+ const UNIT_MS = {
6
+ m: 60_000,
7
+ h: 3600_000,
8
+ d: 86_400_000,
9
+ w: 7 * 86_400_000,
10
+ };
11
+ /** 返回截止时间(ms);0 表示不限制。非法输入抛错。 */
12
+ export function parseSince(input, now = Date.now()) {
13
+ const raw = input.trim().toLowerCase();
14
+ if (raw === 'all' || raw === '' || raw === '0')
15
+ return 0;
16
+ const rel = /^(\d+)([mhdw])$/.exec(raw);
17
+ if (rel) {
18
+ const n = Number(rel[1]);
19
+ return now - n * UNIT_MS[rel[2]];
20
+ }
21
+ if (/^\d{4}-\d{2}-\d{2}$/.test(raw)) {
22
+ const t = new Date(`${raw}T00:00:00`).getTime();
23
+ if (Number.isFinite(t))
24
+ return t;
25
+ }
26
+ throw new Error(`无法解析时间范围 "${input}"(示例:7d / 24h / 2026-10-01 / all)`);
27
+ }
28
+ /** 展示用:0 显示 all,其它显示本地日期时间。 */
29
+ export function formatSince(cutoff) {
30
+ if (!cutoff)
31
+ return 'all';
32
+ const d = new Date(cutoff);
33
+ const p = (n) => String(n).padStart(2, '0');
34
+ return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
35
+ }
36
+ //# sourceMappingURL=time-window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time-window.js","sourceRoot":"","sources":["../../src/core/time-window.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,OAAO,GAA2B;IACtC,CAAC,EAAE,MAAM;IACT,CAAC,EAAE,QAAQ;IACX,CAAC,EAAE,UAAU;IACb,CAAC,EAAE,CAAC,GAAG,UAAU;CAClB,CAAC;AAEF,iCAAiC;AACjC,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,MAAc,IAAI,CAAC,GAAG,EAAE;IAChE,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACvC,IAAI,GAAG,KAAK,KAAK,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC;IAEzD,MAAM,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACzB,OAAO,GAAG,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAE,CAAE,CAAC;IACrC,CAAC;IAED,IAAI,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;QAChD,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,aAAa,KAAK,mCAAmC,CAAC,CAAC;AACzE,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3B,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpD,OAAO,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;AAC/G,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { isProcessAlive } from './core/lock.js';
2
+ import type { Progress } from './progress.js';
3
+ import type { SyncReport } from './core/sync.js';
4
+ import type { TrovePaths } from './paths.js';
5
+ export interface DaemonStatusFile {
6
+ running: boolean;
7
+ pid: number;
8
+ startedAt: number;
9
+ intervalSeconds: number;
10
+ since: string;
11
+ lastRunAt?: number;
12
+ lastDurationMs?: number;
13
+ lastError?: string;
14
+ lastResult?: Pick<SyncReport, 'collected' | 'pulled' | 'pushed'>;
15
+ nextRunAt?: number;
16
+ }
17
+ export interface DaemonRuntime {
18
+ paths: TrovePaths;
19
+ intervalSeconds: number;
20
+ since: string;
21
+ /** 一轮同步;由 CLI 注入(config/adapters/remote 的组装) */
22
+ runOnce: (progress: Progress, signal: AbortSignal) => Promise<SyncReport>;
23
+ /** 同步成功后触发(把本轮新会话入队等);返回可选的日志行。失败只记日志,不中断循环。 */
24
+ afterSync?: (report: SyncReport) => Promise<string | undefined>;
25
+ /** learn 独立循环的 tick:处理队列里最多 learnBatch 个候选。缺省不启 learn 循环。 */
26
+ learnTick?: () => Promise<string | undefined>;
27
+ /** learn 循环间隔秒数;缺省等同 intervalSeconds。 */
28
+ learnIntervalSeconds?: number;
29
+ }
30
+ export declare const isAlive: typeof isProcessAlive;
31
+ /** 单实例锁:pid 文件不存在才创建;陈旧 pid(进程已死)自动接管。 */
32
+ export declare function acquireDaemonPid(paths: TrovePaths): Promise<void>;
33
+ export declare function releaseDaemonPid(paths: TrovePaths): Promise<void>;
34
+ export declare function readDaemonStatus(paths: TrovePaths): Promise<DaemonStatusFile | null>;
35
+ /** 日志超过 10MB 轮转一份,避免 daemon 无限写。 */
36
+ export declare function daemonLog(paths: TrovePaths, text: string): Promise<void>;
37
+ /**
38
+ * daemon 主循环:sync 与 learn 两个循环并发跑,共享 abort 信号;SIGTERM/abort 后清理 pid 退出。
39
+ * sync 循环每轮状态写 daemon.status.json,供 `trove daemon status` 读取;learn 循环只写日志。
40
+ */
41
+ export declare function runDaemon(runtime: DaemonRuntime, signal: AbortSignal): Promise<void>;
42
+ export interface StartDaemonOptions {
43
+ paths: TrovePaths;
44
+ intervalSeconds: number;
45
+ since: string;
46
+ /** 显式 raw 同步开关;undefined = 跟随配置 */
47
+ raw?: boolean;
48
+ /** 默认 process.argv[1](构建后的 dist/main.js) */
49
+ entry?: string;
50
+ /** 追加/覆盖子进程环境变量(init 用它把 TROVE_HOME 传给子进程) */
51
+ env?: NodeJS.ProcessEnv;
52
+ }
53
+ /** 后台启动:spawn 一个独立进程,等待 pid 文件落盘后返回。 */
54
+ export declare function startDaemon(opts: StartDaemonOptions): Promise<number>;
55
+ /** 优雅停止:发 SIGTERM,最多等 5 秒;不做 SIGKILL,避免中断写入。 */
56
+ export declare function stopDaemon(paths: TrovePaths): Promise<boolean>;
57
+ export interface RestartDaemonOptions extends StartDaemonOptions {
58
+ /** 停止函数;测试注入 stub */
59
+ stop?: (paths: TrovePaths) => Promise<boolean>;
60
+ }
61
+ /**
62
+ * 重启:先优雅停止(没在跑就直接跳过),再按同样的参数后台拉起。
63
+ * 停止失败(进程没退)时 startDaemon 会因 pid 锁仍在而报错,不会起两个实例。
64
+ */
65
+ export declare function restartDaemon(opts: RestartDaemonOptions): Promise<{
66
+ pid: number;
67
+ wasRunning: boolean;
68
+ }>;
69
+ export declare function daemonState(paths: TrovePaths): Promise<{
70
+ running: boolean;
71
+ pid?: number;
72
+ status: DaemonStatusFile | null;
73
+ }>;