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/dist/memhtml.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { $ as STATE_SIDECAR_PATH, A as makeIndexRecorder, B as makeGitPort, C as ModelClientLive, D as EMBED_DIM, E as EmbeddingsLive, F as reinforce, G as STATE_MIGRATIONS_DIR, H as DatabaseService, I as Indexer, J as expandRoot, K as STATE_SCHEMA, L as makeIndexer, M as readWatermark, N as Retrieval, O as EMBED_WATERMARK, P as makeRetrieval, Q as STATE_DB_PATH, R as readIndexState, S as ModelClient, T as Embeddings, U as makeDatabase, V as sanitizeFtsQuery, W as MIGRATIONS_DIR, X as INDEX_DB_PATH, Y as makeStore, _ as unlink, a as parseSidecar, at as commitSubject, b as discriminationGate, c as generateArtifacts, ct as isValidDatetime, d as danglingEdges, dt as REINFORCE_SIGNALS, et as attemptIo, f as publishRows, ft as frameKeyOf, g as meta, h as link, i as makeSleep, it as makeGit, j as persistScanned, k as IndexRecorder, l as accessRows, lt as closesFence, m as hrefFor, n as scanTraceRoot, nt as readFileOrNull, o as renderSidecar, ot as checkMemory, p as applyHeadEdits, q as Store, r as Sleep, rt as Git, s as archivedFormOf, st as setMeta, t as mergeTailExtract, tt as initRepo, u as allPaths, ut as fenceOpeningOf, v as SLEEP_PHASES, w as wrapAsData, x as runDiscrimination, y as isSleepPhase, z as IndexGit } from "./dist-Uj47oBRC.mjs";
3
- import { B as ModelUnavailable, G as MEMORY_RELS, H as StorageFailure, J as relClassFor, K as TASK_RELS, N as hasConsolidatorCredentials, Q as INBOX_DIR, R as InvalidMemory, gt as TASK_STATUSES, i as makeConsolidator, ot as normalizePath, q as isEdgeRel, tt as TASKS_SUBDIR, vt as WRITABLE_MEMORY_TYPES, yt as isTaskStatus } from "./dist-t84Q_98w.mjs";
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 four LLM phases.",
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 the four LLM sleep phases report `no model bound` and stay `ok`, so a credential-free run is honest rather than red.",
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
- summary: "The nightly curation cycle: 15 phases, each an isolated commit on a review branch.",
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 15 by default: ${SLEEP_PHASES.join(", ")}.`
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.2.5",
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-Dj-MYf9q.mjs"),
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-Dj-MYf9q.mjs"),
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 fifteen".
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* () {