@fingerskier/augment 0.1.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +20 -2
  2. package/dist/cli.d.ts +6 -0
  3. package/dist/cli.js +43 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/constants.d.ts +6 -0
  6. package/dist/constants.js +46 -6
  7. package/dist/constants.js.map +1 -1
  8. package/dist/daemon/client.d.ts +5 -0
  9. package/dist/daemon/client.js +15 -6
  10. package/dist/daemon/client.js.map +1 -1
  11. package/dist/daemon/http.d.ts +1 -1
  12. package/dist/daemon/http.js +159 -53
  13. package/dist/daemon/http.js.map +1 -1
  14. package/dist/daemon/main.js +15 -1
  15. package/dist/daemon/main.js.map +1 -1
  16. package/dist/daemon/scheduler.d.ts +17 -0
  17. package/dist/daemon/scheduler.js +77 -0
  18. package/dist/daemon/scheduler.js.map +1 -0
  19. package/dist/daemon/single-instance.d.ts +32 -0
  20. package/dist/daemon/single-instance.js +131 -0
  21. package/dist/daemon/single-instance.js.map +1 -0
  22. package/dist/db.d.ts +13 -1
  23. package/dist/db.js +166 -105
  24. package/dist/db.js.map +1 -1
  25. package/dist/embeddings.js +8 -0
  26. package/dist/embeddings.js.map +1 -1
  27. package/dist/hooks.js +28 -3
  28. package/dist/hooks.js.map +1 -1
  29. package/dist/install.d.ts +2 -0
  30. package/dist/install.js +41 -7
  31. package/dist/install.js.map +1 -1
  32. package/dist/mcp/server.js +30 -4
  33. package/dist/mcp/server.js.map +1 -1
  34. package/dist/recall.d.ts +2 -0
  35. package/dist/recall.js +1 -0
  36. package/dist/recall.js.map +1 -1
  37. package/dist/service.d.ts +64 -1
  38. package/dist/service.js +298 -38
  39. package/dist/service.js.map +1 -1
  40. package/dist/sleep.d.ts +43 -0
  41. package/dist/sleep.js +129 -0
  42. package/dist/sleep.js.map +1 -0
  43. package/dist/tally.d.ts +46 -0
  44. package/dist/tally.js +94 -0
  45. package/dist/tally.js.map +1 -0
  46. package/dist/types.d.ts +6 -0
  47. package/dist/util/text.d.ts +3 -0
  48. package/dist/util/text.js +26 -2
  49. package/dist/util/text.js.map +1 -1
  50. package/docs/FEATURES.md +161 -51
  51. package/docs/verify-memory-flow.md +28 -9
  52. package/package.json +2 -1
@@ -1,65 +1,121 @@
1
1
  import { writeFile } from "node:fs/promises";
2
2
  import http from "node:http";
3
+ import path from "node:path";
3
4
  import chokidar from "chokidar";
4
5
  import { EMBEDDING_MODEL_ID } from "../constants.js";
5
6
  import { cytoscapeBundleJs, dashboardAsset } from "../dashboard/assets.js";
7
+ import { ensureConfigDirs } from "../config.js";
8
+ import { appendTallyEvent, appendTallyRating, isTallyVerdict, readTallyRatings, renderTallySummary, summarizeTally, TALLY_VERDICTS, } from "../tally.js";
9
+ import { createIndexScheduler } from "./scheduler.js";
10
+ import { acquireSingleInstance } from "./single-instance.js";
6
11
  export async function startHttpDaemon(config, service) {
7
- await service.init();
8
- const server = http.createServer((request, response) => {
9
- handleRequest(service, request, response).catch((error) => {
10
- sendJson(response, 500, { error: errorMessage(error) });
12
+ // The daemon file and watcher need the state/memory dirs before the (now
13
+ // backgrounded) initial index gets a chance to create them.
14
+ await ensureConfigDirs(config);
15
+ // Single-instance guard: refuse to start if a healthy daemon already owns this
16
+ // state dir, so two daemons never co-open the sqlite index (SQLITE_BUSY). The
17
+ // db handle is lazy, so throwing here means the duplicate never touches it.
18
+ const instanceLock = await acquireSingleInstance(config);
19
+ // Everything past the slot claim runs under one guard: any startup failure
20
+ // (bind error, daemon.json write, watcher wiring) must release the slot and
21
+ // close whatever we opened, or a stranded pidfile would wrongly block the next
22
+ // start (and, once its pid is reused, block it forever).
23
+ let server;
24
+ try {
25
+ // Listen first, index in the background: on a cold corpus the initial index
26
+ // can take minutes of embedding, and clients (hooks especially) must not time
27
+ // out against an unbound port. /index/status reports readiness.
28
+ const indexState = { ready: false };
29
+ const initPromise = service
30
+ .init()
31
+ .then(() => {
32
+ indexState.ready = true;
33
+ })
34
+ .catch((error) => {
35
+ indexState.error = errorMessage(error);
36
+ console.error("augment: initial index failed:", error);
11
37
  });
12
- });
13
- const port = config.daemonPort ?? 0;
14
- await new Promise((resolve, reject) => {
15
- server.once("error", reject);
16
- server.listen(port, "127.0.0.1", () => {
17
- server.off("error", reject);
18
- resolve();
38
+ server = http.createServer((request, response) => {
39
+ handleRequest(service, indexState, config, request, response).catch((error) => {
40
+ sendJson(response, 500, { error: errorMessage(error) });
41
+ });
42
+ });
43
+ const boundServer = server;
44
+ const port = config.daemonPort ?? 0;
45
+ await new Promise((resolve, reject) => {
46
+ boundServer.once("error", reject);
47
+ boundServer.listen(port, "127.0.0.1", () => {
48
+ boundServer.off("error", reject);
49
+ resolve();
50
+ });
19
51
  });
20
- });
21
- const address = server.address();
22
- if (!address || typeof address === "string") {
23
- throw new Error("Failed to determine daemon address");
24
- }
25
- const info = {
26
- pid: process.pid,
27
- endpoint: `http://127.0.0.1:${address.port}`,
28
- memoryRoot: config.memoryRoot,
29
- model: EMBEDDING_MODEL_ID,
30
- startedAt: new Date().toISOString(),
31
- };
32
- await writeFile(config.daemonFile, JSON.stringify(info, null, 2), "utf8");
33
- let rebuildTimer;
34
- const watcher = chokidar.watch(config.memoryRoot, {
35
- ignoreInitial: true,
36
- awaitWriteFinish: { stabilityThreshold: 250, pollInterval: 50 },
37
- });
38
- const scheduleRebuild = () => {
39
- if (rebuildTimer) {
40
- clearTimeout(rebuildTimer);
52
+ const address = boundServer.address();
53
+ if (!address || typeof address === "string") {
54
+ throw new Error("Failed to determine daemon address");
41
55
  }
42
- rebuildTimer = setTimeout(() => {
43
- service.rebuildIndex().catch((error) => console.error("Index rebuild failed:", error));
44
- }, 250);
45
- };
46
- watcher.on("add", scheduleRebuild);
47
- watcher.on("change", scheduleRebuild);
48
- watcher.on("unlink", scheduleRebuild);
49
- return {
50
- info,
51
- async close() {
52
- if (rebuildTimer) {
53
- clearTimeout(rebuildTimer);
56
+ const info = {
57
+ pid: process.pid,
58
+ endpoint: `http://127.0.0.1:${address.port}`,
59
+ memoryRoot: config.memoryRoot,
60
+ model: EMBEDDING_MODEL_ID,
61
+ startedAt: new Date().toISOString(),
62
+ };
63
+ await writeFile(config.daemonFile, JSON.stringify(info, null, 2), "utf8");
64
+ const scheduler = createIndexScheduler(async (paths) => {
65
+ for (const relativePath of paths) {
66
+ await service.indexPath(relativePath).catch((error) => {
67
+ console.error(`augment: incremental index failed for ${relativePath}:`, error);
68
+ });
54
69
  }
55
- await watcher.close();
56
- await new Promise((resolve, reject) => {
57
- server.close((error) => (error ? reject(error) : resolve()));
58
- });
59
- },
60
- };
70
+ });
71
+ const watcher = chokidar.watch(config.memoryRoot, {
72
+ ignoreInitial: true,
73
+ ignored: /(^|[\\/])\.git([\\/]|$)/,
74
+ awaitWriteFinish: { stabilityThreshold: 250, pollInterval: 50 },
75
+ });
76
+ const onWatchEvent = (eventPath) => {
77
+ const relativePath = path.relative(config.memoryRoot, eventPath).split(path.sep).join("/");
78
+ if (!relativePath || relativePath.startsWith("..") || !relativePath.endsWith(".md")) {
79
+ return;
80
+ }
81
+ // Echoes of the service's own writes are already indexed inline; only
82
+ // external edits (editor saves, Dropbox sync) need the incremental pass.
83
+ if (service.consumeSelfWrite(relativePath)) {
84
+ return;
85
+ }
86
+ scheduler.schedule(relativePath);
87
+ };
88
+ watcher.on("add", onWatchEvent);
89
+ watcher.on("change", onWatchEvent);
90
+ watcher.on("unlink", onWatchEvent);
91
+ return {
92
+ info,
93
+ async close() {
94
+ // Release the slot no matter how teardown goes, so a failing watcher or
95
+ // server close can't strand the pidfile.
96
+ try {
97
+ await watcher.close();
98
+ await scheduler.close();
99
+ await initPromise;
100
+ await new Promise((resolve, reject) => {
101
+ boundServer.close((error) => (error ? reject(error) : resolve()));
102
+ });
103
+ }
104
+ finally {
105
+ await instanceLock.release();
106
+ }
107
+ },
108
+ };
109
+ }
110
+ catch (error) {
111
+ await instanceLock.release().catch(() => { });
112
+ if (server) {
113
+ await new Promise((resolve) => server.close(() => resolve()));
114
+ }
115
+ throw error;
116
+ }
61
117
  }
62
- async function handleRequest(service, request, response) {
118
+ async function handleRequest(service, indexState, config, request, response) {
63
119
  const url = new URL(request.url ?? "/", "http://127.0.0.1");
64
120
  if (request.method === "GET" && url.pathname === "/health") {
65
121
  sendJson(response, 200, { ok: true, pid: process.pid, title: process.title });
@@ -103,7 +159,26 @@ async function handleRequest(service, request, response) {
103
159
  return;
104
160
  }
105
161
  if (request.method === "POST" && url.pathname === "/memories/search") {
106
- sendJson(response, 200, await service.search(await readJson(request)));
162
+ const body = (await readJson(request));
163
+ const output = await service.search(body);
164
+ try {
165
+ // Phase-2 dogfood instrumentation. Best-effort by design: search must
166
+ // never fail because the tally could not be written.
167
+ await appendTallyEvent(config.stateDir, {
168
+ ts: new Date().toISOString(),
169
+ surface: body.surface ?? "unknown",
170
+ project: body.project_name,
171
+ query: String(body.query ?? "").slice(0, 200),
172
+ abstained: output.results.length === 0,
173
+ result_count: output.results.length,
174
+ ...(output.results[0] ? { top_score: output.results[0].score } : {}),
175
+ paths: output.results.map((result) => result.memory.relative_path),
176
+ });
177
+ }
178
+ catch {
179
+ // fail open
180
+ }
181
+ sendJson(response, 200, output);
107
182
  return;
108
183
  }
109
184
  if (request.method === "POST" && url.pathname === "/memories/upsert") {
@@ -139,7 +214,34 @@ async function handleRequest(service, request, response) {
139
214
  return;
140
215
  }
141
216
  if (request.method === "GET" && url.pathname === "/index/status") {
142
- sendJson(response, 200, { ok: true });
217
+ sendJson(response, 200, {
218
+ ok: indexState.error === undefined,
219
+ ready: indexState.ready,
220
+ ...(indexState.error !== undefined ? { error: indexState.error } : {}),
221
+ });
222
+ return;
223
+ }
224
+ if (request.method === "POST" && url.pathname === "/tally") {
225
+ const body = (await readJson(request));
226
+ if (!isTallyVerdict(body.verdict)) {
227
+ sendJson(response, 400, { error: `verdict must be one of: ${TALLY_VERDICTS.join(", ")}` });
228
+ return;
229
+ }
230
+ await appendTallyRating(config.stateDir, {
231
+ ts: new Date().toISOString(),
232
+ verdict: body.verdict,
233
+ surface: typeof body.surface === "string" && body.surface ? body.surface : "unknown",
234
+ ...(typeof body.note === "string" && body.note ? { note: body.note } : {}),
235
+ });
236
+ await sendTallySummary(response, config.stateDir);
237
+ return;
238
+ }
239
+ if (request.method === "GET" && url.pathname === "/tally") {
240
+ await sendTallySummary(response, config.stateDir);
241
+ return;
242
+ }
243
+ if (request.method === "POST" && url.pathname === "/sleep/candidates") {
244
+ sendJson(response, 200, await service.sleepCandidates(await readJson(request)));
143
245
  return;
144
246
  }
145
247
  sendJson(response, 404, { error: "not found" });
@@ -156,6 +258,10 @@ function sendJson(response, status, body) {
156
258
  response.writeHead(status, { "content-type": "application/json; charset=utf-8" });
157
259
  response.end(JSON.stringify(body));
158
260
  }
261
+ async function sendTallySummary(response, stateDir) {
262
+ const summary = summarizeTally(await readTallyRatings(stateDir));
263
+ sendJson(response, 200, { ...summary, text: renderTallySummary(summary) });
264
+ }
159
265
  function sendText(response, status, contentType, body) {
160
266
  response.writeHead(status, { "content-type": contentType });
161
267
  response.end(body);
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/daemon/http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/daemon/http.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,24 @@
1
1
  import { loadConfig } from "../config.js";
2
2
  import { AugmentService } from "../service.js";
3
3
  import { startHttpDaemon } from "./http.js";
4
+ import { DaemonAlreadyRunningError } from "./single-instance.js";
4
5
  export async function startDaemonFromCli(_args) {
5
6
  const config = await loadConfig();
6
7
  const service = new AugmentService(config);
7
- const daemon = await startHttpDaemon(config, service);
8
+ let daemon;
9
+ try {
10
+ daemon = await startHttpDaemon(config, service);
11
+ }
12
+ catch (error) {
13
+ if (error instanceof DaemonAlreadyRunningError) {
14
+ // Not a failure: another daemon already serves this state. Exit cleanly
15
+ // without co-opening its sqlite index.
16
+ console.error(`augment-daemon: ${error.message}; exiting`);
17
+ await service.close();
18
+ process.exit(0);
19
+ }
20
+ throw error;
21
+ }
8
22
  console.error(`augment-daemon listening at ${daemon.info.endpoint}`);
9
23
  const close = async () => {
10
24
  await daemon.close();
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/daemon/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAe;IACtD,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,OAAO,CAAC,KAAK,CAAC,+BAA+B,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAErE,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;QACvB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/daemon/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAe;IACtD,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;IAE3C,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,yBAAyB,EAAE,CAAC;YAC/C,wEAAwE;YACxE,uCAAuC;YACvC,OAAO,CAAC,KAAK,CAAC,mBAAmB,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;YAC3D,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,+BAA+B,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAErE,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;QACvB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Single-flight, debounced batcher between the filesystem watcher and the indexer.
3
+ *
4
+ * Watcher events arrive in bursts (editors write temp+rename, Dropbox syncs whole
5
+ * directories). The scheduler coalesces a burst into one batch of unique paths and
6
+ * guarantees the runner is never invoked concurrently with itself: events that land
7
+ * while a run is in flight are queued and processed in one follow-up run.
8
+ */
9
+ export interface IndexScheduler {
10
+ /** Queue a path for (re)indexing. Duplicate paths within a batch collapse. */
11
+ schedule(relativePath: string): void;
12
+ /** Resolves once no run is in flight, no timer is armed, and nothing is queued. */
13
+ idle(): Promise<void>;
14
+ /** Cancels pending work and waits for any in-flight run to finish. */
15
+ close(): Promise<void>;
16
+ }
17
+ export declare function createIndexScheduler(run: (paths: string[]) => Promise<void>, debounceMs?: number): IndexScheduler;
@@ -0,0 +1,77 @@
1
+ export function createIndexScheduler(run, debounceMs = 250) {
2
+ const pending = new Set();
3
+ let timer;
4
+ let inFlight;
5
+ let closed = false;
6
+ const waiters = [];
7
+ function settleIfIdle() {
8
+ if (timer === undefined && inFlight === undefined && pending.size === 0) {
9
+ while (waiters.length > 0) {
10
+ waiters.shift()?.();
11
+ }
12
+ }
13
+ }
14
+ function arm() {
15
+ if (closed || timer !== undefined) {
16
+ return;
17
+ }
18
+ timer = setTimeout(() => {
19
+ timer = undefined;
20
+ drain();
21
+ }, debounceMs);
22
+ timer.unref?.();
23
+ }
24
+ function drain() {
25
+ if (inFlight !== undefined || pending.size === 0) {
26
+ settleIfIdle();
27
+ return;
28
+ }
29
+ const batch = [...pending];
30
+ pending.clear();
31
+ inFlight = run(batch)
32
+ .catch((error) => {
33
+ // A failed run must not wedge the scheduler; the next event retries naturally.
34
+ console.error("augment: index run failed:", error);
35
+ })
36
+ .finally(() => {
37
+ inFlight = undefined;
38
+ if (pending.size > 0 && !closed) {
39
+ arm();
40
+ }
41
+ settleIfIdle();
42
+ });
43
+ }
44
+ return {
45
+ schedule(relativePath) {
46
+ if (closed) {
47
+ return;
48
+ }
49
+ pending.add(relativePath);
50
+ if (inFlight === undefined) {
51
+ arm();
52
+ }
53
+ // With a run in flight, its finally() arms the follow-up drain.
54
+ },
55
+ async idle() {
56
+ if (timer === undefined && inFlight === undefined && pending.size === 0) {
57
+ return;
58
+ }
59
+ await new Promise((resolve) => waiters.push(resolve));
60
+ },
61
+ async close() {
62
+ closed = true;
63
+ if (timer !== undefined) {
64
+ clearTimeout(timer);
65
+ timer = undefined;
66
+ }
67
+ if (inFlight !== undefined) {
68
+ await inFlight;
69
+ }
70
+ pending.clear();
71
+ while (waiters.length > 0) {
72
+ waiters.shift()?.();
73
+ }
74
+ },
75
+ };
76
+ }
77
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/daemon/scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { AugmentConfig } from "../config.js";
2
+ /**
3
+ * Thrown when a healthy daemon already owns this state dir. The daemon process
4
+ * itself (not just the connect-or-start client) must refuse to start a second
5
+ * time: two daemons co-opening the same sqlite index race on writes and produce
6
+ * intermittent SQLITE_BUSY. Callers that spawn the daemon treat this as a clean
7
+ * "already up" exit, not a failure.
8
+ */
9
+ export declare class DaemonAlreadyRunningError extends Error {
10
+ readonly endpoint: string;
11
+ readonly pid: number;
12
+ constructor(endpoint: string, pid: number);
13
+ }
14
+ /** Handle to the single-instance slot; release() frees it for the next start. */
15
+ export interface InstanceLock {
16
+ release(): Promise<void>;
17
+ }
18
+ /**
19
+ * Claim the sole-daemon slot for `config.stateDir`, or throw
20
+ * {@link DaemonAlreadyRunningError} if another daemon already holds it.
21
+ *
22
+ * Two independent signals guard the slot:
23
+ * - the recorded daemon's /health endpoint (authoritative — a daemon that
24
+ * answers /health for this memoryRoot is unambiguously already serving), and
25
+ * - an exclusive `daemon.pid` lockfile that closes the cold-start window before
26
+ * the winner becomes healthy. A pidfile is reclaimed when its holder is
27
+ * provably dead, or when it has aged past the grace window (a crash-stranded
28
+ * orphan, possibly with a since-reused pid); a live, recent holder is honored.
29
+ * Reclamation is atomic — an orphan is renamed aside, so of two racing starts
30
+ * at most one reclaims and the loser honors whoever recreates the slot.
31
+ */
32
+ export declare function acquireSingleInstance(config: AugmentConfig): Promise<InstanceLock>;
@@ -0,0 +1,131 @@
1
+ import { constants } from "node:fs";
2
+ import { open, readFile, rename, rm, stat } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { isDaemonHealthy, readDaemonInfo } from "./client.js";
5
+ /**
6
+ * A pidfile whose holder is not provably dead is honored only this long. Past
7
+ * this age it is treated as an orphan and reclaimed — covering an unclean death
8
+ * (SIGKILL / `taskkill /F` / power loss) that stranded the file, and the case
9
+ * where the OS has since reused the dead daemon's pid for an unrelated live
10
+ * process. The window must exceed a real cold start (acquire → bind →
11
+ * write-daemon.json, sub-second under listen-first) so a genuinely-starting peer
12
+ * is never reclaimed out from under itself; 30s sits well above that and matches
13
+ * the client's existing daemon timeouts.
14
+ */
15
+ const STALE_PIDFILE_GRACE_MS = 30_000;
16
+ /**
17
+ * Thrown when a healthy daemon already owns this state dir. The daemon process
18
+ * itself (not just the connect-or-start client) must refuse to start a second
19
+ * time: two daemons co-opening the same sqlite index race on writes and produce
20
+ * intermittent SQLITE_BUSY. Callers that spawn the daemon treat this as a clean
21
+ * "already up" exit, not a failure.
22
+ */
23
+ export class DaemonAlreadyRunningError extends Error {
24
+ endpoint;
25
+ pid;
26
+ constructor(endpoint, pid) {
27
+ super(`augment daemon already running at ${endpoint} (pid ${pid})`);
28
+ this.endpoint = endpoint;
29
+ this.pid = pid;
30
+ this.name = "DaemonAlreadyRunningError";
31
+ }
32
+ }
33
+ /**
34
+ * Claim the sole-daemon slot for `config.stateDir`, or throw
35
+ * {@link DaemonAlreadyRunningError} if another daemon already holds it.
36
+ *
37
+ * Two independent signals guard the slot:
38
+ * - the recorded daemon's /health endpoint (authoritative — a daemon that
39
+ * answers /health for this memoryRoot is unambiguously already serving), and
40
+ * - an exclusive `daemon.pid` lockfile that closes the cold-start window before
41
+ * the winner becomes healthy. A pidfile is reclaimed when its holder is
42
+ * provably dead, or when it has aged past the grace window (a crash-stranded
43
+ * orphan, possibly with a since-reused pid); a live, recent holder is honored.
44
+ * Reclamation is atomic — an orphan is renamed aside, so of two racing starts
45
+ * at most one reclaims and the loser honors whoever recreates the slot.
46
+ */
47
+ export async function acquireSingleInstance(config) {
48
+ const pidPath = path.join(config.stateDir, "daemon.pid");
49
+ for (let attempt = 0; attempt < 50; attempt += 1) {
50
+ // Authoritative check: is a daemon for this memoryRoot already answering?
51
+ const recorded = await readDaemonInfo(config);
52
+ if (recorded && (await isDaemonHealthy(recorded, config))) {
53
+ throw new DaemonAlreadyRunningError(recorded.endpoint, recorded.pid);
54
+ }
55
+ let handle;
56
+ try {
57
+ handle = await open(pidPath, constants.O_CREAT | constants.O_EXCL | constants.O_RDWR);
58
+ }
59
+ catch (error) {
60
+ if (error.code !== "EEXIST") {
61
+ throw error;
62
+ }
63
+ // A pidfile exists but no healthy daemon answered above.
64
+ const holder = await classifyPidfile(pidPath);
65
+ if (!holder.reclaim) {
66
+ throw new DaemonAlreadyRunningError(recorded?.endpoint ?? "unknown", recorded?.pid ?? holder.pid);
67
+ }
68
+ // Reclaim atomically: only one racer can rename the orphan away, so two
69
+ // concurrent starts can never both delete-and-recreate the slot. The loser
70
+ // gets ENOENT and re-evaluates, then honors whoever recreated the pidfile.
71
+ const parked = `${pidPath}.${process.pid}.${attempt}.reclaim`;
72
+ try {
73
+ await rename(pidPath, parked);
74
+ }
75
+ catch (renameError) {
76
+ if (renameError.code === "ENOENT") {
77
+ continue;
78
+ }
79
+ throw renameError;
80
+ }
81
+ await rm(parked, { force: true });
82
+ continue;
83
+ }
84
+ try {
85
+ await handle.writeFile(String(process.pid), "utf8");
86
+ }
87
+ finally {
88
+ await handle.close();
89
+ }
90
+ return {
91
+ async release() {
92
+ await rm(pidPath, { force: true });
93
+ },
94
+ };
95
+ }
96
+ throw new Error(`Could not acquire daemon single-instance lock: ${pidPath}`);
97
+ }
98
+ /**
99
+ * Decide whether an existing pidfile may be reclaimed. A provably-dead holder is
100
+ * always safe. Otherwise the pidfile is honored only until it ages out: a real
101
+ * cold-start peer writes its pid and becomes healthy within the grace window, so
102
+ * anything older is a crash-stranded orphan (empty, or a since-reused pid).
103
+ */
104
+ async function classifyPidfile(pidPath) {
105
+ let ageMs = Infinity;
106
+ try {
107
+ ageMs = Date.now() - (await stat(pidPath)).mtimeMs;
108
+ }
109
+ catch {
110
+ // Vanished between the failed O_EXCL create and now — free to take.
111
+ return { reclaim: true, pid: -1 };
112
+ }
113
+ const raw = (await readFile(pidPath, "utf8").catch(() => "")).trim();
114
+ const pid = Number(raw);
115
+ const parsed = raw !== "" && Number.isInteger(pid) && pid > 0;
116
+ if (parsed && !isProcessAlive(pid)) {
117
+ return { reclaim: true, pid };
118
+ }
119
+ return { reclaim: ageMs > STALE_PIDFILE_GRACE_MS, pid: parsed ? pid : -1 };
120
+ }
121
+ /** True if `pid` names a live process (including one we lack permission to signal). */
122
+ function isProcessAlive(pid) {
123
+ try {
124
+ process.kill(pid, 0);
125
+ return true;
126
+ }
127
+ catch (error) {
128
+ return error.code === "EPERM";
129
+ }
130
+ }
131
+ //# sourceMappingURL=single-instance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"single-instance.js","sourceRoot":"","sources":["../../src/daemon/single-instance.ts"],"names":[],"mappings":"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"}
package/dist/db.d.ts CHANGED
@@ -12,7 +12,10 @@ export declare class AugmentDatabase {
12
12
  getProjectByName(name: string): Promise<ProjectRecord | undefined>;
13
13
  upsertMemory(memory: ParsedMemory): Promise<MemoryRecord>;
14
14
  deleteMemory(id: number): Promise<void>;
15
- removeMissingMemories(relativePaths: string[]): Promise<void>;
15
+ deleteMemoryByPath(relativePath: string): Promise<void>;
16
+ /** relative_path → stored file mtime (ms), for change detection without reading file bodies. */
17
+ listMemoryFileStats(): Promise<Map<string, number>>;
18
+ removeMissingMemories(relativePaths: string[]): Promise<number>;
16
19
  rebuildLinks(): Promise<void>;
17
20
  getMemoryById(id: number): Promise<MemoryRecord | undefined>;
18
21
  getMemoryByPath(relativePath: string): Promise<MemoryRecord | undefined>;
@@ -28,7 +31,16 @@ export declare class AugmentDatabase {
28
31
  getAllEmbeddings(): Promise<Map<number, number[]>>;
29
32
  upsertEmbedding(memory: ParsedMemory | MemoryRecord, provider: EmbeddingProvider, vector: number[]): Promise<void>;
30
33
  embeddingText(memory: ParsedMemory | MemoryRecord): string;
34
+ /**
35
+ * Incremental link maintenance for one re-indexed memory: replaces its outbound links from its
36
+ * frontmatter, then materializes inbound links other memories declare toward its path (they may
37
+ * have been dangling if this file was just created). Equivalent to {@link rebuildLinks} for the
38
+ * subgraph touching this memory, without paying the full O(memories × links) sweep.
39
+ */
40
+ rebuildLinksForMemory(memory: MemoryRecord): Promise<void>;
31
41
  private execute;
32
42
  private batch;
43
+ /** Parameterized statements in one transaction: one commit, all-or-nothing. */
44
+ private batchExecute;
33
45
  private getClient;
34
46
  }