pi-blackhole 0.4.2 → 0.4.3

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 (87) hide show
  1. package/README.md +15 -0
  2. package/dist/index.js +11660 -0
  3. package/dist/index.js.map +1 -0
  4. package/example-config.json +1 -1
  5. package/index.ts +37 -63
  6. package/package.json +21 -9
  7. package/src/commands/cleanup.ts +279 -240
  8. package/src/commands/memory.ts +236 -184
  9. package/src/commands/pi-vcc.ts +202 -152
  10. package/src/commands/vcc-recall.ts +126 -95
  11. package/src/core/brief.ts +167 -33
  12. package/src/core/build-sections.ts +8 -2
  13. package/src/core/config-env.ts +117 -0
  14. package/src/core/content.ts +31 -7
  15. package/src/core/drill-down.ts +41 -11
  16. package/src/core/filter-noise.ts +9 -3
  17. package/src/core/format-recall.ts +15 -6
  18. package/src/core/format.ts +14 -4
  19. package/src/core/lineage.ts +9 -3
  20. package/src/core/load-messages.ts +24 -5
  21. package/src/core/normalize.ts +38 -14
  22. package/src/core/recall-scope.ts +11 -3
  23. package/src/core/render-entries.ts +22 -6
  24. package/src/core/sanitize.ts +5 -1
  25. package/src/core/search-entries.ts +111 -19
  26. package/src/core/settings.ts +1 -3
  27. package/src/core/summarize.ts +42 -21
  28. package/src/core/unified-config.ts +549 -411
  29. package/src/extract/commits.ts +4 -2
  30. package/src/extract/files.ts +10 -5
  31. package/src/extract/goals.ts +7 -2
  32. package/src/hooks/before-compact.ts +210 -88
  33. package/src/om/agents/dropper/agent.ts +380 -265
  34. package/src/om/agents/dropper/coverage.ts +102 -82
  35. package/src/om/agents/observer/agent.ts +242 -206
  36. package/src/om/agents/reflector/agent.ts +212 -153
  37. package/src/om/cleanup.ts +239 -218
  38. package/src/om/clipboard.ts +59 -51
  39. package/src/om/compaction-trigger.ts +448 -333
  40. package/src/om/config.ts +13 -6
  41. package/src/om/configure-overlay.ts +518 -355
  42. package/src/om/consolidation.ts +1460 -953
  43. package/src/om/cooldown.ts +75 -65
  44. package/src/om/debug-log.ts +86 -68
  45. package/src/om/ids.ts +1 -1
  46. package/src/om/ledger/fold.ts +89 -78
  47. package/src/om/ledger/progress.ts +181 -153
  48. package/src/om/ledger/projection.ts +248 -185
  49. package/src/om/ledger/recall.ts +247 -196
  50. package/src/om/ledger/render-summary.ts +79 -50
  51. package/src/om/ledger/types.ts +146 -117
  52. package/src/om/model-budget.ts +23 -13
  53. package/src/om/pending.ts +243 -179
  54. package/src/om/provider-stream.ts +52 -7
  55. package/src/om/retryable-error.ts +12 -16
  56. package/src/om/reverse-recall.ts +97 -91
  57. package/src/om/runtime.ts +474 -375
  58. package/src/om/serialize.ts +190 -166
  59. package/src/om/status-overlay.ts +246 -195
  60. package/src/om/tokens.ts +28 -21
  61. package/src/pi-base/blackhole-settings.ts +437 -0
  62. package/src/pi-base/config-manager.ts +440 -0
  63. package/src/pi-base/config.ts +469 -0
  64. package/src/pi-base/env.ts +43 -0
  65. package/src/pi-base/paths.ts +47 -0
  66. package/src/pi-base/settings/body.ts +1648 -0
  67. package/src/pi-base/settings/fields/action.ts +43 -0
  68. package/src/pi-base/settings/fields/boolean.ts +47 -0
  69. package/src/pi-base/settings/fields/custom.ts +72 -0
  70. package/src/pi-base/settings/fields/enum.ts +310 -0
  71. package/src/pi-base/settings/fields/index.ts +46 -0
  72. package/src/pi-base/settings/fields/model.ts +452 -0
  73. package/src/pi-base/settings/fields/string.ts +527 -0
  74. package/src/pi-base/settings/fields/text.ts +115 -0
  75. package/src/pi-base/settings/frame.ts +197 -0
  76. package/src/pi-base/settings/index.ts +77 -0
  77. package/src/pi-base/settings/inline-edit.ts +313 -0
  78. package/src/pi-base/settings/modal.ts +152 -0
  79. package/src/pi-base/settings/types.ts +500 -0
  80. package/src/pi-base/settings/validate-field.ts +113 -0
  81. package/src/pi-base/shell.ts +117 -0
  82. package/src/pi-base/types.ts +6 -0
  83. package/src/pi-base/ui.ts +32 -0
  84. package/src/tools/recall.ts +347 -225
  85. package/src/types.ts +20 -3
  86. package/tsup.config.ts +23 -0
  87. package/vitest.config.ts +15 -15
@@ -4,108 +4,114 @@
4
4
  * This is the vcc→OM direction: when expanding session entries, look up
5
5
  * observations whose sourceEntryIds contain those entry IDs.
6
6
  */
7
- import {
8
- indexLedger,
9
- type Entry,
10
- } from "./ledger/recall.js";
7
+ import { indexLedger, type Entry } from "./ledger/recall.js";
11
8
  import { type RenderedEntry } from "../core/render-entries.js";
12
9
 
13
10
  // ── Types ─────────────────────────────────────────────────────────────────
14
11
 
15
12
  export interface RelatedObservation {
16
- memoryId: string;
17
- content: string;
18
- timestamp: string;
19
- relevance: string;
20
- status: "active" | "dropped";
21
- matchedEntryIds: string[];
13
+ memoryId: string;
14
+ content: string;
15
+ timestamp: string;
16
+ relevance: string;
17
+ status: "active" | "dropped";
18
+ matchedEntryIds: string[];
22
19
  }
23
20
 
24
21
  export interface RelatedReflection {
25
- memoryId: string;
26
- content: string;
22
+ memoryId: string;
23
+ content: string;
27
24
  }
28
25
 
29
26
  // ── Lookup ────────────────────────────────────────────────────────────────
30
27
 
31
28
  export function findObservationsForEntryIds(
32
- entries: Entry[],
33
- targetEntryIds: string[],
29
+ entries: Entry[],
30
+ targetEntryIds: string[],
34
31
  ): RelatedObservation[] {
35
- if (targetEntryIds.length === 0) return [];
36
- const { observations, droppedIds } = indexLedger(entries);
37
- const targetSet = new Set(targetEntryIds);
32
+ if (targetEntryIds.length === 0) return [];
33
+ const { observations, droppedIds } = indexLedger(entries);
34
+ const targetSet = new Set(targetEntryIds);
38
35
 
39
- const result: RelatedObservation[] = [];
40
- for (const indexed of observations) {
41
- const matched = indexed.observation.sourceEntryIds.filter((id) => targetSet.has(id));
42
- if (matched.length > 0) {
43
- result.push({
44
- memoryId: indexed.observation.id,
45
- content: indexed.observation.content,
46
- timestamp: indexed.observation.timestamp,
47
- relevance: indexed.observation.relevance,
48
- status: droppedIds.has(indexed.observation.id) ? "dropped" : "active",
49
- matchedEntryIds: matched,
50
- });
51
- }
52
- }
53
- return result;
36
+ const result: RelatedObservation[] = [];
37
+ for (const indexed of observations) {
38
+ const matched = indexed.observation.sourceEntryIds.filter((id) =>
39
+ targetSet.has(id),
40
+ );
41
+ if (matched.length > 0) {
42
+ result.push({
43
+ memoryId: indexed.observation.id,
44
+ content: indexed.observation.content,
45
+ timestamp: indexed.observation.timestamp,
46
+ relevance: indexed.observation.relevance,
47
+ status: droppedIds.has(indexed.observation.id) ? "dropped" : "active",
48
+ matchedEntryIds: matched,
49
+ });
50
+ }
51
+ }
52
+ return result;
54
53
  }
55
54
 
56
55
  export function findReflectionsForEntryIds(
57
- entries: Entry[],
58
- targetEntryIds: string[],
56
+ entries: Entry[],
57
+ targetEntryIds: string[],
59
58
  ): RelatedReflection[] {
60
- if (targetEntryIds.length === 0) return [];
61
- const { reflections, observations } = indexLedger(entries);
62
- // Reflections don't directly reference entry IDs — they reference observation IDs.
63
- // So we only match indirectly: first find observations for these entry IDs,
64
- // then find reflections that support those observations.
65
- const targetSet = new Set(targetEntryIds);
66
- const matchingObsIds = new Set<string>();
67
- for (const indexed of observations) {
68
- if (indexed.observation.sourceEntryIds.some((id) => targetSet.has(id))) {
69
- matchingObsIds.add(indexed.observation.id);
70
- }
71
- }
72
- if (matchingObsIds.size === 0) return [];
73
- return reflections
74
- .filter((r) => r.reflection.supportingObservationIds.some((id) => matchingObsIds.has(id)))
75
- .map((r) => ({
76
- memoryId: r.reflection.id,
77
- content: r.reflection.content,
78
- }));
59
+ if (targetEntryIds.length === 0) return [];
60
+ const { reflections, observations } = indexLedger(entries);
61
+ // Reflections don't directly reference entry IDs — they reference observation IDs.
62
+ // So we only match indirectly: first find observations for these entry IDs,
63
+ // then find reflections that support those observations.
64
+ const targetSet = new Set(targetEntryIds);
65
+ const matchingObsIds = new Set<string>();
66
+ for (const indexed of observations) {
67
+ if (indexed.observation.sourceEntryIds.some((id) => targetSet.has(id))) {
68
+ matchingObsIds.add(indexed.observation.id);
69
+ }
70
+ }
71
+ if (matchingObsIds.size === 0) return [];
72
+ return reflections
73
+ .filter((r) =>
74
+ r.reflection.supportingObservationIds.some((id) =>
75
+ matchingObsIds.has(id),
76
+ ),
77
+ )
78
+ .map((r) => ({
79
+ memoryId: r.reflection.id,
80
+ content: r.reflection.content,
81
+ }));
79
82
  }
80
83
 
81
84
  // ── Formatters ────────────────────────────────────────────────────────────
82
85
 
83
86
  export function formatRelatedObservations(
84
- observations: RelatedObservation[],
85
- reflections: RelatedReflection[],
87
+ observations: RelatedObservation[],
88
+ reflections: RelatedReflection[],
86
89
  ): string {
87
- const parts: string[] = [];
90
+ const parts: string[] = [];
88
91
 
89
- if (observations.length > 0) {
90
- parts.push("Related observations:");
91
- for (const obs of observations) {
92
- const dropped = obs.status === "dropped" ? " [dropped]" : "";
93
- const entryRefs = obs.matchedEntryIds.length > 0
94
- ? ` (${obs.matchedEntryIds.join(", ")})`
95
- : "";
96
- parts.push(` [${obs.memoryId}]${dropped} ${obs.timestamp} [${obs.relevance}] ${obs.content}${entryRefs}`);
97
- }
98
- }
92
+ if (observations.length > 0) {
93
+ parts.push("Related observations:");
94
+ for (const obs of observations) {
95
+ const dropped = obs.status === "dropped" ? " [dropped]" : "";
96
+ const entryRefs =
97
+ obs.matchedEntryIds.length > 0
98
+ ? ` (${obs.matchedEntryIds.join(", ")})`
99
+ : "";
100
+ parts.push(
101
+ ` [${obs.memoryId}]${dropped} ${obs.timestamp} [${obs.relevance}] ${obs.content}${entryRefs}`,
102
+ );
103
+ }
104
+ }
99
105
 
100
- if (reflections.length > 0) {
101
- if (parts.length > 0) parts.push("");
102
- parts.push("Related reflections:");
103
- for (const ref of reflections) {
104
- parts.push(` [${ref.memoryId}] ${ref.content}`);
105
- }
106
- }
106
+ if (reflections.length > 0) {
107
+ if (parts.length > 0) parts.push("");
108
+ parts.push("Related reflections:");
109
+ for (const ref of reflections) {
110
+ parts.push(` [${ref.memoryId}] ${ref.content}`);
111
+ }
112
+ }
107
113
 
108
- return parts.join("\n");
114
+ return parts.join("\n");
109
115
  }
110
116
 
111
117
  /**
@@ -113,25 +119,25 @@ export function formatRelatedObservations(
113
119
  * Used to annotate source entries with their #N indices.
114
120
  */
115
121
  export function buildIndexMap(rendered: RenderedEntry[]): Map<string, number> {
116
- const map = new Map<string, number>();
117
- for (const entry of rendered) {
118
- if (entry.id && !map.has(entry.id)) {
119
- map.set(entry.id, entry.index);
120
- }
121
- }
122
- return map;
122
+ const map = new Map<string, number>();
123
+ for (const entry of rendered) {
124
+ if (entry.id && !map.has(entry.id)) {
125
+ map.set(entry.id, entry.index);
126
+ }
127
+ }
128
+ return map;
123
129
  }
124
130
 
125
131
  export function formatEntryIndexAnnotation(
126
- sourceEntryIds: string[],
127
- idToIndex: Map<string, number>,
132
+ sourceEntryIds: string[],
133
+ idToIndex: Map<string, number>,
128
134
  ): string {
129
- const indices: number[] = [];
130
- for (const id of sourceEntryIds) {
131
- const idx = idToIndex.get(id);
132
- if (idx !== undefined) indices.push(idx);
133
- }
134
- if (indices.length === 0) return "";
135
- indices.sort((a, b) => a - b);
136
- return `(at index #${indices.join(", #")})`;
135
+ const indices: number[] = [];
136
+ for (const id of sourceEntryIds) {
137
+ const idx = idToIndex.get(id);
138
+ if (idx !== undefined) indices.push(idx);
139
+ }
140
+ if (indices.length === 0) return "";
141
+ indices.sort((a, b) => a - b);
142
+ return `(at index #${indices.join(", #")})`;
137
143
  }