@fingerskier/augment 0.1.10 → 0.2.1
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.
- package/README.md +20 -2
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +43 -2
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts +3 -0
- package/dist/constants.js +19 -3
- package/dist/constants.js.map +1 -1
- package/dist/daemon/client.d.ts +5 -0
- package/dist/daemon/client.js +15 -6
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/http.d.ts +1 -1
- package/dist/daemon/http.js +159 -53
- package/dist/daemon/http.js.map +1 -1
- package/dist/daemon/main.js +15 -1
- package/dist/daemon/main.js.map +1 -1
- package/dist/daemon/scheduler.d.ts +17 -0
- package/dist/daemon/scheduler.js +77 -0
- package/dist/daemon/scheduler.js.map +1 -0
- package/dist/daemon/single-instance.d.ts +32 -0
- package/dist/daemon/single-instance.js +131 -0
- package/dist/daemon/single-instance.js.map +1 -0
- package/dist/db.d.ts +13 -1
- package/dist/db.js +166 -105
- package/dist/db.js.map +1 -1
- package/dist/hooks.js +28 -3
- package/dist/hooks.js.map +1 -1
- package/dist/install.d.ts +2 -0
- package/dist/install.js +50 -8
- package/dist/install.js.map +1 -1
- package/dist/mcp/server.js +30 -4
- package/dist/mcp/server.js.map +1 -1
- package/dist/recall.d.ts +2 -0
- package/dist/recall.js +1 -0
- package/dist/recall.js.map +1 -1
- package/dist/service.d.ts +64 -1
- package/dist/service.js +269 -35
- package/dist/service.js.map +1 -1
- package/dist/sleep.d.ts +43 -0
- package/dist/sleep.js +129 -0
- package/dist/sleep.js.map +1 -0
- package/dist/tally.d.ts +46 -0
- package/dist/tally.js +94 -0
- package/dist/tally.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/util/text.d.ts +3 -0
- package/dist/util/text.js +26 -2
- package/dist/util/text.js.map +1 -1
- package/docs/FEATURES.md +155 -50
- package/docs/verify-memory-flow.md +28 -9
- package/integrations/examples/claude-mcp-config.json +0 -3
- package/integrations/examples/codex-mcp-config.json +0 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,13 +69,17 @@ The point is to close the loop on every coding session:
|
|
|
69
69
|
3. **Work done.** The agent implements against that context instead of guessing.
|
|
70
70
|
4. **Memories updated.** Durable outcomes — requirements (`SPEC`), decisions (`ARCH`), bugs (`ISSUE`), deferred work (`TODO`), milestones (`WORK`) — are written back and linked, ready for the next session.
|
|
71
71
|
|
|
72
|
+
Installed integrations enforce this loop with lifecycle hooks: relevant memory is
|
|
73
|
+
auto-injected at prompt and tool time, and a Stop hook prompts the end-of-turn
|
|
74
|
+
write-back — no reliance on the agent remembering.
|
|
75
|
+
|
|
72
76
|
Over time the memory folder becomes a project's institutional knowledge:
|
|
73
77
|
queryable by semantic search, browsable as a graph in the [dashboard](#dashboard), and portable across machines via relative paths.
|
|
74
78
|
For example, you could set your memory-root at a Dropbox folder and use them on multiple machines-
|
|
75
79
|
paths and linkages are relative to that path so the search index is rebuildable and useable on multiple systems at once.
|
|
76
80
|
|
|
77
81
|
Feature details live in [docs/FEATURES.md](docs/FEATURES.md).
|
|
78
|
-
|
|
82
|
+
Remaining planned work lives in [ROADMAP.md](ROADMAP.md).
|
|
79
83
|
|
|
80
84
|
----
|
|
81
85
|
|
|
@@ -113,6 +117,10 @@ Defaults:
|
|
|
113
117
|
- Memory root: `~/.augment/memories`
|
|
114
118
|
- State directory: `~/.augment/state`
|
|
115
119
|
|
|
120
|
+
Also honored: `AUGMENT_STATE_DIR` (state directory) and `AUGMENT_DAEMON_PORT`
|
|
121
|
+
(fixed daemon port; the default is dynamic). Full resolution order and defaults:
|
|
122
|
+
[docs/FEATURES.md](docs/FEATURES.md#configuration).
|
|
123
|
+
|
|
116
124
|
## Run Locally
|
|
117
125
|
|
|
118
126
|
Show all commands and options:
|
|
@@ -217,11 +225,17 @@ Install the Claude plugin:
|
|
|
217
225
|
npm exec --yes --package @fingerskier/augment -- augment install claude --scope repo --memory-root "C:\Users\you\Dropbox\augment-memories"
|
|
218
226
|
```
|
|
219
227
|
|
|
220
|
-
`install claude` does
|
|
228
|
+
`install claude` does seven things:
|
|
221
229
|
|
|
222
230
|
- Scaffolds a real Claude Code plugin at `<root>/plugins/augment/`
|
|
223
231
|
(`.claude-plugin/plugin.json`, an auto-discovered `augment-context` skill, and a
|
|
224
232
|
bundled `.mcp.json`).
|
|
233
|
+
- Writes `hooks/hooks.json` into the plugin — lifecycle hooks (SessionStart /
|
|
234
|
+
UserPromptSubmit / PreToolUse / Stop) that auto-inject recalled memory and
|
|
235
|
+
prompt the end-of-turn memory write-back.
|
|
236
|
+
- Provisions the hook runtime once (`npm install` into `~/.augment/npm-exec`) so
|
|
237
|
+
hooks run via a direct `node` command instead of paying an npm bootstrap on
|
|
238
|
+
every event.
|
|
225
239
|
- Adds a marketplace entry at `<root>/.claude-plugin/marketplace.json`.
|
|
226
240
|
- **Registers the MCP server directly** so it is active without the marketplace
|
|
227
241
|
step: repo scope writes `<repo>/.mcp.json`; user scope merges into
|
|
@@ -261,6 +275,10 @@ npm exec --yes --package @fingerskier/augment -- augment install codex --scope u
|
|
|
261
275
|
|
|
262
276
|
The installer configures MCP commands with an isolated npm `--prefix` directory
|
|
263
277
|
under `~/.augment/npm-exec` so they work even when launched from this repository.
|
|
278
|
+
The same directory hosts the provisioned hook runtime; if npm was unavailable at
|
|
279
|
+
install time, the installer prints the manual
|
|
280
|
+
`npm install --prefix <prefix> @fingerskier/augment` command and hooks stay
|
|
281
|
+
silent no-ops until it is run.
|
|
264
282
|
|
|
265
283
|
Run these package commands from outside this repository. When developing inside
|
|
266
284
|
this repo, use `node .\dist\bin\augment.js install ...` after `npm run build`.
|
package/dist/cli.d.ts
CHANGED
|
@@ -3,12 +3,18 @@ import { type RecallOptions } from "./recall.js";
|
|
|
3
3
|
export interface DashboardDaemon {
|
|
4
4
|
endpoint: string;
|
|
5
5
|
}
|
|
6
|
+
/** The slice of the daemon client the `tally` command needs. */
|
|
7
|
+
export interface TallyDaemon {
|
|
8
|
+
tally(input: unknown): Promise<unknown>;
|
|
9
|
+
tallySummary(): Promise<unknown>;
|
|
10
|
+
}
|
|
6
11
|
/** Injectable seams so `recall`/`hook`/`dashboard` are testable without touching the daemon, browser, or real stdin. */
|
|
7
12
|
export interface RunCliDeps {
|
|
8
13
|
recall?: (options: RecallOptions) => Promise<string>;
|
|
9
14
|
readStdin?: () => Promise<string>;
|
|
10
15
|
connectDashboardDaemon?: () => Promise<DashboardDaemon>;
|
|
11
16
|
openUrl?: (url: string) => Promise<void>;
|
|
17
|
+
connectTallyDaemon?: () => Promise<TallyDaemon>;
|
|
12
18
|
}
|
|
13
19
|
export declare function runCli(args: string[], deps?: RunCliDeps): Promise<void>;
|
|
14
20
|
/** Human-readable usage shown by `augment help`, `--help`, `-h`, and on unknown commands. */
|
package/dist/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ export async function runCli(args, deps = {}) {
|
|
|
17
17
|
}
|
|
18
18
|
if (command === "install") {
|
|
19
19
|
const parsed = parseInstallArgs(args.slice(1));
|
|
20
|
-
const plan = await installIntegration({ ...parsed, runClaude: defaultClaudeRunner });
|
|
20
|
+
const plan = await installIntegration({ ...parsed, runClaude: defaultClaudeRunner, runNpm: defaultClaudeRunner });
|
|
21
21
|
for (const line of plan.summary) {
|
|
22
22
|
console.log(line);
|
|
23
23
|
}
|
|
@@ -39,12 +39,22 @@ export async function runCli(args, deps = {}) {
|
|
|
39
39
|
}
|
|
40
40
|
if (command === "recall") {
|
|
41
41
|
const recall = deps.recall ?? defaultRecall;
|
|
42
|
-
const text = await recall(parseRecallArgs(args.slice(1)));
|
|
42
|
+
const text = await recall({ ...parseRecallArgs(args.slice(1)), surface: "cli-recall" });
|
|
43
43
|
if (text) {
|
|
44
44
|
console.log(text);
|
|
45
45
|
}
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
+
if (command === "tally") {
|
|
49
|
+
const parsed = parseTallyArgs(args.slice(1));
|
|
50
|
+
const client = await (deps.connectTallyDaemon ?? defaultConnectTallyDaemon)();
|
|
51
|
+
const result = parsed.verdict
|
|
52
|
+
? await client.tally(parsed)
|
|
53
|
+
: await client.tallySummary();
|
|
54
|
+
const text = result.text;
|
|
55
|
+
console.log(typeof text === "string" ? text : JSON.stringify(result, null, 2));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
48
58
|
if (command === "hook") {
|
|
49
59
|
const event = args[1] ?? "";
|
|
50
60
|
const raw = await (deps.readStdin ?? readStdin)();
|
|
@@ -74,6 +84,7 @@ export function helpText() {
|
|
|
74
84
|
" install <target> Install an agent integration (see below).",
|
|
75
85
|
" dashboard Open the memory dashboard (project/memory graph + search + CRUD).",
|
|
76
86
|
" recall <query> Print memory recalled for a task (auto-injected by hooks).",
|
|
87
|
+
" tally [verdict] Record or show the Phase-2 dogfood tally (recall quality).",
|
|
77
88
|
" hook <event> Run a lifecycle hook over stdin JSON (host-wired; see below).",
|
|
78
89
|
" help Show this help (also --help, -h).",
|
|
79
90
|
"",
|
|
@@ -85,6 +96,11 @@ export function helpText() {
|
|
|
85
96
|
" augment recall \"<task text>\" [--project ORG/REPO] [--cwd PATH]",
|
|
86
97
|
" [--limit N] [--max-chars N] [--min-score F]",
|
|
87
98
|
"",
|
|
99
|
+
"TALLY (Phase-2 dogfood: rate what recall injected)",
|
|
100
|
+
" augment tally Print the running tally (target: 30 datapoints).",
|
|
101
|
+
" augment tally <helpful|harmless|harmful|correct-abstention>",
|
|
102
|
+
" [--surface S] [--note \"...\"] Record one datapoint.",
|
|
103
|
+
"",
|
|
88
104
|
"HOOK (wired into Claude Code / Codex by `install`; reads hook JSON on stdin)",
|
|
89
105
|
" augment hook session-start | user-prompt-submit | pre-tool-use | stop",
|
|
90
106
|
"",
|
|
@@ -159,6 +175,31 @@ function parseRecallArgs(args) {
|
|
|
159
175
|
options.query = queryParts.join(" ");
|
|
160
176
|
return options;
|
|
161
177
|
}
|
|
178
|
+
function parseTallyArgs(args) {
|
|
179
|
+
const result = {};
|
|
180
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
181
|
+
const arg = args[index];
|
|
182
|
+
if (arg === "--surface") {
|
|
183
|
+
result.surface = required(args[++index], "--surface requires a value");
|
|
184
|
+
}
|
|
185
|
+
else if (arg === "--note") {
|
|
186
|
+
result.note = required(args[++index], "--note requires a value");
|
|
187
|
+
}
|
|
188
|
+
else if (arg.startsWith("--")) {
|
|
189
|
+
throw new Error(`Unknown tally option: ${arg}`);
|
|
190
|
+
}
|
|
191
|
+
else if (!result.verdict) {
|
|
192
|
+
result.verdict = arg;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
throw new Error(`Unknown tally option: ${arg}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
async function defaultConnectTallyDaemon() {
|
|
201
|
+
return connectOrStartDaemon();
|
|
202
|
+
}
|
|
162
203
|
function required(value, message) {
|
|
163
204
|
if (!value) {
|
|
164
205
|
throw new Error(message);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAyC,MAAM,cAAc,CAAC;AAC9G,OAAO,EAAE,MAAM,IAAI,aAAa,EAAsB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAyC,MAAM,cAAc,CAAC;AAC9G,OAAO,EAAE,MAAM,IAAI,aAAa,EAAsB,MAAM,aAAa,CAAC;AAsB1E,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAc,EAAE,OAAmB,EAAE;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;IAEpC,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QACxB,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACjD,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAClH,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QAC5B,MAAM,EAAE,IAAI,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,IAAI,CAAC,sBAAsB,IAAI,6BAA6B,CAAC;QAC7E,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,GAAG,QAAQ,YAAY,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,EAAE,CAAC,CAAC;QACzC,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC;QAC5C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;QACxF,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,IAAI,yBAAyB,CAAC,EAAE,CAAC;QAC9E,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO;YAC3B,CAAC,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;YAC5B,CAAC,CAAC,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;QAChC,MAAM,IAAI,GAAI,MAA6B,CAAC,IAAI,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/E,OAAO;IACT,CAAC;IAED,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,EAAE,CAAC;QAClD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAClE,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACnC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC1B,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,QAAQ;IACtB,OAAO;QACL,8CAA8C;QAC9C,EAAE;QACF,OAAO;QACP,+BAA+B;QAC/B,EAAE;QACF,UAAU;QACV,yEAAyE;QACzE,uCAAuC;QACvC,+DAA+D;QAC/D,uFAAuF;QACvF,gFAAgF;QAChF,gFAAgF;QAChF,mFAAmF;QACnF,uDAAuD;QACvD,EAAE;QACF,WAAW;QACX,qFAAqF;QACrF,8FAA8F;QAC9F,EAAE;QACF,QAAQ;QACR,oEAAoE;QACpE,2EAA2E;QAC3E,EAAE;QACF,oDAAoD;QACpD,iGAAiG;QACjG,+DAA+D;QAC/D,wEAAwE;QACxE,EAAE;QACF,8EAA8E;QAC9E,yEAAyE;QACzE,EAAE;QACF,SAAS;QACT,gDAAgD;QAChD,EAAE;QACF,YAAY;QACZ,2FAA2F;QAC3F,mFAAmF;QACnF,0EAA0E;QAC1E,4FAA4F;QAC5F,EAAE;QACF,kCAAkC;QAClC,uHAAuH;QACvH,uFAAuF;QACvF,+FAA+F;QAC/F,EAAE;QACF,6DAA6D;QAC7D,2EAA2E;QAC3E,EAAE;QACF,0DAA0D;KAC3D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAc;IACxC,IAAI,IAAI,GAAG,IAAI,CAAC;IAChB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,IAAI,GAAG,KAAK,CAAC;QACf,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,6BAA6B;IAC1C,MAAM,MAAM,GAAG,MAAM,oBAAoB,EAAE,CAAC;IAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;AACvC,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,GAAW;IACvC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,MAAM,OAAO,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;IAC3F,6FAA6F;IAC7F,MAAM,WAAW,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC/E,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC;AAED,SAAS,eAAe,CAAC,IAAc;IACrC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,OAAO,GAAkB,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAE7C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,OAAO,CAAC,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,4BAA4B,CAAC,CAAC;QAC1E,CAAC;aAAM,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,uBAAuB,CAAC,CAAC;QACjE,CAAC;aAAM,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC;QACrD,CAAC;aAAM,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YACjC,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,aAAa,CAAC,CAAC;QAC5D,CAAC;aAAM,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YACjC,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,aAAa,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,IAAc;IACpC,MAAM,MAAM,GAA0D,EAAE,CAAC;IACzE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,4BAA4B,CAAC,CAAC;QACzE,CAAC;aAAM,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,yBAAyB,CAAC,CAAC;QACnE,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,EAAE,CAAC,CAAC;QAClD,CAAC;aAAM,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAC3B,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,yBAAyB;IACtC,OAAO,oBAAoB,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,QAAQ,CAAC,KAAyB,EAAE,OAAe;IAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAAyB,EAAE,IAAY;IACvD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,IAAI,oBAAoB,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,mBAAmB,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gFAAgF;AAChF,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAc;IAOtC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAA8B,CAAC;IACpD,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CACb,8GAA8G,CAC/G,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,GAAiB,MAAM,CAAC;IACjC,IAAI,UAA8B,CAAC;IACnC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,KAAK,CAA6B,CAAC;YACxD,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;gBACzC,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAClD,CAAC;YACD,KAAK,GAAG,KAAK,CAAC;QAChB,CAAC;aAAM,IAAI,GAAG,KAAK,eAAe,EAAE,CAAC;YACnC,UAAU,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;YAC3B,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;aAAM,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YAC/B,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;aAAM,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YACjC,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,OAAO;QACL,MAAM;QACN,KAAK;QACL,UAAU;QACV,MAAM;QACN,QAAQ;KACT,CAAC;AACJ,CAAC"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -13,3 +13,6 @@ export declare const MEMORY_KINDS: readonly ["ISSUE", "ARCH", "TODO", "SPEC", "W
|
|
|
13
13
|
export type MemoryKind = (typeof MEMORY_KINDS)[number];
|
|
14
14
|
export declare const LINK_TYPES: readonly ["DEPENDS_ON", "BLOCKS", "IMPLEMENTS", "PARENT", "RELATED"];
|
|
15
15
|
export type LinkType = (typeof LINK_TYPES)[number];
|
|
16
|
+
export declare const SLEEP_MIN_COSINE = 0.75;
|
|
17
|
+
export declare const SLEEP_MIN_AGE_DAYS = 3;
|
|
18
|
+
export declare const SLEEP_MAX_CLUSTERS = 20;
|
package/dist/constants.js
CHANGED
|
@@ -31,11 +31,27 @@ export const SEMANTIC_COSINE_MATCH = 1.0;
|
|
|
31
31
|
export const EMBEDDING_MODEL_ID = "Xenova/bge-small-en-v1.5";
|
|
32
32
|
// Concrete HF commit that `Xenova/bge-small-en-v1.5` `main` resolved to on
|
|
33
33
|
// 2026-06-30 (`git ls-remote https://huggingface.co/Xenova/bge-small-en-v1.5`),
|
|
34
|
-
// and the snapshot cached on the build machine.
|
|
35
|
-
// load
|
|
36
|
-
//
|
|
34
|
+
// and the snapshot cached on the build machine. Deliberately NOT threaded into
|
|
35
|
+
// the pipeline() load (see embeddings.ts): transformers.js keys its on-disk
|
|
36
|
+
// cache by requested revision, so pinning would break offline loads from a
|
|
37
|
+
// main-populated cache. This constant is a tripwire — the real-model test
|
|
38
|
+
// asserts it, so a moved `main` fails loudly instead of silently changing
|
|
39
|
+
// embeddings.
|
|
37
40
|
export const PINNED_MODEL_REVISION = "ea104dacec62c0de699686887e3f920caeb4f3e3";
|
|
38
41
|
export const EMBEDDING_DIMENSIONS = 384;
|
|
39
42
|
export const MEMORY_KINDS = ["ISSUE", "ARCH", "TODO", "SPEC", "WORK"];
|
|
40
43
|
export const LINK_TYPES = ["DEPENDS_ON", "BLOCKS", "IMPLEMENTS", "PARENT", "RELATED"];
|
|
44
|
+
// --- sleep_candidates (READ-ONLY consolidation preview) -------------------
|
|
45
|
+
// Raw-cosine clustering threshold — deliberately NOT the blended recall score.
|
|
46
|
+
// Council 2026-06-30: clustering must use a semantic-only floor above the band
|
|
47
|
+
// where unrelated same-domain memories land. Measured bge-small raw-cosine
|
|
48
|
+
// anchors (see above): same-domain-unrelated ~0.485, paraphrase ~0.882. 0.75
|
|
49
|
+
// splits that gap with margin toward "don't fold what shouldn't fold": a
|
|
50
|
+
// missed merge costs nothing in a read-only preview; a bad merge is exactly
|
|
51
|
+
// the failure mode the council flagged.
|
|
52
|
+
export const SLEEP_MIN_COSINE = 0.75;
|
|
53
|
+
// WORK memories younger than this are still "in play" — the session that
|
|
54
|
+
// wrote them may still be appending related notes. Days, by updated_at.
|
|
55
|
+
export const SLEEP_MIN_AGE_DAYS = 3;
|
|
56
|
+
export const SLEEP_MAX_CLUSTERS = 20;
|
|
41
57
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,sBAAsB,CAAC;AACnD,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,CAAC;AACrD,MAAM,CAAC,MAAM,+BAA+B,GAAG,MAAM,CAAC;AACtD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AACtC,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAC/C,6EAA6E;AAC7E,0EAA0E;AAC1E,uEAAuE;AACvE,4EAA4E;AAC5E,8EAA8E;AAC9E,+DAA+D;AAC/D,8EAA8E;AAC9E,2EAA2E;AAC3E,6EAA6E;AAC7E,sEAAsE;AACtE,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAE5C,gFAAgF;AAChF,6EAA6E;AAC7E,mEAAmE;AACnE,wDAAwD;AACxD,qCAAqC;AACrC,qCAAqC;AACrC,oDAAoD;AACpD,+EAA+E;AAC/E,+EAA+E;AAC/E,iFAAiF;AACjF,iFAAiF;AACjF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAC7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC,MAAM,CAAC,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AAC7D,2EAA2E;AAC3E,gFAAgF;AAChF,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,sBAAsB,CAAC;AACnD,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,CAAC;AACrD,MAAM,CAAC,MAAM,+BAA+B,GAAG,MAAM,CAAC;AACtD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AACtC,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAC/C,6EAA6E;AAC7E,0EAA0E;AAC1E,uEAAuE;AACvE,4EAA4E;AAC5E,8EAA8E;AAC9E,+DAA+D;AAC/D,8EAA8E;AAC9E,2EAA2E;AAC3E,6EAA6E;AAC7E,sEAAsE;AACtE,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAE5C,gFAAgF;AAChF,6EAA6E;AAC7E,mEAAmE;AACnE,wDAAwD;AACxD,qCAAqC;AACrC,qCAAqC;AACrC,oDAAoD;AACpD,+EAA+E;AAC/E,+EAA+E;AAC/E,iFAAiF;AACjF,iFAAiF;AACjF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAC7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC,MAAM,CAAC,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AAC7D,2EAA2E;AAC3E,gFAAgF;AAChF,+EAA+E;AAC/E,4EAA4E;AAC5E,2EAA2E;AAC3E,0EAA0E;AAC1E,0EAA0E;AAC1E,cAAc;AACd,MAAM,CAAC,MAAM,qBAAqB,GAAG,0CAA0C,CAAC;AAChF,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAExC,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAG/E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,CAAU,CAAC;AAG/F,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,2EAA2E;AAC3E,6EAA6E;AAC7E,yEAAyE;AACzE,4EAA4E;AAC5E,wCAAwC;AACxC,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AACrC,yEAAyE;AACzE,wEAAwE;AACxE,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC"}
|
package/dist/daemon/client.d.ts
CHANGED
|
@@ -12,9 +12,14 @@ export declare class DaemonClient {
|
|
|
12
12
|
link(input: unknown): Promise<unknown>;
|
|
13
13
|
listLinks(memoryId: number): Promise<unknown>;
|
|
14
14
|
unlink(id: number): Promise<unknown>;
|
|
15
|
+
tally(input: unknown): Promise<unknown>;
|
|
16
|
+
sleepCandidates(input: unknown): Promise<unknown>;
|
|
17
|
+
tallySummary(): Promise<unknown>;
|
|
15
18
|
private get;
|
|
16
19
|
private post;
|
|
17
20
|
private delete;
|
|
18
21
|
private request;
|
|
19
22
|
}
|
|
20
23
|
export declare function connectOrStartDaemon(config?: AugmentConfig): Promise<DaemonClient>;
|
|
24
|
+
export declare function readDaemonInfo(config: AugmentConfig): Promise<DaemonInfo | undefined>;
|
|
25
|
+
export declare function isDaemonHealthy(info: DaemonInfo, config: AugmentConfig): Promise<boolean>;
|
package/dist/daemon/client.js
CHANGED
|
@@ -37,6 +37,15 @@ export class DaemonClient {
|
|
|
37
37
|
async unlink(id) {
|
|
38
38
|
return this.delete(`/links/${id}`);
|
|
39
39
|
}
|
|
40
|
+
async tally(input) {
|
|
41
|
+
return this.post("/tally", input);
|
|
42
|
+
}
|
|
43
|
+
async sleepCandidates(input) {
|
|
44
|
+
return this.post("/sleep/candidates", input);
|
|
45
|
+
}
|
|
46
|
+
async tallySummary() {
|
|
47
|
+
return this.get("/tally");
|
|
48
|
+
}
|
|
40
49
|
async get(pathname) {
|
|
41
50
|
return this.request("GET", pathname);
|
|
42
51
|
}
|
|
@@ -63,24 +72,24 @@ export async function connectOrStartDaemon(config) {
|
|
|
63
72
|
config ??= await loadConfig();
|
|
64
73
|
await ensureConfigDirs(config);
|
|
65
74
|
const existing = await readDaemonInfo(config);
|
|
66
|
-
if (existing && (await
|
|
75
|
+
if (existing && (await isDaemonHealthy(existing, config))) {
|
|
67
76
|
return new DaemonClient(existing);
|
|
68
77
|
}
|
|
69
78
|
await withDaemonLock(config, async () => {
|
|
70
79
|
const afterLock = await readDaemonInfo(config);
|
|
71
|
-
if (afterLock && (await
|
|
80
|
+
if (afterLock && (await isDaemonHealthy(afterLock, config))) {
|
|
72
81
|
return;
|
|
73
82
|
}
|
|
74
83
|
await startDaemonProcess();
|
|
75
84
|
await waitForDaemon(config);
|
|
76
85
|
});
|
|
77
86
|
const info = await readDaemonInfo(config);
|
|
78
|
-
if (!info || !(await
|
|
87
|
+
if (!info || !(await isDaemonHealthy(info, config))) {
|
|
79
88
|
throw new Error("Failed to start augment daemon");
|
|
80
89
|
}
|
|
81
90
|
return new DaemonClient(info);
|
|
82
91
|
}
|
|
83
|
-
async function readDaemonInfo(config) {
|
|
92
|
+
export async function readDaemonInfo(config) {
|
|
84
93
|
try {
|
|
85
94
|
return JSON.parse(await readFile(config.daemonFile, "utf8"));
|
|
86
95
|
}
|
|
@@ -88,7 +97,7 @@ async function readDaemonInfo(config) {
|
|
|
88
97
|
return undefined;
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
|
-
async function
|
|
100
|
+
export async function isDaemonHealthy(info, config) {
|
|
92
101
|
if (info.memoryRoot !== config.memoryRoot) {
|
|
93
102
|
return false;
|
|
94
103
|
}
|
|
@@ -104,7 +113,7 @@ async function waitForDaemon(config) {
|
|
|
104
113
|
const deadline = Date.now() + 15_000;
|
|
105
114
|
while (Date.now() < deadline) {
|
|
106
115
|
const info = await readDaemonInfo(config);
|
|
107
|
-
if (info && (await
|
|
116
|
+
if (info && (await isDaemonHealthy(info, config))) {
|
|
108
117
|
return;
|
|
109
118
|
}
|
|
110
119
|
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/daemon/client.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/daemon/client.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon/http.d.ts
CHANGED
package/dist/daemon/http.js
CHANGED
|
@@ -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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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, {
|
|
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);
|