threadnote 0.7.9 → 0.7.10

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.
@@ -9547,6 +9547,40 @@ async function runCompact(config, options) {
9547
9547
  await runForget(config, action.uri, { dryRun: false });
9548
9548
  }
9549
9549
  }
9550
+ async function runCompactDiagnostics(config, options) {
9551
+ const project = normalizeOptionalMetadata2(options.project);
9552
+ if (!project) {
9553
+ throw new Error("Provide --project for scoped memory hygiene.");
9554
+ }
9555
+ const topic = normalizeOptionalMetadata2(options.topic);
9556
+ const records = await scopedCompactRecords(config, {
9557
+ kind: options.kind,
9558
+ project
9559
+ });
9560
+ const activeRecords = records.filter((record) => record.metadata.status === "active");
9561
+ const matchingRecords = activeRecords.filter((record) => topic === void 0 || topicForRecord(record) === topic);
9562
+ const counts = /* @__PURE__ */ new Map();
9563
+ for (const record of matchingRecords) {
9564
+ const kind = record.metadata.kind;
9565
+ if (kind === "durable" || kind === "handoff" || kind === "incident") {
9566
+ counts.set(kind, (counts.get(kind) ?? 0) + 1);
9567
+ }
9568
+ }
9569
+ console.log(
9570
+ [
9571
+ "Scope summary:",
9572
+ `- project: ${project}`,
9573
+ `- topic: ${topic ?? "(all)"}`,
9574
+ `- kind: ${options.kind ?? "(handoff, durable, incident)"}`,
9575
+ `- stable records read: ${records.length}`,
9576
+ `- active records in project: ${activeRecords.length}`,
9577
+ `- active records matching topic: ${matchingRecords.length}`,
9578
+ `- matching by kind: ${formatKindCounts(counts)}`,
9579
+ "- skipped by design: archived memories, shared memories, preferences, smoke records, seeded resources, and non-stable timestamped/global paths",
9580
+ ""
9581
+ ].join("\n")
9582
+ );
9583
+ }
9550
9584
  async function scopedCompactRecords(config, options) {
9551
9585
  const kinds = options.kind ? [options.kind] : ["handoff", "durable", "incident"];
9552
9586
  const records = [];
@@ -9575,6 +9609,9 @@ async function scopedCompactRecords(config, options) {
9575
9609
  }
9576
9610
  return records;
9577
9611
  }
9612
+ function formatKindCounts(counts) {
9613
+ return ["handoff", "durable", "incident"].map((kind) => `${kind} ${counts.get(kind) ?? 0}`).join(", ");
9614
+ }
9578
9615
  async function readMemoryRecordsByUri(config, uris) {
9579
9616
  const records = [];
9580
9617
  for (const uri of uris) {
@@ -12810,7 +12847,12 @@ var STATIC_FILES = {
12810
12847
  "/index.html": { contentType: "text/html; charset=utf-8", path: "index.html" },
12811
12848
  "/app.css": { contentType: "text/css; charset=utf-8", path: "app.css" },
12812
12849
  "/app.js": { contentType: "text/javascript; charset=utf-8", path: "app.js" },
12813
- "/threadnote-logo.svg": { contentType: "image/svg+xml; charset=utf-8", path: "threadnote-logo.svg", root: "docs" }
12850
+ "/threadnote-logo.svg": { contentType: "image/svg+xml; charset=utf-8", path: "threadnote-logo.svg", root: "docs" },
12851
+ "/threadnote-logo-inverted.svg": {
12852
+ contentType: "image/svg+xml; charset=utf-8",
12853
+ path: "threadnote-logo-inverted.svg",
12854
+ root: "docs"
12855
+ }
12814
12856
  };
12815
12857
  async function runManage(config, options) {
12816
12858
  const token = (0, import_node_crypto2.randomBytes)(24).toString("base64url");
@@ -13018,7 +13060,14 @@ async function handleRequest(context, request, response) {
13018
13060
  if (body.apply === true) {
13019
13061
  requireConfirm(body);
13020
13062
  }
13021
- writeJson(response, 200, await runCaptured(() => runCompact(context.config, body)));
13063
+ writeJson(
13064
+ response,
13065
+ 200,
13066
+ await runCaptured(async () => {
13067
+ await runCompactDiagnostics(context.config, body);
13068
+ await runCompact(context.config, body);
13069
+ })
13070
+ );
13022
13071
  return;
13023
13072
  case "/api/recall":
13024
13073
  writeJson(
package/manager/app.css CHANGED
@@ -196,9 +196,9 @@ body.is-resizing-sidebar * {
196
196
 
197
197
  .brand-logo {
198
198
  flex: 0 0 auto;
199
- height: 42px;
199
+ height: 86px;
200
200
  object-fit: contain;
201
- width: 42px;
201
+ width: 86px;
202
202
  }
203
203
 
204
204
  .brand h1,
@@ -264,7 +264,7 @@ body.is-resizing-sidebar * {
264
264
 
265
265
  .tree summary {
266
266
  cursor: pointer;
267
- grid-template-columns: 14px minmax(0, 1fr);
267
+ grid-template-columns: 18px 14px minmax(0, 1fr);
268
268
  list-style: none;
269
269
  }
270
270
 
@@ -380,6 +380,10 @@ body.is-resizing-sidebar * {
380
380
  height: 100%;
381
381
  }
382
382
 
383
+ .health-panel.panel.is-active {
384
+ overflow: auto;
385
+ }
386
+
383
387
  .content-grid,
384
388
  .split {
385
389
  display: grid;
@@ -766,6 +770,34 @@ dd {
766
770
  overflow: auto;
767
771
  }
768
772
 
773
+ .loading-row {
774
+ align-items: center;
775
+ background: var(--panel-alt);
776
+ border: 1px solid var(--accent-line);
777
+ border-radius: 8px;
778
+ color: var(--text);
779
+ display: inline-flex;
780
+ gap: 8px;
781
+ margin-top: 12px;
782
+ padding: 9px 12px;
783
+ }
784
+
785
+ .spinner {
786
+ animation: spin 0.8s linear infinite;
787
+ border: 2px solid var(--accent-line);
788
+ border-top-color: var(--accent);
789
+ border-radius: 50%;
790
+ display: inline-block;
791
+ height: 14px;
792
+ width: 14px;
793
+ }
794
+
795
+ @keyframes spin {
796
+ to {
797
+ transform: rotate(360deg);
798
+ }
799
+ }
800
+
769
801
  .output {
770
802
  background: var(--code-bg);
771
803
  border-radius: var(--radius);
@@ -779,7 +811,9 @@ dd {
779
811
 
780
812
  .doctor-output {
781
813
  margin: 12px 0 0;
814
+ max-height: min(34dvh, 360px);
782
815
  min-height: 120px;
816
+ overflow: auto;
783
817
  }
784
818
 
785
819
  .uri-list {
@@ -819,6 +853,24 @@ dd {
819
853
  z-index: 10;
820
854
  }
821
855
 
856
+ .busy-overlay {
857
+ align-items: center;
858
+ background: rgba(5, 5, 8, 0.34);
859
+ display: flex;
860
+ inset: 0;
861
+ justify-content: center;
862
+ position: fixed;
863
+ z-index: 20;
864
+ }
865
+
866
+ .busy-panel {
867
+ background: #050508;
868
+ border: 1px solid var(--accent-line);
869
+ border-radius: 8px;
870
+ color: var(--text);
871
+ padding: 12px 16px;
872
+ }
873
+
822
874
  .danger-text {
823
875
  color: var(--danger);
824
876
  }