@cleocode/core 2026.5.131 → 2026.5.133

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 (110) hide show
  1. package/dist/db/index.d.ts +36 -0
  2. package/dist/db/index.d.ts.map +1 -0
  3. package/dist/db/index.js +36 -0
  4. package/dist/db/index.js.map +1 -0
  5. package/dist/gc/daemon.d.ts +17 -8
  6. package/dist/gc/daemon.d.ts.map +1 -1
  7. package/dist/gc/daemon.js +24 -67
  8. package/dist/gc/daemon.js.map +1 -1
  9. package/dist/gc/gc-subsystem.d.ts +96 -0
  10. package/dist/gc/gc-subsystem.d.ts.map +1 -0
  11. package/dist/gc/gc-subsystem.js +186 -0
  12. package/dist/gc/gc-subsystem.js.map +1 -0
  13. package/dist/gc/index.d.ts +1 -0
  14. package/dist/gc/index.d.ts.map +1 -1
  15. package/dist/gc/index.js +1 -0
  16. package/dist/gc/index.js.map +1 -1
  17. package/dist/go/driver.d.ts +132 -0
  18. package/dist/go/driver.d.ts.map +1 -0
  19. package/dist/go/driver.js +191 -0
  20. package/dist/go/driver.js.map +1 -0
  21. package/dist/go/index.d.ts +13 -0
  22. package/dist/go/index.d.ts.map +1 -0
  23. package/dist/go/index.js +13 -0
  24. package/dist/go/index.js.map +1 -0
  25. package/dist/goal/advance-with-persist.d.ts +80 -0
  26. package/dist/goal/advance-with-persist.d.ts.map +1 -0
  27. package/dist/goal/advance-with-persist.js +105 -0
  28. package/dist/goal/advance-with-persist.js.map +1 -0
  29. package/dist/goal/arm.d.ts +61 -0
  30. package/dist/goal/arm.d.ts.map +1 -0
  31. package/dist/goal/arm.js +65 -0
  32. package/dist/goal/arm.js.map +1 -0
  33. package/dist/goal/index.d.ts +2 -0
  34. package/dist/goal/index.d.ts.map +1 -1
  35. package/dist/goal/index.js +2 -0
  36. package/dist/goal/index.js.map +1 -1
  37. package/dist/index.d.ts +3 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +3 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/orchestrate/lifecycle-ops.js +1 -1
  42. package/dist/orchestrate/lifecycle-ops.js.map +1 -1
  43. package/dist/orchestration/classify-readiness.d.ts +172 -0
  44. package/dist/orchestration/classify-readiness.d.ts.map +1 -0
  45. package/dist/orchestration/classify-readiness.js +346 -0
  46. package/dist/orchestration/classify-readiness.js.map +1 -0
  47. package/dist/orchestration/index.d.ts +2 -0
  48. package/dist/orchestration/index.d.ts.map +1 -1
  49. package/dist/orchestration/index.js +1 -0
  50. package/dist/orchestration/index.js.map +1 -1
  51. package/dist/output.d.ts +2 -0
  52. package/dist/output.d.ts.map +1 -1
  53. package/dist/output.js +59 -1
  54. package/dist/output.js.map +1 -1
  55. package/dist/release/pr-evidence.d.ts +4 -3
  56. package/dist/release/pr-evidence.d.ts.map +1 -1
  57. package/dist/release/pr-evidence.js +4 -3
  58. package/dist/release/pr-evidence.js.map +1 -1
  59. package/dist/sagas/index.d.ts +1 -0
  60. package/dist/sagas/index.d.ts.map +1 -1
  61. package/dist/sagas/index.js +1 -0
  62. package/dist/sagas/index.js.map +1 -1
  63. package/dist/sagas/next.d.ts +77 -0
  64. package/dist/sagas/next.d.ts.map +1 -0
  65. package/dist/sagas/next.js +159 -0
  66. package/dist/sagas/next.js.map +1 -0
  67. package/dist/sentient/daemon-entry.d.ts +6 -0
  68. package/dist/sentient/daemon-entry.d.ts.map +1 -1
  69. package/dist/sentient/daemon-entry.js +10 -1
  70. package/dist/sentient/daemon-entry.js.map +1 -1
  71. package/dist/sentient/daemon.d.ts +30 -0
  72. package/dist/sentient/daemon.d.ts.map +1 -1
  73. package/dist/sentient/daemon.js +12 -2
  74. package/dist/sentient/daemon.js.map +1 -1
  75. package/dist/sentient/index.d.ts +2 -0
  76. package/dist/sentient/index.d.ts.map +1 -1
  77. package/dist/sentient/index.js +5 -0
  78. package/dist/sentient/index.js.map +1 -1
  79. package/dist/sentient/propose-tick.d.ts +101 -0
  80. package/dist/sentient/propose-tick.d.ts.map +1 -1
  81. package/dist/sentient/propose-tick.js +284 -0
  82. package/dist/sentient/propose-tick.js.map +1 -1
  83. package/dist/sentient/tick.d.ts +23 -0
  84. package/dist/sentient/tick.d.ts.map +1 -1
  85. package/dist/sentient/tick.js +91 -21
  86. package/dist/sentient/tick.js.map +1 -1
  87. package/dist/store/dual-scope-db.d.ts +183 -0
  88. package/dist/store/dual-scope-db.d.ts.map +1 -0
  89. package/dist/store/dual-scope-db.js +315 -0
  90. package/dist/store/dual-scope-db.js.map +1 -0
  91. package/dist/store/open-cleo-db.d.ts +51 -4
  92. package/dist/store/open-cleo-db.d.ts.map +1 -1
  93. package/dist/store/open-cleo-db.js +56 -2
  94. package/dist/store/open-cleo-db.js.map +1 -1
  95. package/dist/store/schema/cleo-global/nexus.d.ts +1 -1
  96. package/dist/store/schema/cleo-global/signaldock.d.ts +1 -1
  97. package/dist/store/schema/cleo-shared/brain.d.ts +1 -1
  98. package/dist/tasks/add.d.ts.map +1 -1
  99. package/dist/tasks/add.js +16 -2
  100. package/dist/tasks/add.js.map +1 -1
  101. package/dist/tasks/evidence.d.ts +3 -2
  102. package/dist/tasks/evidence.d.ts.map +1 -1
  103. package/dist/tasks/evidence.js.map +1 -1
  104. package/dist/verification/verify-tools.d.ts +164 -0
  105. package/dist/verification/verify-tools.d.ts.map +1 -0
  106. package/dist/verification/verify-tools.js +236 -0
  107. package/dist/verification/verify-tools.js.map +1 -0
  108. package/package.json +16 -11
  109. package/templates/CLEO-INJECTION.md +3 -2
  110. package/templates/workflows/release-prepare.yml.tmpl +86 -7
@@ -0,0 +1,36 @@
1
+ /**
2
+ * `@cleocode/core/db` subpath export — typed dual-scope SQLite client.
3
+ *
4
+ * This barrel re-exports the public API of the dual-scope DB chokepoint
5
+ * implemented in `packages/core/src/store/dual-scope-db.ts` as the
6
+ * `@cleocode/core/db` subpath module.
7
+ *
8
+ * ## What is exported
9
+ *
10
+ * - {@link openDualScopeDb} — open (or re-use) the consolidated `cleo.db`
11
+ * for either scope.
12
+ * - {@link DualScopeDbHandle} — handle type returned by `openDualScopeDb`.
13
+ * - {@link DualScope} — the `'project' | 'global'` scope union.
14
+ * - {@link CleoProjectDb} — typed Drizzle handle for the project scope.
15
+ * - {@link CleoGlobalDb} — typed Drizzle handle for the global scope.
16
+ * - {@link resolveDualScopeDbPath} — resolve the absolute DB file path.
17
+ * - {@link insertIdempotent} — retry-safe insert (ON CONFLICT DO NOTHING).
18
+ * - {@link upsertIdempotent} — retry-safe upsert (ON CONFLICT DO UPDATE).
19
+ * - {@link _resetDualScopeDbCache} — test helper: clear singleton cache.
20
+ *
21
+ * ## Usage
22
+ *
23
+ * ```ts
24
+ * import { openDualScopeDb, insertIdempotent } from '@cleocode/core/db';
25
+ *
26
+ * const proj = await openDualScopeDb('project', process.cwd());
27
+ * const global = await openDualScopeDb('global');
28
+ * ```
29
+ *
30
+ * @packageDocumentation
31
+ * @task T11514 (E4-T3)
32
+ * @epic T11247 (E4)
33
+ * @saga T11242 (SG-DB-SUBSTRATE-V2)
34
+ */
35
+ export { _resetDualScopeDbCache, type CleoGlobalDb, type CleoProjectDb, type DualScope, type DualScopeDbHandle, insertIdempotent, openDualScopeDb, resolveDualScopeDbPath, upsertIdempotent, } from '../store/dual-scope-db.js';
36
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EACL,sBAAsB,EACtB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * `@cleocode/core/db` subpath export — typed dual-scope SQLite client.
3
+ *
4
+ * This barrel re-exports the public API of the dual-scope DB chokepoint
5
+ * implemented in `packages/core/src/store/dual-scope-db.ts` as the
6
+ * `@cleocode/core/db` subpath module.
7
+ *
8
+ * ## What is exported
9
+ *
10
+ * - {@link openDualScopeDb} — open (or re-use) the consolidated `cleo.db`
11
+ * for either scope.
12
+ * - {@link DualScopeDbHandle} — handle type returned by `openDualScopeDb`.
13
+ * - {@link DualScope} — the `'project' | 'global'` scope union.
14
+ * - {@link CleoProjectDb} — typed Drizzle handle for the project scope.
15
+ * - {@link CleoGlobalDb} — typed Drizzle handle for the global scope.
16
+ * - {@link resolveDualScopeDbPath} — resolve the absolute DB file path.
17
+ * - {@link insertIdempotent} — retry-safe insert (ON CONFLICT DO NOTHING).
18
+ * - {@link upsertIdempotent} — retry-safe upsert (ON CONFLICT DO UPDATE).
19
+ * - {@link _resetDualScopeDbCache} — test helper: clear singleton cache.
20
+ *
21
+ * ## Usage
22
+ *
23
+ * ```ts
24
+ * import { openDualScopeDb, insertIdempotent } from '@cleocode/core/db';
25
+ *
26
+ * const proj = await openDualScopeDb('project', process.cwd());
27
+ * const global = await openDualScopeDb('global');
28
+ * ```
29
+ *
30
+ * @packageDocumentation
31
+ * @task T11514 (E4-T3)
32
+ * @epic T11247 (E4)
33
+ * @saga T11242 (SG-DB-SUBSTRATE-V2)
34
+ */
35
+ export { _resetDualScopeDbCache, insertIdempotent, openDualScopeDb, resolveDualScopeDbPath, upsertIdempotent, } from '../store/dual-scope-db.js';
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EACL,sBAAsB,EAKtB,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,2BAA2B,CAAC"}
@@ -8,13 +8,21 @@
8
8
  * - Crash recovery via `.cleo/gc-state.json` startup-check
9
9
  * - node-cron v4 for scheduling (zero runtime deps, cross-platform)
10
10
  *
11
- * Startup algorithm (systemd `Persistent=true` semantics in pure Node.js):
12
- * 1. Read gc-state.json
13
- * 2. If pendingPrune non-empty resume deletion (crash recovery)
14
- * 3. If lastRunAt null OR elapsed > 24h → run GC immediately (missed-run recovery)
15
- * 4. Schedule future runs via node-cron (daily at 03:00 UTC)
16
- * 5. Write daemonPid to state
11
+ * R5 migration (T11256)
12
+ * ----------------------
13
+ * The standalone cron loop that previously lived inside `bootstrapDaemon` has
14
+ * been migrated to the `@cleocode/runtime` subsystem framework
15
+ * (`gc-subsystem.ts`). `bootstrapDaemon` now delegates to
16
+ * `createGcSubsystem(cleoDir).start()` so the same startup algorithm (crash
17
+ * recovery → missed-run recovery → cron schedule) is expressed once, in the
18
+ * `Subsystem<GcSubsystemContext>` shape, and the standalone entry-point
19
+ * (`daemon-entry.ts`) drives it through the uniform lifecycle.
17
20
  *
21
+ * The spawn helpers (`spawnGCDaemon`, `stopGCDaemon`, `getGCDaemonStatus`) are
22
+ * preserved unchanged — they are the parent-process-side interface and are
23
+ * unaffected by the internal lifecycle migration.
24
+ *
25
+ * @see packages/core/src/gc/gc-subsystem.ts — subsystem adapter (R5-T1)
18
26
  * @see ADR-047 — Autonomous GC and Disk Safety
19
27
  * @see T751 §2.2 for sidecar daemon pattern rationale
20
28
  * @task T731
@@ -23,8 +31,9 @@
23
31
  /**
24
32
  * Bootstrap the GC daemon process.
25
33
  *
26
- * Performs crash recovery, missed-run recovery, and schedules future GC runs.
27
- * This function runs in the long-lived daemon process.
34
+ * Delegates to `createGcSubsystem(cleoDir).start()` which performs crash
35
+ * recovery, missed-run recovery, and schedules future GC runs — the
36
+ * standalone cron loop no longer lives here (R5 migration, T11256).
28
37
  *
29
38
  * @param cleoDir - Absolute path to the `.cleo/` directory
30
39
  */
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/gc/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AA0BH;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DpE;AAMD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmCpE;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCnE;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC,CAsBD"}
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/gc/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAeH;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOpE;AAMD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmCpE;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCnE;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC,CAsBD"}
package/dist/gc/daemon.js CHANGED
@@ -8,13 +8,21 @@
8
8
  * - Crash recovery via `.cleo/gc-state.json` startup-check
9
9
  * - node-cron v4 for scheduling (zero runtime deps, cross-platform)
10
10
  *
11
- * Startup algorithm (systemd `Persistent=true` semantics in pure Node.js):
12
- * 1. Read gc-state.json
13
- * 2. If pendingPrune non-empty resume deletion (crash recovery)
14
- * 3. If lastRunAt null OR elapsed > 24h → run GC immediately (missed-run recovery)
15
- * 4. Schedule future runs via node-cron (daily at 03:00 UTC)
16
- * 5. Write daemonPid to state
11
+ * R5 migration (T11256)
12
+ * ----------------------
13
+ * The standalone cron loop that previously lived inside `bootstrapDaemon` has
14
+ * been migrated to the `@cleocode/runtime` subsystem framework
15
+ * (`gc-subsystem.ts`). `bootstrapDaemon` now delegates to
16
+ * `createGcSubsystem(cleoDir).start()` so the same startup algorithm (crash
17
+ * recovery → missed-run recovery → cron schedule) is expressed once, in the
18
+ * `Subsystem<GcSubsystemContext>` shape, and the standalone entry-point
19
+ * (`daemon-entry.ts`) drives it through the uniform lifecycle.
17
20
  *
21
+ * The spawn helpers (`spawnGCDaemon`, `stopGCDaemon`, `getGCDaemonStatus`) are
22
+ * preserved unchanged — they are the parent-process-side interface and are
23
+ * unaffected by the internal lifecycle migration.
24
+ *
25
+ * @see packages/core/src/gc/gc-subsystem.ts — subsystem adapter (R5-T1)
18
26
  * @see ADR-047 — Autonomous GC and Disk Safety
19
27
  * @see T751 §2.2 for sidecar daemon pattern rationale
20
28
  * @task T731
@@ -26,78 +34,27 @@ import { createWriteStream } from 'node:fs';
26
34
  import { mkdir } from 'node:fs/promises';
27
35
  import { join } from 'node:path';
28
36
  import { fileURLToPath } from 'node:url';
29
- import cron from 'node-cron';
30
- import { runGC } from './runner.js';
37
+ import { createGcSubsystem } from './gc-subsystem.js';
31
38
  import { patchGCState, readGCState } from './state.js';
32
39
  // ---------------------------------------------------------------------------
33
- // Constants
34
- // ---------------------------------------------------------------------------
35
- /** Cron expression: daily at 03:00 UTC. */
36
- const GC_CRON_EXPR = '0 3 * * *';
37
- /** Interval for missed-run recovery check (24 hours in ms). */
38
- const GC_INTERVAL_MS = 24 * 60 * 60 * 1000;
39
- // ---------------------------------------------------------------------------
40
40
  // Daemon Bootstrap (runs when this module is executed as a standalone script)
41
41
  // ---------------------------------------------------------------------------
42
42
  /**
43
43
  * Bootstrap the GC daemon process.
44
44
  *
45
- * Performs crash recovery, missed-run recovery, and schedules future GC runs.
46
- * This function runs in the long-lived daemon process.
45
+ * Delegates to `createGcSubsystem(cleoDir).start()` which performs crash
46
+ * recovery, missed-run recovery, and schedules future GC runs — the
47
+ * standalone cron loop no longer lives here (R5 migration, T11256).
47
48
  *
48
49
  * @param cleoDir - Absolute path to the `.cleo/` directory
49
50
  */
50
51
  export async function bootstrapDaemon(cleoDir) {
51
- const statePath = join(cleoDir, 'gc-state.json');
52
- // Register daemon PID in state file
53
- await patchGCState(statePath, {
54
- daemonPid: process.pid,
55
- daemonStartedAt: new Date().toISOString(),
56
- });
57
- const state = await readGCState(statePath);
58
- // Step 1: Crash recovery — resume pending prune from prior run
59
- if (state.pendingPrune && state.pendingPrune.length > 0) {
60
- try {
61
- await runGC({ cleoDir, resumeFrom: state.pendingPrune });
62
- }
63
- catch {
64
- // Crash recovery failure is non-fatal; continue with scheduled runs
65
- }
66
- }
67
- // Step 2: Missed-run recovery — if last run was > 24h ago, run immediately
68
- const lastRunTs = state.lastRunAt ? new Date(state.lastRunAt).getTime() : 0;
69
- const elapsed = Date.now() - lastRunTs;
70
- if (elapsed > GC_INTERVAL_MS) {
71
- try {
72
- await runGC({ cleoDir });
73
- }
74
- catch {
75
- // Immediate GC failure is non-fatal; cron will retry next cycle
76
- }
77
- }
78
- // Step 3: Schedule future runs via node-cron
79
- // noOverlap: true prevents double-runs if a previous run exceeds 24h
80
- cron.schedule(GC_CRON_EXPR, async () => {
81
- try {
82
- await runGC({ cleoDir });
83
- }
84
- catch {
85
- // Log failures via stderr (already redirected to gc.log by spawn)
86
- const state2 = await readGCState(statePath);
87
- await patchGCState(statePath, {
88
- consecutiveFailures: state2.consecutiveFailures + 1,
89
- lastRunResult: 'failed',
90
- escalationNeeded: state2.consecutiveFailures + 1 >= 3,
91
- escalationReason: state2.consecutiveFailures + 1 >= 3
92
- ? `GC daemon: ${state2.consecutiveFailures + 1} consecutive failures. Check logs.`
93
- : state2.escalationReason,
94
- });
95
- }
96
- }, {
97
- timezone: 'UTC',
98
- noOverlap: true,
99
- name: 'cleo-gc',
100
- });
52
+ const subsystem = createGcSubsystem(cleoDir);
53
+ // start() handles crash recovery, missed-run recovery, and cron scheduling.
54
+ // The returned context (cron task handle) keeps the cron alive for the
55
+ // lifetime of this process — we intentionally do not call shutdown() so the
56
+ // daemon continues running until the process receives SIGTERM.
57
+ await subsystem.start();
101
58
  }
102
59
  // ---------------------------------------------------------------------------
103
60
  // Spawn Helpers (called by `cleo daemon start` in the parent CLI process)
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/gc/daemon.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/gc/daemon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * GC daemon expressed as a supervised daemon subsystem.
3
+ *
4
+ * Wraps the GC bootstrap logic (`bootstrapDaemon`, crash recovery, missed-run
5
+ * recovery, and the node-cron schedule) in the uniform
6
+ * `start → healthProbe → shutdown` lifecycle from `@cleocode/contracts/daemon`
7
+ * so the `@cleocode/runtime` `SubsystemRegistry` can drive it identically to
8
+ * every other long-running concern (Studio supervision, the web server, …).
9
+ *
10
+ * Design constraints
11
+ * ------------------
12
+ * `@cleocode/core` CANNOT depend on `@cleocode/runtime` (runtime already
13
+ * depends on core). To remain dependency-cycle free this module imports only
14
+ * the pure type contracts from `@cleocode/contracts` and returns a plain
15
+ * frozen object that satisfies the `Subsystem<GcSubsystemContext>` interface
16
+ * without calling `defineSubsystem()` (a runtime-layer factory). A caller that
17
+ * holds a `SubsystemRegistry` (from `@cleocode/runtime/daemon`) simply calls
18
+ * `registry.register(createGcSubsystem(cleoDir))` — the frozen shape is
19
+ * identical to what `defineSubsystem` returns and the registry types accept it.
20
+ *
21
+ * Thread-through context
22
+ * ----------------------
23
+ * `start()` returns a {@link GcSubsystemContext} that is threaded into
24
+ * `shutdown()` by the registry (same pattern as `GatewaySubsystemContext`
25
+ * in `@cleocode/runtime/gateway`). This lets `shutdown()` cancel the exact
26
+ * cron task that `start()` scheduled without requiring module-level mutable
27
+ * state.
28
+ *
29
+ * @see packages/core/src/gc/daemon.ts — standalone bootstrap / spawn helpers
30
+ * @see packages/runtime/src/daemon/define-subsystem.ts — `defineSubsystem` factory
31
+ * @see packages/runtime/src/gateway/daemon-subsystem.ts — reference implementation
32
+ *
33
+ * @packageDocumentation
34
+ * @module @cleocode/core/gc
35
+ *
36
+ * @task T11503 (R5-T1)
37
+ * @task T11504 (R5-T2)
38
+ * @epic T11256
39
+ * @saga T11243 SG-RUNTIME-UNIFICATION
40
+ */
41
+ import type { Subsystem } from '@cleocode/contracts';
42
+ /**
43
+ * The live context `start()` returns and the registry threads into
44
+ * `shutdown()`. Carries the scheduled cron task so `shutdown()` can destroy
45
+ * exactly the task that `start()` created.
46
+ */
47
+ export interface GcSubsystemContext {
48
+ /** The OS pid of this daemon process (set at subsystem start). */
49
+ readonly pid: number;
50
+ /** The ISO-8601 timestamp when this subsystem started. */
51
+ readonly startedAt: string;
52
+ /**
53
+ * The scheduled cron task. `ScheduledTask` is the node-cron return value.
54
+ * Typed as the minimal destroy surface so callers do not need to import
55
+ * node-cron types.
56
+ */
57
+ readonly cronTask: {
58
+ destroy: () => void;
59
+ };
60
+ /** Count of GC runs performed since subsystem start. */
61
+ runs: number;
62
+ }
63
+ /**
64
+ * Create a GC cron-daemon expressed as a uniform daemon subsystem.
65
+ *
66
+ * The returned object is a frozen `Subsystem<GcSubsystemContext>` that any
67
+ * `SubsystemRegistry` (from `@cleocode/runtime/daemon`) can `register()`.
68
+ *
69
+ * Lifecycle
70
+ * ---------
71
+ * - `start(cleoDir)` — reads gc-state.json, performs crash recovery
72
+ * (resumes `pendingPrune` if non-empty), performs missed-run recovery (runs
73
+ * GC immediately if elapsed > 24 h), then schedules the daily cron job.
74
+ * Returns a {@link GcSubsystemContext} for health-probe and shutdown.
75
+ * - `healthProbe()` — reports a single {@link SubsystemHealth} row keyed on
76
+ * `child_id: 'gc'`; `running` while the cron task is active, with a `detail`
77
+ * summarising run count and last-run timestamp.
78
+ * - `shutdown(context)` — destroys the cron task so the daemon process can
79
+ * exit cleanly.
80
+ *
81
+ * @param cleoDir - Absolute path to the `.cleo/` directory for this project.
82
+ * @returns A frozen `Subsystem<GcSubsystemContext>`.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * // In the daemon process:
87
+ * import { SubsystemRegistry } from '@cleocode/runtime/daemon';
88
+ * import { createGcSubsystem } from '@cleocode/core/gc/gc-subsystem.js';
89
+ *
90
+ * const registry = new SubsystemRegistry();
91
+ * registry.register(createGcSubsystem('/home/user/.local/share/cleo/project/abc/.cleo'));
92
+ * await registry.startAll();
93
+ * ```
94
+ */
95
+ export declare function createGcSubsystem(cleoDir: string): Subsystem<GcSubsystemContext>;
96
+ //# sourceMappingURL=gc-subsystem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gc-subsystem.d.ts","sourceRoot":"","sources":["../../src/gc/gc-subsystem.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAmC,MAAM,qBAAqB,CAAC;AAmBtF;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAC3C,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;CACd;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC,kBAAkB,CAAC,CA+GhF"}
@@ -0,0 +1,186 @@
1
+ /**
2
+ * GC daemon expressed as a supervised daemon subsystem.
3
+ *
4
+ * Wraps the GC bootstrap logic (`bootstrapDaemon`, crash recovery, missed-run
5
+ * recovery, and the node-cron schedule) in the uniform
6
+ * `start → healthProbe → shutdown` lifecycle from `@cleocode/contracts/daemon`
7
+ * so the `@cleocode/runtime` `SubsystemRegistry` can drive it identically to
8
+ * every other long-running concern (Studio supervision, the web server, …).
9
+ *
10
+ * Design constraints
11
+ * ------------------
12
+ * `@cleocode/core` CANNOT depend on `@cleocode/runtime` (runtime already
13
+ * depends on core). To remain dependency-cycle free this module imports only
14
+ * the pure type contracts from `@cleocode/contracts` and returns a plain
15
+ * frozen object that satisfies the `Subsystem<GcSubsystemContext>` interface
16
+ * without calling `defineSubsystem()` (a runtime-layer factory). A caller that
17
+ * holds a `SubsystemRegistry` (from `@cleocode/runtime/daemon`) simply calls
18
+ * `registry.register(createGcSubsystem(cleoDir))` — the frozen shape is
19
+ * identical to what `defineSubsystem` returns and the registry types accept it.
20
+ *
21
+ * Thread-through context
22
+ * ----------------------
23
+ * `start()` returns a {@link GcSubsystemContext} that is threaded into
24
+ * `shutdown()` by the registry (same pattern as `GatewaySubsystemContext`
25
+ * in `@cleocode/runtime/gateway`). This lets `shutdown()` cancel the exact
26
+ * cron task that `start()` scheduled without requiring module-level mutable
27
+ * state.
28
+ *
29
+ * @see packages/core/src/gc/daemon.ts — standalone bootstrap / spawn helpers
30
+ * @see packages/runtime/src/daemon/define-subsystem.ts — `defineSubsystem` factory
31
+ * @see packages/runtime/src/gateway/daemon-subsystem.ts — reference implementation
32
+ *
33
+ * @packageDocumentation
34
+ * @module @cleocode/core/gc
35
+ *
36
+ * @task T11503 (R5-T1)
37
+ * @task T11504 (R5-T2)
38
+ * @epic T11256
39
+ * @saga T11243 SG-RUNTIME-UNIFICATION
40
+ */
41
+ import { join } from 'node:path';
42
+ import cron from 'node-cron';
43
+ import { runGC } from './runner.js';
44
+ import { patchGCState, readGCState } from './state.js';
45
+ // ---------------------------------------------------------------------------
46
+ // Constants (mirrors daemon.ts — single authority is retained in daemon.ts)
47
+ // ---------------------------------------------------------------------------
48
+ /** Cron expression: daily at 03:00 UTC. Kept in sync with daemon.ts. */
49
+ const GC_CRON_EXPR = '0 3 * * *';
50
+ /** Interval for missed-run recovery check (24 hours in ms). */
51
+ const GC_INTERVAL_MS = 24 * 60 * 60 * 1000;
52
+ // ---------------------------------------------------------------------------
53
+ // Factory
54
+ // ---------------------------------------------------------------------------
55
+ /**
56
+ * Create a GC cron-daemon expressed as a uniform daemon subsystem.
57
+ *
58
+ * The returned object is a frozen `Subsystem<GcSubsystemContext>` that any
59
+ * `SubsystemRegistry` (from `@cleocode/runtime/daemon`) can `register()`.
60
+ *
61
+ * Lifecycle
62
+ * ---------
63
+ * - `start(cleoDir)` — reads gc-state.json, performs crash recovery
64
+ * (resumes `pendingPrune` if non-empty), performs missed-run recovery (runs
65
+ * GC immediately if elapsed > 24 h), then schedules the daily cron job.
66
+ * Returns a {@link GcSubsystemContext} for health-probe and shutdown.
67
+ * - `healthProbe()` — reports a single {@link SubsystemHealth} row keyed on
68
+ * `child_id: 'gc'`; `running` while the cron task is active, with a `detail`
69
+ * summarising run count and last-run timestamp.
70
+ * - `shutdown(context)` — destroys the cron task so the daemon process can
71
+ * exit cleanly.
72
+ *
73
+ * @param cleoDir - Absolute path to the `.cleo/` directory for this project.
74
+ * @returns A frozen `Subsystem<GcSubsystemContext>`.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * // In the daemon process:
79
+ * import { SubsystemRegistry } from '@cleocode/runtime/daemon';
80
+ * import { createGcSubsystem } from '@cleocode/core/gc/gc-subsystem.js';
81
+ *
82
+ * const registry = new SubsystemRegistry();
83
+ * registry.register(createGcSubsystem('/home/user/.local/share/cleo/project/abc/.cleo'));
84
+ * await registry.startAll();
85
+ * ```
86
+ */
87
+ export function createGcSubsystem(cleoDir) {
88
+ const statePath = join(cleoDir, 'gc-state.json');
89
+ // Closure-held live context so `healthProbe()` (which receives no arguments
90
+ // per the Subsystem contract) can read the current state.
91
+ let live;
92
+ const subsystem = {
93
+ name: 'gc',
94
+ async start() {
95
+ // Register daemon PID in state file
96
+ await patchGCState(statePath, {
97
+ daemonPid: process.pid,
98
+ daemonStartedAt: new Date().toISOString(),
99
+ });
100
+ const state = await readGCState(statePath);
101
+ let runs = 0;
102
+ // Step 1: Crash recovery — resume pending prune from prior run
103
+ if (state.pendingPrune && state.pendingPrune.length > 0) {
104
+ try {
105
+ await runGC({ cleoDir, resumeFrom: state.pendingPrune });
106
+ runs += 1;
107
+ }
108
+ catch {
109
+ // Crash-recovery failure is non-fatal; continue with scheduled runs
110
+ }
111
+ }
112
+ // Step 2: Missed-run recovery — if last run was > 24 h ago, run immediately
113
+ const lastRunTs = state.lastRunAt ? new Date(state.lastRunAt).getTime() : 0;
114
+ const elapsed = Date.now() - lastRunTs;
115
+ if (elapsed > GC_INTERVAL_MS) {
116
+ try {
117
+ await runGC({ cleoDir });
118
+ runs += 1;
119
+ }
120
+ catch {
121
+ // Immediate GC failure is non-fatal; cron will retry next cycle
122
+ }
123
+ }
124
+ // Step 3: Schedule future runs via node-cron
125
+ // noOverlap: true prevents double-runs if a previous run exceeds 24 h
126
+ const cronTask = cron.schedule(GC_CRON_EXPR, async () => {
127
+ try {
128
+ await runGC({ cleoDir });
129
+ if (live !== undefined) {
130
+ live.runs += 1;
131
+ }
132
+ }
133
+ catch {
134
+ // Log failures via stderr (redirected to gc.log by spawn)
135
+ const currentState = await readGCState(statePath);
136
+ await patchGCState(statePath, {
137
+ consecutiveFailures: currentState.consecutiveFailures + 1,
138
+ lastRunResult: 'failed',
139
+ escalationNeeded: currentState.consecutiveFailures + 1 >= 3,
140
+ escalationReason: currentState.consecutiveFailures + 1 >= 3
141
+ ? `GC daemon: ${currentState.consecutiveFailures + 1} consecutive failures. Check logs.`
142
+ : currentState.escalationReason,
143
+ });
144
+ }
145
+ }, {
146
+ timezone: 'UTC',
147
+ noOverlap: true,
148
+ name: 'cleo-gc',
149
+ });
150
+ const context = {
151
+ pid: process.pid,
152
+ startedAt: new Date().toISOString(),
153
+ cronTask,
154
+ runs,
155
+ };
156
+ live = context;
157
+ return context;
158
+ },
159
+ healthProbe() {
160
+ if (live === undefined) {
161
+ const stopped = 'stopped';
162
+ return {
163
+ child_id: 'gc',
164
+ pid: 0,
165
+ state: stopped,
166
+ restart_count: 0,
167
+ detail: 'gc subsystem not started',
168
+ };
169
+ }
170
+ const running = 'running';
171
+ return {
172
+ child_id: 'gc',
173
+ pid: live.pid,
174
+ state: running,
175
+ restart_count: live.runs,
176
+ detail: `runs=${live.runs} startedAt=${live.startedAt}`,
177
+ };
178
+ },
179
+ shutdown(context) {
180
+ context.cronTask.destroy();
181
+ live = undefined;
182
+ },
183
+ };
184
+ return Object.freeze(subsystem);
185
+ }
186
+ //# sourceMappingURL=gc-subsystem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gc-subsystem.js","sourceRoot":"","sources":["../../src/gc/gc-subsystem.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@
9
9
  */
10
10
  export { auditOrphanTempDirs, auditOrphanWorktrees, } from '../validation/doctor/checks.js';
11
11
  export * from './daemon.js';
12
+ export * from './gc-subsystem.js';
12
13
  export * from './runner.js';
13
14
  export * from './state.js';
14
15
  export * from './transcript.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gc/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,gCAAgC,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gc/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,gCAAgC,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
package/dist/gc/index.js CHANGED
@@ -11,6 +11,7 @@
11
11
  // Read-only audit counterparts to pruneOrphanWorktrees / pruneOrphanTempDirs.
12
12
  export { auditOrphanTempDirs, auditOrphanWorktrees, } from '../validation/doctor/checks.js';
13
13
  export * from './daemon.js';
14
+ export * from './gc-subsystem.js';
14
15
  export * from './runner.js';
15
16
  export * from './state.js';
16
17
  export * from './transcript.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gc/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,yFAAyF;AACzF,8EAA8E;AAC9E,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,gCAAgC,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gc/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,yFAAyF;AACzF,8EAA8E;AAC9E,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,gCAAgC,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}