memhtml 0.2.5 → 0.4.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.
- package/README.md +114 -245
- package/agent/instructions.md +74 -84
- package/dist/{dist-t84Q_98w.mjs → dist-BCsav-EP.mjs} +341 -6
- package/dist/dist-BCsav-EP.mjs.map +1 -0
- package/dist/{dist-Uj47oBRC.mjs → dist-D73gfqLc.mjs} +4087 -370
- package/dist/dist-D73gfqLc.mjs.map +1 -0
- package/dist/dist-DuzGralO.mjs +3 -0
- package/dist/memhtml-mcp.mjs +45 -7
- package/dist/memhtml-mcp.mjs.map +1 -1
- package/dist/memhtml.mjs +64 -11
- package/dist/memhtml.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +180 -8
- package/src/contract.ts +232 -5
- package/state-migrations/S0002_entity_corroboration.sql +55 -0
- package/dist/dist-Dj-MYf9q.mjs +0 -3
- package/dist/dist-Uj47oBRC.mjs.map +0 -1
- package/dist/dist-t84Q_98w.mjs.map +0 -1
package/dist/memhtml.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
3
|
-
import {
|
|
2
|
+
import { $ as STATE_DB_PATH, A as IndexRecorder, B as IndexGit, C as ModelClient, D as EmbeddingsLive, E as Embeddings, F as makeRetrieval, G as MIGRATIONS_DIR, H as sanitizeFtsQuery, I as reinforce, J as Store, K as STATE_MIGRATIONS_DIR, L as Indexer, M as persistScanned, N as readWatermark, O as EMBED_DIM, P as Retrieval, R as makeIndexer, S as runDiscrimination, T as wrapAsData, U as DatabaseService, V as makeGitPort, W as makeDatabase, X as makeStore, Y as expandRoot, Z as INDEX_DB_PATH, _ as meta, a as parseSidecar, at as makeGit, b as isSleepPhase, c as generateArtifacts, ct as setMeta, d as allPaths, dt as fenceOpeningOf, et as STATE_SIDECAR_PATH, f as danglingEdges, ft as REINFORCE_SIGNALS, g as link, h as hrefFor, i as makeSleep, it as Git, j as makeIndexRecorder, k as EMBED_WATERMARK, l as DETECTION_PREFIX, lt as isValidDatetime, m as applyHeadEdits, n as scanTraceRoot, nt as initRepo, o as renderSidecar, ot as commitSubject, p as publishRows, pt as frameKeyOf, q as STATE_SCHEMA, r as Sleep, rt as readFileOrNull, s as archivedFormOf, st as checkMemory, t as mergeTailExtract, tt as attemptIo, u as accessRows, ut as closesFence, v as unlink, w as ModelClientLive, x as discriminationGate, y as SLEEP_PHASES, z as readIndexState } from "./dist-D73gfqLc.mjs";
|
|
3
|
+
import { $ as TASK_RELS, Dt as isTaskStatus, Et as WRITABLE_MEMORY_TYPES, G as InvalidMemory, Q as MEMORY_RELS, R as hasConsolidatorCredentials, Y as StorageFailure, a as makeConsolidator, et as isEdgeRel, lt as TASKS_SUBDIR, mt as normalizePath, ot as INBOX_DIR, q as ModelUnavailable, tt as relClassFor, wt as TASK_STATUSES } from "./dist-BCsav-EP.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { Config, Context, Effect, Layer, Logger } from "effect";
|
|
6
6
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
@@ -82,7 +82,7 @@ const CONFIG_VARS = [
|
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
name: "MEMHTML_AWS_REGION",
|
|
85
|
-
description: "The Bedrock region for embeddings and the sleep cycle's
|
|
85
|
+
description: "The Bedrock region for embeddings and the sleep cycle's model-calling phases.",
|
|
86
86
|
fallback: "us-east-1"
|
|
87
87
|
},
|
|
88
88
|
{
|
|
@@ -97,7 +97,7 @@ const CONFIG_VARS = [
|
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
name: "MEMHTML_LLM",
|
|
100
|
-
description: "`off` makes
|
|
100
|
+
description: "`off` makes every model-calling sleep phase report `no model bound` and stay `ok`, so a credential-free run is honest rather than red. `entity-resolution` still runs its deterministic normalization and character-overlap passes; the others do nothing.",
|
|
101
101
|
fallback: "on"
|
|
102
102
|
},
|
|
103
103
|
{
|
|
@@ -1643,6 +1643,32 @@ const setTaskStatus = (params) => Effect.gen(function* () {
|
|
|
1643
1643
|
};
|
|
1644
1644
|
});
|
|
1645
1645
|
/**
|
|
1646
|
+
* The `GLOB` pattern that matches a detected task's path, and nothing else.
|
|
1647
|
+
*
|
|
1648
|
+
* **The PATH is the discriminator, and `author` is deliberately not it.** `packages/sleep/src/tasks.ts`
|
|
1649
|
+
* records why the path carries the detection key: it survives `rm index.db && rebuild` with no
|
|
1650
|
+
* projection, it is collision-free by construction, and it costs no new meta in a CLOSED vocabulary.
|
|
1651
|
+
* `files.author` IS a real column and every detected task carries `agent:sleep` in it — but so does
|
|
1652
|
+
* every memory `trace-consolidation` and `arc-synthesis` write, and so would a task an operator opened
|
|
1653
|
+
* while impersonating the cycle. `author = 'agent:sleep'` is therefore necessary and not sufficient,
|
|
1654
|
+
* while the path is both. Adding the author predicate beside this one would look like defense in depth
|
|
1655
|
+
* and would actually be a second, weaker copy of the same test — and it would break the moment a
|
|
1656
|
+
* detector minted under a different author, which is a change the path would survive.
|
|
1657
|
+
*
|
|
1658
|
+
* `GLOB` rather than `LIKE`, and the character class is the reason. `LIKE 'areas/inbox/tasks/det-%'`
|
|
1659
|
+
* would match `det-nothex…` and `detonate-things.html`; the twelve `[0-9a-f]` positions are the same
|
|
1660
|
+
* shape `detectionKeyOf`'s regex asserts, so the two agree about what a detected path IS. Verified
|
|
1661
|
+
* against node:sqlite: the pattern matches a real detected path and an archived one, and rejects a
|
|
1662
|
+
* human `t-…` task, a non-hex stem, a short digest, and `detonate-`.
|
|
1663
|
+
*
|
|
1664
|
+
* The leading `*` covers the ARCHIVE. `archivePathFor` prefixes `archive/<year>/`, so a closed detected
|
|
1665
|
+
* task's path is `archive/2026/areas/inbox/tasks/det-…`, and `--detected --include-archived` has to
|
|
1666
|
+
* reach it or "what did the machine propose and what happened to it" is unanswerable. It also means the
|
|
1667
|
+
* pattern is anchored on the FILENAME rather than on the directory, which is correct: the digest prefix
|
|
1668
|
+
* is the claim, and `placementFor` owns where a task files.
|
|
1669
|
+
*/
|
|
1670
|
+
const DETECTED_TASK_GLOB = `*/${DETECTION_PREFIX}${"[0-9a-f]".repeat(12)}-*.html`;
|
|
1671
|
+
/**
|
|
1646
1672
|
* The task working set: a direct indexed scan, deliberately not retrieval.
|
|
1647
1673
|
*
|
|
1648
1674
|
* No RRF, no MMR, no embedding. A to-do list is not a ranking problem. An agent asking "what is
|
|
@@ -1700,6 +1726,20 @@ const listTasks = (params) => Effect.gen(function* () {
|
|
|
1700
1726
|
conditions.push("f.path > ?");
|
|
1701
1727
|
values.push(normalizePath(params.cursor));
|
|
1702
1728
|
}
|
|
1729
|
+
/**
|
|
1730
|
+
* A FILTER on the existing shape, not a new payload. Every row `task list` returns still carries
|
|
1731
|
+
* exactly the {@link TaskRow} fields, so `task.list` keeps its meaning and the append-only
|
|
1732
|
+
* discriminator rule in `envelope.ts` is untouched — nothing was added to a shipped shape and no
|
|
1733
|
+
* consumer's parse changes.
|
|
1734
|
+
*
|
|
1735
|
+
* A `detected: boolean` column per row was the alternative and it was declined. It would put the
|
|
1736
|
+
* same fact in two places (the path already says it) and it would make every caller of `task list`
|
|
1737
|
+
* parse a field only one flag's users read.
|
|
1738
|
+
*/
|
|
1739
|
+
if (params.detected === true) {
|
|
1740
|
+
conditions.push("f.path GLOB ?");
|
|
1741
|
+
values.push(DETECTED_TASK_GLOB);
|
|
1742
|
+
}
|
|
1703
1743
|
const rows = yield* db.all(`SELECT f.path, f.title, f.task_status, f.due_at, f.workspace, f.archived, f.updated_at,
|
|
1704
1744
|
(SELECT group_concat(b.src_path, char(10)) FROM (
|
|
1705
1745
|
SELECT e.src_path AS src_path FROM edges e
|
|
@@ -2506,6 +2546,12 @@ const COMMANDS = [
|
|
|
2506
2546
|
type: "boolean",
|
|
2507
2547
|
description: "Include finished tasks. `done` archives, so they are otherwise absent.",
|
|
2508
2548
|
default: false
|
|
2549
|
+
},
|
|
2550
|
+
{
|
|
2551
|
+
name: "detected",
|
|
2552
|
+
type: "boolean",
|
|
2553
|
+
description: "Only tasks the sleep cycle detected, never ones opened by hand. The machine's queue: each is a proposal carrying the evidence it was detected from.",
|
|
2554
|
+
default: false
|
|
2509
2555
|
}
|
|
2510
2556
|
],
|
|
2511
2557
|
responseTypes: ["task.list"]
|
|
@@ -2593,7 +2639,13 @@ const COMMANDS = [
|
|
|
2593
2639
|
},
|
|
2594
2640
|
{
|
|
2595
2641
|
name: "sleep run",
|
|
2596
|
-
|
|
2642
|
+
/**
|
|
2643
|
+
* The count is DERIVED from `SLEEP_PHASES`, not typed. Both strings used to spell `15` by hand,
|
|
2644
|
+
* and adding a sixteenth phase left `AGENTS.md` and `memhtml manifest` asserting a number the list
|
|
2645
|
+
* beside them contradicted — visible only because the doc drift gate compares generated bytes, and
|
|
2646
|
+
* only for the one of the two that also prints the names.
|
|
2647
|
+
*/
|
|
2648
|
+
summary: `The nightly curation cycle: ${SLEEP_PHASES.length} phases, each an isolated commit on a review branch.`,
|
|
2597
2649
|
args: [],
|
|
2598
2650
|
flags: [
|
|
2599
2651
|
{
|
|
@@ -2604,7 +2656,7 @@ const COMMANDS = [
|
|
|
2604
2656
|
{
|
|
2605
2657
|
name: "phases",
|
|
2606
2658
|
type: "string",
|
|
2607
|
-
description: `Comma-separated subset. All
|
|
2659
|
+
description: `Comma-separated subset. All ${SLEEP_PHASES.length} by default: ${SLEEP_PHASES.join(", ")}.`
|
|
2608
2660
|
},
|
|
2609
2661
|
{
|
|
2610
2662
|
name: "dry-run",
|
|
@@ -2884,7 +2936,7 @@ const GUIDE_TOPICS = GUIDE.map((block) => block.topic);
|
|
|
2884
2936
|
*/
|
|
2885
2937
|
const buildManifest = () => ({
|
|
2886
2938
|
name: "memhtml",
|
|
2887
|
-
version: "0.
|
|
2939
|
+
version: "0.4.0",
|
|
2888
2940
|
summary: "Read, write, and curate the git-backed memory repo.",
|
|
2889
2941
|
apiVersion: "1",
|
|
2890
2942
|
/**
|
|
@@ -3983,7 +4035,7 @@ const runExec = (input) => Effect.gen(function* () {
|
|
|
3983
4035
|
catch: (cause) => StorageFailure.make({ operation: `exec.sandbox-load: ${String(cause)}` })
|
|
3984
4036
|
});
|
|
3985
4037
|
const { mountReadOnlyRoots } = yield* Effect.tryPromise({
|
|
3986
|
-
try: () => import("./dist-
|
|
4038
|
+
try: () => import("./dist-DuzGralO.mjs"),
|
|
3987
4039
|
catch: (cause) => StorageFailure.make({ operation: `exec.mount-load: ${String(cause)}` })
|
|
3988
4040
|
});
|
|
3989
4041
|
const helperSource = yield* Effect.tryPromise({
|
|
@@ -4128,7 +4180,7 @@ const execCommand = (input) => Effect.gen(function* () {
|
|
|
4128
4180
|
* would not cover.
|
|
4129
4181
|
*/
|
|
4130
4182
|
const { pinCorpusSnapshot } = yield* Effect.tryPromise({
|
|
4131
|
-
try: () => import("./dist-
|
|
4183
|
+
try: () => import("./dist-DuzGralO.mjs"),
|
|
4132
4184
|
catch: (cause) => StorageFailure.make({ operation: `exec.mount-load: ${String(cause)}` })
|
|
4133
4185
|
});
|
|
4134
4186
|
const snapshot = yield* Effect.acquireRelease(Effect.tryPromise({
|
|
@@ -4330,7 +4382,7 @@ const indexReport = () => Effect.gen(function* () {
|
|
|
4330
4382
|
});
|
|
4331
4383
|
const count = (db, sql) => db.get(sql).pipe(Effect.map((row) => row?.n ?? 0), Effect.orElseSucceed(() => 0));
|
|
4332
4384
|
/**
|
|
4333
|
-
* A `--phases` value as a validated phase list, or `undefined` for "all
|
|
4385
|
+
* A `--phases` value as a validated phase list, or `undefined` for "all sixteen".
|
|
4334
4386
|
*
|
|
4335
4387
|
* An unknown phase is rejected instead of dropped silently. A run asked for `--phases dedup,compress`
|
|
4336
4388
|
* with a typo in the first name would otherwise execute only the second. `dedup-merge` is a hard
|
|
@@ -4644,7 +4696,8 @@ const dispatch = (parsed, applyOps = []) => {
|
|
|
4644
4696
|
dueBefore: str(parsed, "due-before"),
|
|
4645
4697
|
limit: int(parsed, "limit"),
|
|
4646
4698
|
cursor: str(parsed, "cursor"),
|
|
4647
|
-
includeArchived: bool(parsed, "include-archived", false)
|
|
4699
|
+
includeArchived: bool(parsed, "include-archived", false),
|
|
4700
|
+
detected: bool(parsed, "detected", false)
|
|
4648
4701
|
})];
|
|
4649
4702
|
});
|
|
4650
4703
|
case "index rebuild": return Effect.gen(function* () {
|