freeharness 0.4.1 → 0.4.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 (194) hide show
  1. package/README.md +8 -7
  2. package/canonical/HARVEST.yaml +25 -14
  3. package/canonical/PROVENANCE.yaml +1 -1
  4. package/canonical/agents/README.md +77 -36
  5. package/canonical/agents/agentic-architect.md +2 -1
  6. package/canonical/agents/database-reviewer.md +6 -8
  7. package/canonical/agents/explorer-ai-engineer-analyst.md +2 -6
  8. package/canonical/agents/implementer.md +30 -0
  9. package/canonical/agents/pr-reviewer.md +9 -11
  10. package/canonical/agents/python-reviewer.md +7 -9
  11. package/canonical/agents/report-formatter.md +7 -3
  12. package/canonical/agents/security-reviewer.md +7 -8
  13. package/canonical/agents/test-writer.md +5 -2
  14. package/canonical/hooks/cost-prices.json +11 -9
  15. package/canonical/hooks/freeharness-config-guard.mjs +8072 -87
  16. package/canonical/hooks/freeharness-context-monitor.mjs +88 -54
  17. package/canonical/hooks/freeharness-converge.mjs +78 -23
  18. package/canonical/hooks/freeharness-cost-tracker.mjs +1129 -218
  19. package/canonical/hooks/freeharness-memory-guard.mjs +20 -23
  20. package/canonical/hooks/freeharness-precompact.mjs +217 -87
  21. package/canonical/hooks/freeharness-quota-tap.mjs +173 -0
  22. package/canonical/hooks/freeharness-reload-context.mjs +197 -0
  23. package/canonical/hooks/freeharness-repeat-tool.mjs +1 -1
  24. package/canonical/hooks/freeharness-sdd-context.mjs +970 -0
  25. package/canonical/hooks/freeharness-session-start +297 -59
  26. package/canonical/hooks/hooks.claude-code.json +1 -1
  27. package/canonical/hooks/hooks.config-guard.claude-code.json +3 -2
  28. package/canonical/hooks/hooks.context-monitor.claude-code.json +1 -1
  29. package/canonical/hooks/hooks.converge.claude-code.json +1 -1
  30. package/canonical/hooks/hooks.memory-guard.claude-code.json +3 -2
  31. package/canonical/hooks/hooks.reload-context.claude-code.json +15 -0
  32. package/canonical/openspec/schema.spec-driven.yaml +29 -8
  33. package/canonical/openspec/templates/follow-ups.md +3 -2
  34. package/canonical/openspec/templates/proposal.md +1 -1
  35. package/canonical/openspec/templates/tasks.md +8 -0
  36. package/canonical/rules/CLAUDE.md +5 -4
  37. package/canonical/rules/routing.md +10 -9
  38. package/canonical/skills/agent-evaluation/SKILL.md +17 -6
  39. package/canonical/skills/agent-evaluation/evals/cases.yaml +38 -23
  40. package/canonical/skills/agentic-architecture/SKILL.md +4 -0
  41. package/canonical/skills/agentic-architecture/evals/cases.yaml +27 -0
  42. package/canonical/skills/code-review/SKILL.md +9 -2
  43. package/canonical/skills/code-review/evals/cases.yaml +1118 -27
  44. package/canonical/skills/git-workflow/SKILL.md +2 -0
  45. package/canonical/skills/local-code/SKILL.md +2 -2
  46. package/canonical/skills/local-code/evals/cases.yaml +1 -1
  47. package/canonical/skills/report-formatting/SKILL.md +10 -2
  48. package/canonical/skills/report-formatting/reference/ARCHITECTURE.md +3 -3
  49. package/canonical/skills/report-formatting/reference/HELPERS.md +10 -5
  50. package/canonical/skills/report-formatting/reference/RELEASE.md +1 -2
  51. package/canonical/skills/report-formatting/reference/TEMPLATES.md +3 -2
  52. package/canonical/skills/report-formatting/reference/authoring.md +25 -37
  53. package/canonical/skills/report-formatting/scripts/build-architecture.js +1 -1
  54. package/canonical/skills/report-formatting/scripts/build-md-claro.js +5 -8
  55. package/canonical/skills/report-formatting/scripts/check-env.js +0 -4
  56. package/canonical/skills/report-formatting/scripts/docmodel.js +3 -11
  57. package/canonical/skills/report-formatting/scripts/example-build.js +8 -10
  58. package/canonical/skills/report-formatting/scripts/example_build_ArchitectureReview_docx.js +8 -10
  59. package/canonical/skills/report-formatting/scripts/example_build_ExecutiveReport_docx.js +8 -10
  60. package/canonical/skills/report-formatting/scripts/theme-claro.js +39 -10
  61. package/canonical/skills/subagent-driven-development/SKILL.md +35 -28
  62. package/canonical/skills/subagent-driven-development/evals/cases.yaml +3496 -19
  63. package/canonical/skills/subagent-driven-development/reference/brief.md +185 -35
  64. package/canonical/skills/subagent-driven-development/reference/handoff.md +82 -2
  65. package/canonical/skills/subagent-driven-development/reference/loop.md +57 -0
  66. package/canonical/skills/subagent-driven-development/reference/trees.md +40 -0
  67. package/canonical/skills/subagent-driven-development/reference/workspace.md +31 -0
  68. package/canonical/skills/subagent-driven-development/scripts/validate-handoff.mjs +4771 -326
  69. package/dist/adapters/harness/claude-code.d.ts +19 -3
  70. package/dist/adapters/harness/claude-code.js +204 -39
  71. package/dist/adapters/harness/opencode.js +16 -2
  72. package/dist/adapters/harness/plugin.js +28 -17
  73. package/dist/adapters/memory/doctor.d.ts +174 -29
  74. package/dist/adapters/memory/doctor.js +758 -134
  75. package/dist/adapters/memory/migrate.d.ts +95 -0
  76. package/dist/adapters/memory/migrate.js +497 -0
  77. package/dist/adapters/memory/paths.d.ts +22 -0
  78. package/dist/adapters/memory/paths.js +85 -0
  79. package/dist/adapters/memory/vendored.d.ts +56 -29
  80. package/dist/adapters/memory/vendored.js +191 -154
  81. package/dist/adapters/sync/diff.js +4 -1
  82. package/dist/cli/cleanup-prompt.d.ts +35 -0
  83. package/dist/cli/cleanup-prompt.js +68 -0
  84. package/dist/cli/cleanup.d.ts +22 -24
  85. package/dist/cli/cleanup.js +182 -68
  86. package/dist/cli/cost-quota.d.ts +158 -0
  87. package/dist/cli/cost-quota.js +645 -0
  88. package/dist/cli/cost.d.ts +408 -46
  89. package/dist/cli/cost.js +1731 -57
  90. package/dist/cli/doctor.d.ts +52 -13
  91. package/dist/cli/doctor.js +193 -44
  92. package/dist/cli/hard-cleanup.d.ts +93 -0
  93. package/dist/cli/hard-cleanup.js +552 -0
  94. package/dist/cli/install-facts.d.ts +28 -0
  95. package/dist/cli/install-facts.js +66 -0
  96. package/dist/cli/json-key-edit.d.ts +18 -0
  97. package/dist/cli/json-key-edit.js +118 -0
  98. package/dist/cli/memory-import.d.ts +74 -0
  99. package/dist/cli/memory-import.js +469 -0
  100. package/dist/cli/plugin-validate.d.ts +12 -0
  101. package/dist/cli/plugin-validate.js +43 -0
  102. package/dist/cli/uninstall.d.ts +1 -1
  103. package/dist/cli/uninstall.js +2 -2
  104. package/dist/cli/upstream-launchers.d.ts +49 -0
  105. package/dist/cli/upstream-launchers.js +287 -0
  106. package/dist/index.js +247 -70
  107. package/dist/infra/fsutil.d.ts +31 -3
  108. package/dist/infra/fsutil.js +69 -6
  109. package/dist/infra/manifest.d.ts +2 -1
  110. package/dist/infra/manifest.js +3 -2
  111. package/dist/infra/prices.d.ts +18 -0
  112. package/dist/infra/prices.js +64 -0
  113. package/node_modules/@freeharness/core/dist/tiers.d.ts +10 -1
  114. package/node_modules/@freeharness/core/dist/tiers.js +24 -2
  115. package/node_modules/@freeharness/core/package.json +1 -1
  116. package/node_modules/@freeharness/sdd/PROVENANCE.yaml +279 -2
  117. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.js +34 -8
  118. package/node_modules/@freeharness/sdd/dist/src/shim/archive.d.ts +7 -6
  119. package/node_modules/@freeharness/sdd/dist/src/shim/archive.js +72 -64
  120. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.d.ts +48 -16
  121. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.js +168 -70
  122. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.d.ts +36 -6
  123. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.js +110 -49
  124. package/node_modules/@freeharness/sdd/dist/src/shim/list.d.ts +1 -1
  125. package/node_modules/@freeharness/sdd/dist/src/shim/list.js +57 -14
  126. package/node_modules/@freeharness/sdd/dist/src/shim/nested-change.d.ts +7 -0
  127. package/node_modules/@freeharness/sdd/dist/src/shim/nested-change.js +118 -0
  128. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.js +3 -1
  129. package/node_modules/@freeharness/sdd/dist/src/shim/proposal-capabilities.d.ts +12 -0
  130. package/node_modules/@freeharness/sdd/dist/src/shim/proposal-capabilities.js +94 -0
  131. package/node_modules/@freeharness/sdd/dist/src/shim/shared.d.ts +17 -0
  132. package/node_modules/@freeharness/sdd/dist/src/shim/shared.js +182 -1
  133. package/node_modules/@freeharness/sdd/dist/src/shim/status.d.ts +2 -2
  134. package/node_modules/@freeharness/sdd/dist/src/shim/status.js +34 -5
  135. package/node_modules/@freeharness/sdd/dist/src/shim/validate.d.ts +9 -0
  136. package/node_modules/@freeharness/sdd/dist/src/shim/validate.js +49 -41
  137. package/node_modules/@freeharness/sdd/dist/src/shim/warnings.d.ts +21 -0
  138. package/node_modules/@freeharness/sdd/dist/src/shim/warnings.js +66 -0
  139. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/line-endings.d.ts +4 -0
  140. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/line-endings.js +17 -0
  141. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.js +95 -22
  142. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.d.ts +6 -0
  143. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.js +14 -6
  144. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.d.ts +1 -1
  145. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.js +1 -1
  146. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.d.ts +3 -3
  147. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.js +24 -4
  148. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.js +4 -7
  149. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.js +13 -1
  150. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.js +21 -6
  151. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.js +80 -19
  152. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.js +42 -22
  153. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/project-root.d.ts +32 -0
  154. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/project-root.js +39 -0
  155. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.js +16 -9
  156. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.js +36 -1
  157. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.js +65 -30
  158. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.d.ts +1 -1
  159. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.js +1 -1
  160. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.d.ts +8 -13
  161. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.js +79 -102
  162. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.js +4 -9
  163. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.d.ts +50 -10
  164. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.js +165 -37
  165. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.d.ts +24 -3
  166. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.js +55 -8
  167. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.js +4 -1
  168. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.js +19 -9
  169. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.d.ts +10 -0
  170. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.js +115 -0
  171. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.d.ts +3 -3
  172. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.js +20 -20
  173. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.d.ts +6 -0
  174. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.js +75 -14
  175. package/node_modules/@freeharness/sdd/package.json +1 -1
  176. package/node_modules/@freeharness/sdd/vendor/openspec/assets/schema.upstream.yaml +47 -7
  177. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-apply-change/SKILL.md +25 -7
  178. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-archive-change/SKILL.md +50 -11
  179. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-bulk-archive-change/SKILL.md +48 -10
  180. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-continue-change/SKILL.md +27 -7
  181. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-explore/SKILL.md +25 -12
  182. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-ff-change/SKILL.md +17 -5
  183. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-new-change/SKILL.md +12 -1
  184. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-onboard/SKILL.md +47 -33
  185. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-propose/SKILL.md +17 -5
  186. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-sync-specs/SKILL.md +29 -1
  187. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-update-change/SKILL.md +31 -13
  188. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-verify-change/SKILL.md +75 -27
  189. package/package.json +6 -4
  190. package/provenance/canonical.PROVENANCE.yaml +1 -1
  191. package/provenance/memory.PROVENANCE.yaml +458 -6
  192. package/provenance/sdd.PROVENANCE.yaml +279 -2
  193. package/canonical/hooks/freeharness-auto-memory.mjs +0 -158
  194. package/canonical/hooks/hooks.auto-memory.claude-code.json +0 -16
@@ -1,4 +1,7 @@
1
1
  import { spawnSync } from "node:child_process";
2
+ import { type StageResult } from "./vendored.js";
3
+ import { type MemoryPaths } from "./paths.js";
4
+ import { type StopResult } from "./migrate.js";
2
5
  export interface CacheVersion {
3
6
  version: string;
4
7
  dir: string;
@@ -8,15 +11,49 @@ export interface CacheVersion {
8
11
  * build (pre-rename) or a genuine upstream install, never our current native path. */
9
12
  legacy: boolean;
10
13
  }
14
+ /** What the foreign responder said about itself, already filtered for printing. */
15
+ export interface WorkerFacts {
16
+ pid?: number;
17
+ workerPath: string;
18
+ version: string;
19
+ }
11
20
  export interface WorkerProbe {
12
21
  port: number;
13
22
  reachable: boolean;
14
23
  version?: string;
15
- viewer?: boolean;
24
+ /** Set when reachable: the engine's rule applied to the /api/health answer and the free-mem PID file. */
25
+ identity?: "ours" | "ours-stale" | "foreign";
26
+ /** Set when reachable: `identity !== "foreign"`. */
16
27
  ours?: boolean;
28
+ foreign?: WorkerFacts;
29
+ /** Absent when the worker predates the parked field of /api/health. */
30
+ parked?: ParkedHealth;
31
+ /** Absent when the worker predates the embeddings field of /api/health. */
32
+ embeddings?: EmbeddingsHealth;
33
+ }
34
+ /** The `embeddings` field of /api/health: the vector stream of the configured model. */
35
+ export interface EmbeddingsHealth {
36
+ state: "off" | "ready" | "backfilling" | "degraded" | "unreachable";
37
+ reason: "unset" | "refused" | null;
38
+ /** Null while off: none configured, so no model or floor is shown. */
39
+ model: string | null;
40
+ maxDistance: number;
41
+ embedded: number;
42
+ failed: number;
43
+ total: number;
44
+ lastErrorClass: string | null;
45
+ otherModels: {
46
+ model: string;
47
+ count: number;
48
+ }[];
49
+ }
50
+ /** The `parked` field of /api/health: quota-paused sessions whose buffer holds work, in worker memory only. */
51
+ export interface ParkedHealth {
52
+ count: number;
53
+ oldestAgeMs: number | null;
17
54
  }
18
- /** Marker in the FreeHarness viewer page served on GET / (plugin/ui/viewer.html). */
19
- export declare const VIEWER_MARKER = "FreeHarness memory";
55
+ /** The /api/health product marker of our worker; a test pins it to the engine's and the hooks' copies. */
56
+ export declare const FREE_MEM_PRODUCT = "free-mem";
20
57
  /** Mirror of engine shared/observer-health.ts: warn only after this many consecutive failures. */
21
58
  export declare const OBSERVER_UNHEALTHY_FAILURE_THRESHOLD = 3;
22
59
  /** Mirror of engine shared/quota-cooldown.ts: how long requests are withheld after a quota refusal. */
@@ -111,6 +148,18 @@ export declare function isObserverVerdictStale(ledger: ObserverHealth | null, no
111
148
  export declare function observerLines(s: ObserverStatus, now?: number): string[];
112
149
  /** Highest schema_versions row our vendored SessionStore applies (13.24.0 port; the upstream v50 observed_model/observed_billing migration is telemetry-only and not ported). */
113
150
  export declare const OUR_SCHEMA_VERSION = 49;
151
+ /**
152
+ * Build the schema status line. Upstream and FreeHarness versions are split at 9000 so a
153
+ * FreeHarness migration is never reported as a newer upstream engine. A store that records
154
+ * some FreeHarness versions but not all of them has not finished migrating (a migration
155
+ * rolled back, or the worker predates the update), so the line warns and names each missing
156
+ * version; a store with none has never been opened
157
+ * by a FreeHarness worker and keeps the upstream verdict.
158
+ *
159
+ * Returns:
160
+ * The line, or null when the db/sqlite3 is unavailable.
161
+ */
162
+ export declare function schemaVersionLine(dbPath: string, dbName: string): string | null;
114
163
  /** One (window, model) group from the `observations` table. */
115
164
  export interface SpendRow {
116
165
  window: "today" | "seven_day";
@@ -133,7 +182,9 @@ export interface SpendUnavailable {
133
182
  /**
134
183
  * Reads observer spend (observation count and summed `discovery_tokens`) grouped by day
135
184
  * window and `generated_by_model`, through `sqlite3 -readonly` (same invocation shape as
136
- * `dbSchemaVersion`). The seven-day window includes today, matching the running total an
185
+ * `dbSchemaVersions`), plus each model's `consolidation_calls` tokens: consolidation
186
+ * observations carry `discovery_tokens` 0, and the cost-tracker hook's `observerSink` counts
187
+ * the same rows. The seven-day window includes today, matching the running total an
137
188
  * owner reads off `memory status` (not "the other six days").
138
189
  *
139
190
  * Args:
@@ -145,6 +196,16 @@ export interface SpendUnavailable {
145
196
  * One row per (window, model) with a row, or the reason spend could not be read.
146
197
  */
147
198
  export declare function observerSpend(dbPath: string, spawn?: SpawnSyncFn): SpendRow[] | SpendUnavailable;
199
+ /**
200
+ * The capture pipeline and retrieval health as INFO lines: spool backlog and drops,
201
+ * consolidation jobs by status, the rules tier's share of the last 7 days' observations, the
202
+ * search streams, the last gc run, the feedback counts and the parked batches the worker
203
+ * reports. Anything unreadable prints `n/a` rather than failing the report.
204
+ *
205
+ * Args:
206
+ * worker: The /api/health probe; omitted, the worker counts as not answering.
207
+ */
208
+ export declare function pipelineLines(dataDir: string, dbPath: string, spawn?: SpawnSyncFn, worker?: Pick<WorkerProbe, "reachable" | "parked" | "embeddings">): string[];
148
209
  /**
149
210
  * Model ids that name metered Claude spend: the `claude-*` families, a bare tier alias
150
211
  * (`haiku`, `sonnet`, `opus`, alone or with a `-` suffix) and the `$TIER:` placeholder the
@@ -194,6 +255,10 @@ export interface LocalProviderLogSummary {
194
255
  skippedLines: number;
195
256
  /** True when the file exceeded the read cap and only its tail was scanned (see `readLocalProviderLog`'s `maxBytes`). */
196
257
  truncated: boolean;
258
+ /** Batches marked `degraded: true` today, keyed by `tier`; empty when Claude never paused today. */
259
+ degraded: Record<string, number>;
260
+ /** `paused_window` values seen on today's degraded batches, keyed by window name. */
261
+ pausedWindows: Record<string, number>;
197
262
  }
198
263
  /** A present but unreadable batch log (permissions, I/O), distinct from one that does not exist. */
199
264
  export interface LocalProviderLogUnavailable {
@@ -215,7 +280,7 @@ export interface LocalProviderLogUnavailable {
215
280
  *
216
281
  * Returns:
217
282
  * The day's batch/fallback counts and whether the read was truncated; null when the log file
218
- * does not exist yet (a fresh `CLAUDE_MEM_PROVIDER=claude` machine has never written one);
283
+ * does not exist yet (a fresh `FREE_MEM_PROVIDER=claude` machine has never written one);
219
284
  * the reason when the file is there but could not be read, which is a different state from
220
285
  * an absent log and gets its own printed line.
221
286
  */
@@ -252,10 +317,12 @@ export interface DuplicateStats {
252
317
  export declare function observerDuplicateRate(dbPath: string, spawn?: SpawnSyncFn): DuplicateStats | SpendUnavailable;
253
318
  /**
254
319
  * Renders the local-provider log summary and near-duplicate rate as printable INFO lines: the
255
- * batch/fallback line, then the near-duplicate-rate line (omitted when the rate could not be
256
- * read). Nothing at all when `summary` is null (no `local-provider.jsonl` yet); a single WARN
257
- * naming the reason when the log is present but unreadable, so a permission or I/O failure
258
- * never reads like a machine that has not run the local provider.
320
+ * batch/fallback line, the degraded-day line (present only when today has at least one
321
+ * `degraded: true` batch, naming the tier breakdown and the most frequent `paused_window`),
322
+ * then the near-duplicate-rate line (omitted when the rate could not be read). Nothing at all
323
+ * when `summary` is null (no `local-provider.jsonl` yet); a single WARN naming the reason when
324
+ * the log is present but unreadable, so a permission or I/O failure never reads like a machine
325
+ * that has not run the local provider.
259
326
  *
260
327
  * Args:
261
328
  * summary: `readLocalProviderLog`'s return value.
@@ -288,14 +355,14 @@ export declare function effectiveObserverModels(settingsPath: string): Effective
288
355
  /** Which provider the observer actually runs on, and its model when that provider is local. */
289
356
  export interface ObserverProvider {
290
357
  provider: "claude" | "local";
291
- /** `CLAUDE_MEM_LOCAL_MODEL` (or the engine's `local-model` default) when `provider` is
358
+ /** `FREE_MEM_LOCAL_MODEL` (or the engine's `local-model` default) when `provider` is
292
359
  * `local`; null when `provider` is `claude` (no local model is in play). */
293
360
  model: string | null;
294
361
  }
295
362
  /**
296
- * Effective observer provider: `CLAUDE_MEM_PROVIDER` from settings.json (default `claude`; any
363
+ * Effective observer provider: `FREE_MEM_PROVIDER` from settings.json (default `claude`; any
297
364
  * value other than the literal `local` is treated as `claude`, mirroring the engine's own
298
- * `SettingsDefaultsManager` fallback), and when local, the configured `CLAUDE_MEM_LOCAL_MODEL`
365
+ * `SettingsDefaultsManager` fallback), and when local, the configured `FREE_MEM_LOCAL_MODEL`
299
366
  * or the engine's `local-model` default.
300
367
  *
301
368
  * Args:
@@ -306,16 +373,17 @@ export interface ObserverProvider {
306
373
  */
307
374
  export declare function effectiveObserverProvider(settingsPath: string): ObserverProvider;
308
375
  /**
309
- * The FreeHarness-recommended observer settings: a haiku base and simple tier (the daily-spend
310
- * gate), a sonnet summary tier (session summaries read by every future session, worth the
311
- * larger model), the upstream skip list extended with the tools whose decisions matter for
312
- * recall (Read, Glob, Grep and the multi-agent tools), and a concurrency cap of 2. Shared by
313
- * `memory status`'s WARN check and the `memory settings` command.
376
+ * The FreeHarness-recommended observer settings: Haiku on every tier, because the summary tier
377
+ * alone spent 25.4M Sonnet tokens in a week, and the claude provider, because a local provider
378
+ * running beside it doubled the observer work. The skip list extends the upstream one with
379
+ * the read-only and multi-agent tools, which carry no decision worth recording, and
380
+ * concurrency is capped at 2. Shared by `memory status`'s WARN checks and the `memory
381
+ * settings` command.
314
382
  */
315
383
  export declare const RECOMMENDED_OBSERVER_SETTINGS: Record<string, string>;
316
384
  /**
317
385
  * `memory settings --no-local`: the two keys that return the observer to the Claude provider —
318
- * `CLAUDE_MEM_PROVIDER` and `CLAUDE_MEM_SKIP_TOOLS` restored to the recommended default, so the
386
+ * `FREE_MEM_PROVIDER` and `FREE_MEM_SKIP_TOOLS` restored to the recommended default, so the
319
387
  * skip list follows the provider back.
320
388
  */
321
389
  export declare const NO_LOCAL_OBSERVER_SETTINGS: Record<string, string>;
@@ -342,8 +410,8 @@ export interface ObserverSettingsPreview {
342
410
  /**
343
411
  * Previews `memory settings`: the selected key set against the current file, same or
344
412
  * would-change, writing nothing. Plain (no options): the five recommended keys. `--local`:
345
- * `CLAUDE_MEM_PROVIDER` plus the four `CLAUDE_MEM_LOCAL_*` keys plus the narrowed
346
- * `CLAUDE_MEM_SKIP_TOOLS`. `--no-local`: `CLAUDE_MEM_PROVIDER` and `CLAUDE_MEM_SKIP_TOOLS`
413
+ * `FREE_MEM_PROVIDER` plus the four `FREE_MEM_LOCAL_*` keys plus the narrowed
414
+ * `FREE_MEM_SKIP_TOOLS`. `--no-local`: `FREE_MEM_PROVIDER` and `FREE_MEM_SKIP_TOOLS`
347
415
  * restored to the recommended default.
348
416
  *
349
417
  * Args:
@@ -366,7 +434,8 @@ export interface ApplyObserverSettingsResult {
366
434
  }
367
435
  /**
368
436
  * Applies `memory settings`: adds or updates the selected key set (see `previewObserverSettings`
369
- * for which set), preserving every other key, after backing up an existing file first. Refuses
437
+ * for which set) and drops each written key's `CLAUDE_MEM_` twin, preserving every other key,
438
+ * after backing up an existing file first. Refuses
370
439
  * (throws) without writing anything when `opts` fails validation or the existing file is not
371
440
  * valid JSON.
372
441
  *
@@ -399,8 +468,8 @@ export interface MemoryProviderProbe {
399
468
  * Down is a one-line reason, never a throw.
400
469
  *
401
470
  * Args:
402
- * baseUrl: `CLAUDE_MEM_LOCAL_BASE_URL`.
403
- * model: `CLAUDE_MEM_LOCAL_MODEL`.
471
+ * baseUrl: `FREE_MEM_LOCAL_BASE_URL`.
472
+ * model: `FREE_MEM_LOCAL_MODEL`.
404
473
  * timeoutMs: The whole probe's deadline (both requests together).
405
474
  *
406
475
  * Returns:
@@ -409,7 +478,7 @@ export interface MemoryProviderProbe {
409
478
  export declare function probeMemoryProvider(baseUrl: string, model: string, timeoutMs?: number): Promise<MemoryProviderProbe>;
410
479
  /**
411
480
  * The `memory provider` doctor line: only when the data dir's settings.json sets
412
- * `CLAUDE_MEM_PROVIDER=local`, a probe of the configured base URL and model, OK or WARN with
481
+ * `FREE_MEM_PROVIDER=local`, a probe of the configured base URL and model, OK or WARN with
413
482
  * the reason; absent or `claude` prints nothing.
414
483
  *
415
484
  * Args:
@@ -422,13 +491,30 @@ export declare function probeMemoryProvider(baseUrl: string, model: string, time
422
491
  export declare function memoryProviderLines(settingsPath: string, probe?: (baseUrl: string, model: string, timeoutMs?: number) => Promise<MemoryProviderProbe>): Promise<string[]>;
423
492
  /** Resolve $CLAUDE_CONFIG_DIR or ~/.claude. */
424
493
  export declare function configDir(): string;
425
- /** Mirror engine shared/paths.ts resolveDataDir (env, then settings.json, then default). */
494
+ /** The engine's data directory and database for this process. */
495
+ export declare function memoryPaths(): MemoryPaths;
426
496
  export declare function dataDir(): string;
497
+ /**
498
+ * One WARN per `CLAUDE_MEM_*` variable in `env`, naming its `FREE_MEM_*` replacement, and one
499
+ * WARN for all `CLAUDE_MEM_*` keys in the active settings file: a seeded legacy file holds dozens,
500
+ * and a line per key would bury the rest of the report.
501
+ */
502
+ export declare function deprecatedNameLines(env: Record<string, string | undefined>, settingsPath: string): string[];
503
+ /**
504
+ * A WARN when the legacy database (or its WAL) changed after the migration marker's `at`:
505
+ * a build still on the old name keeps writing memories the new directory never sees.
506
+ */
507
+ export declare function legacyWriteLines(home: string): string[];
508
+ /** Engine worker port: env, then settings.json, then 37700 + uid % 100. */
509
+ export declare function workerPort(dir: string): number;
510
+ /** One WARN while the upstream plugin is still registered: both workers bind the same port. */
511
+ export declare function upstreamLines(cfg: string, port: number): string[];
427
512
  /**
428
513
  * Diagnose which claude-mem is active.
429
514
  *
430
515
  * Returns:
431
- * A MemoryDiagnosis with a verdict and printable lines (OK/WARN prefixed).
516
+ * A MemoryDiagnosis with a verdict and printable lines (OK/WARN/INFO prefixed; FAIL for a
517
+ * foreign worker on the memory port).
432
518
  */
433
519
  export declare function diagnoseMemory(): Promise<MemoryDiagnosis>;
434
520
  /**
@@ -461,20 +547,79 @@ export interface RestartResult {
461
547
  * What was (or would be) done.
462
548
  */
463
549
  export declare function restartWorker(dryRun: boolean, diagnosis?: MemoryDiagnosis): Promise<RestartResult>;
550
+ /**
551
+ * Stops the worker without starting another, then waits until its pid file names no live process
552
+ * and its port is closed.
553
+ * @param mode Only `shutdown`.
554
+ * @param opts Data dir and port (the resolved ones by default) and the wait bound in ms.
555
+ * @returns Whether it stopped, whether one was running, and the reason on timeout.
556
+ */
557
+ export declare function stopWorker(mode: "shutdown", opts?: {
558
+ dir?: string;
559
+ port?: number;
560
+ timeoutMs?: number;
561
+ }): Promise<StopResult>;
562
+ /** Whether a worker answers on the data dir's worker port right now. */
563
+ export declare function workerRunning(): Promise<boolean>;
564
+ /** The engine's log file for a day, where a failed worker start leaves its reason. */
565
+ export declare function workerLogPath(now?: Date): string;
566
+ /** Restart decision after a plugin-cache stage; `error` and `log` never fail the command. */
567
+ export interface StageRestart {
568
+ planned: boolean;
569
+ reason: string;
570
+ result?: RestartResult;
571
+ error?: string;
572
+ log?: string;
573
+ }
574
+ /**
575
+ * Restart a worker that was running before the command when the command staged a different build
576
+ * or stopped that worker itself; a worker that was not running stays stopped. A failed
577
+ * restart, including a launched worker that never answers health or an old worker that never
578
+ * gives way to a new one, is reported, never thrown.
579
+ *
580
+ * Args:
581
+ * wasRunning: Whether a worker answered before the command changed anything.
582
+ * cause: Whether the command staged a build or stopped the worker.
583
+ * dryRun: Report only.
584
+ * healthMs: How long a launched worker has to answer `/api/health`.
585
+ *
586
+ * Returns:
587
+ * The decision and, on apply, its outcome.
588
+ */
589
+ export declare function restartAfterStage(wasRunning: boolean, cause: {
590
+ staged: boolean;
591
+ stopped?: boolean;
592
+ }, dryRun: boolean, healthMs?: number): Promise<StageRestart>;
464
593
  export interface ActivateResult {
465
594
  stoppedWorker: boolean;
466
595
  disabled: string[];
467
596
  registered: boolean;
597
+ stage?: StageResult & {
598
+ cacheDir: string;
599
+ version: string;
600
+ };
601
+ /** The staging notes, or why the cached build is registered as is. */
602
+ stageNotes: string[];
603
+ restart: StageRestart;
468
604
  }
469
605
  /**
470
- * Make the FreeHarness build the only active claude-mem: stop a running worker, move
471
- * foreign cache versions aside (never deleted), point installed_plugins at ours.
606
+ * Make the FreeHarness build the only active claude-mem: stage the vendored build when it is
607
+ * built and differs from the cache, stop a running worker, move foreign cache versions aside
608
+ * (never deleted), point installed_plugins at ours, and restart the worker it stopped.
609
+ * Staging runs first, so a staging failure leaves a running worker up.
472
610
  *
473
611
  * Args:
474
612
  * dryRun: Report only.
613
+ * opts: The vendored plugin dir; without it the newest cached build is registered as is.
475
614
  *
476
615
  * Returns:
477
616
  * What was (or would be) done.
617
+ *
618
+ * Raises:
619
+ * Error: When the cache holds no FreeHarness build, the plugin version is not semver, staging
620
+ * fails, or deps need a missing Bun (refused before any cache write).
478
621
  */
479
- export declare function activateOurs(dryRun: boolean): Promise<ActivateResult>;
622
+ export declare function activateOurs(dryRun: boolean, opts?: {
623
+ pluginDir?: string;
624
+ }): Promise<ActivateResult>;
480
625
  export {};