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
@@ -1,135 +1,163 @@
1
1
  import { estimateEntryTokens } from "../tokens.js";
2
2
  import {
3
- OM_OBSERVATIONS_DROPPED,
4
- OM_OBSERVATIONS_RECORDED,
5
- OM_REFLECTIONS_RECORDED,
6
- isObservationsRecordedData,
7
- isReflectionsRecordedData,
8
- type Entry,
9
- type Observation,
10
- type Reflection,
11
- type V3MemoryCustomType,
3
+ OM_OBSERVATIONS_DROPPED,
4
+ OM_OBSERVATIONS_RECORDED,
5
+ OM_REFLECTIONS_RECORDED,
6
+ isObservationsRecordedData,
7
+ isReflectionsRecordedData,
8
+ type Entry,
9
+ type Observation,
10
+ type Reflection,
11
+ type V3MemoryCustomType,
12
12
  } from "./types.js";
13
13
 
14
- const SOURCE_ENTRY_TYPES = new Set(["message", "custom_message", "branch_summary"]);
14
+ const SOURCE_ENTRY_TYPES = new Set([
15
+ "message",
16
+ "custom_message",
17
+ "branch_summary",
18
+ ]);
15
19
 
16
20
  export function isSourceEntry(entry: Entry): boolean {
17
- return SOURCE_ENTRY_TYPES.has(entry.type);
21
+ return SOURCE_ENTRY_TYPES.has(entry.type);
18
22
  }
19
23
 
20
24
  export function entryIndexById(entries: Entry[]): Map<string, number> {
21
- const idToIndex = new Map<string, number>();
22
- for (let i = 0; i < entries.length; i++) idToIndex.set(entries[i].id, i);
23
- return idToIndex;
25
+ const idToIndex = new Map<string, number>();
26
+ for (let i = 0; i < entries.length; i++) idToIndex.set(entries[i].id, i);
27
+ return idToIndex;
24
28
  }
25
29
 
26
- export function entryIndexForId(entries: Entry[], entryId: string | undefined): number {
27
- if (!entryId) return -1;
28
- const idx = entryIndexById(entries).get(entryId);
29
- return idx ?? -1;
30
+ export function entryIndexForId(
31
+ entries: Entry[],
32
+ entryId: string | undefined,
33
+ ): number {
34
+ if (!entryId) return -1;
35
+ const idx = entryIndexById(entries).get(entryId);
36
+ return idx ?? -1;
30
37
  }
31
38
 
32
39
  function isObject(value: unknown): value is Record<string, unknown> {
33
- return typeof value === "object" && value !== null;
40
+ return typeof value === "object" && value !== null;
34
41
  }
35
42
 
36
43
  function isNonEmptyArray(value: unknown): value is unknown[] {
37
- return Array.isArray(value) && value.length > 0;
38
- }
39
-
40
- function isValidCoverageEntry(entry: Entry, customType: V3MemoryCustomType): entry is Entry & { data: { coversUpToId: string } } {
41
- if (entry.type !== "custom" || entry.customType !== customType) return false;
42
- if (!isObject(entry.data) || typeof entry.data.coversUpToId !== "string") return false;
43
-
44
- if (customType === OM_OBSERVATIONS_RECORDED) return isNonEmptyArray(entry.data.observations);
45
- if (customType === OM_REFLECTIONS_RECORDED) return isNonEmptyArray(entry.data.reflections);
46
- return isNonEmptyArray(entry.data.observationIds);
47
- }
48
-
49
- export function latestCoverageIndex(entries: Entry[], customType: V3MemoryCustomType): number {
50
- const idToIndex = entryIndexById(entries);
51
- let latest = -1;
52
-
53
- for (const entry of entries) {
54
- if (!isValidCoverageEntry(entry, customType)) continue;
55
- const coveredIndex = idToIndex.get(entry.data.coversUpToId);
56
- if (coveredIndex === undefined) continue;
57
- if (coveredIndex > latest) latest = coveredIndex;
58
- }
59
-
60
- return latest;
61
- }
62
-
63
- export function latestCoverageMarkerId(entries: Entry[], customType: V3MemoryCustomType): string | undefined {
64
- const idToIndex = entryIndexById(entries);
65
- let latestIndex = -1;
66
- let latestMarkerId: string | undefined;
67
-
68
- for (const entry of entries) {
69
- if (!isValidCoverageEntry(entry, customType)) continue;
70
- const coveredIndex = idToIndex.get(entry.data.coversUpToId);
71
- if (coveredIndex === undefined) continue;
72
- if (coveredIndex > latestIndex) {
73
- latestIndex = coveredIndex;
74
- latestMarkerId = entry.data.coversUpToId;
75
- }
76
- }
77
-
78
- return latestMarkerId;
79
- }
80
-
81
- export function earlierCoverageMarkerId(entries: Entry[], firstId: string | undefined, secondId: string | undefined): string | undefined {
82
- if (!firstId) return secondId;
83
- if (!secondId) return firstId;
84
-
85
- const idToIndex = entryIndexById(entries);
86
- const firstIndex = idToIndex.get(firstId);
87
- const secondIndex = idToIndex.get(secondId);
88
- if (firstIndex === undefined) return secondIndex === undefined ? undefined : secondId;
89
- if (secondIndex === undefined) return firstId;
90
- return firstIndex <= secondIndex ? firstId : secondId;
44
+ return Array.isArray(value) && value.length > 0;
45
+ }
46
+
47
+ function isValidCoverageEntry(
48
+ entry: Entry,
49
+ customType: V3MemoryCustomType,
50
+ ): entry is Entry & { data: { coversUpToId: string } } {
51
+ if (entry.type !== "custom" || entry.customType !== customType) return false;
52
+ if (!isObject(entry.data) || typeof entry.data.coversUpToId !== "string")
53
+ return false;
54
+
55
+ if (customType === OM_OBSERVATIONS_RECORDED)
56
+ return isNonEmptyArray(entry.data.observations);
57
+ if (customType === OM_REFLECTIONS_RECORDED)
58
+ return isNonEmptyArray(entry.data.reflections);
59
+ return isNonEmptyArray(entry.data.observationIds);
60
+ }
61
+
62
+ export function latestCoverageIndex(
63
+ entries: Entry[],
64
+ customType: V3MemoryCustomType,
65
+ ): number {
66
+ const idToIndex = entryIndexById(entries);
67
+ let latest = -1;
68
+
69
+ for (const entry of entries) {
70
+ if (!isValidCoverageEntry(entry, customType)) continue;
71
+ const coveredIndex = idToIndex.get(entry.data.coversUpToId);
72
+ if (coveredIndex === undefined) continue;
73
+ if (coveredIndex > latest) latest = coveredIndex;
74
+ }
75
+
76
+ return latest;
77
+ }
78
+
79
+ export function latestCoverageMarkerId(
80
+ entries: Entry[],
81
+ customType: V3MemoryCustomType,
82
+ ): string | undefined {
83
+ const idToIndex = entryIndexById(entries);
84
+ let latestIndex = -1;
85
+ let latestMarkerId: string | undefined;
86
+
87
+ for (const entry of entries) {
88
+ if (!isValidCoverageEntry(entry, customType)) continue;
89
+ const coveredIndex = idToIndex.get(entry.data.coversUpToId);
90
+ if (coveredIndex === undefined) continue;
91
+ if (coveredIndex > latestIndex) {
92
+ latestIndex = coveredIndex;
93
+ latestMarkerId = entry.data.coversUpToId;
94
+ }
95
+ }
96
+
97
+ return latestMarkerId;
98
+ }
99
+
100
+ export function earlierCoverageMarkerId(
101
+ entries: Entry[],
102
+ firstId: string | undefined,
103
+ secondId: string | undefined,
104
+ ): string | undefined {
105
+ if (!firstId) return secondId;
106
+ if (!secondId) return firstId;
107
+
108
+ const idToIndex = entryIndexById(entries);
109
+ const firstIndex = idToIndex.get(firstId);
110
+ const secondIndex = idToIndex.get(secondId);
111
+ if (firstIndex === undefined)
112
+ return secondIndex === undefined ? undefined : secondId;
113
+ if (secondIndex === undefined) return firstId;
114
+ return firstIndex <= secondIndex ? firstId : secondId;
91
115
  }
92
116
 
93
117
  export function rawTokensAfterIndex(entries: Entry[], index: number): number {
94
- let total = 0;
95
- for (let i = Math.max(0, index + 1); i < entries.length; i++) {
96
- if (isSourceEntry(entries[i])) total += estimateEntryTokens(entries[i]);
97
- }
98
- return total;
118
+ let total = 0;
119
+ for (let i = Math.max(0, index + 1); i < entries.length; i++) {
120
+ if (isSourceEntry(entries[i])) total += estimateEntryTokens(entries[i]);
121
+ }
122
+ return total;
99
123
  }
100
124
 
101
- export function rawTokensSinceCoverage(entries: Entry[], customType: V3MemoryCustomType): number {
102
- return rawTokensAfterIndex(entries, latestCoverageIndex(entries, customType));
125
+ export function rawTokensSinceCoverage(
126
+ entries: Entry[],
127
+ customType: V3MemoryCustomType,
128
+ ): number {
129
+ return rawTokensAfterIndex(entries, latestCoverageIndex(entries, customType));
103
130
  }
104
131
 
105
132
  export function rawTokensSinceObservationCoverage(entries: Entry[]): number {
106
- return rawTokensSinceCoverage(entries, OM_OBSERVATIONS_RECORDED);
133
+ return rawTokensSinceCoverage(entries, OM_OBSERVATIONS_RECORDED);
107
134
  }
108
135
 
109
136
  export function rawTokensSinceReflectionCoverage(entries: Entry[]): number {
110
- return rawTokensSinceCoverage(entries, OM_REFLECTIONS_RECORDED);
137
+ return rawTokensSinceCoverage(entries, OM_REFLECTIONS_RECORDED);
111
138
  }
112
139
 
113
140
  export function rawTokensSinceDropCoverage(entries: Entry[]): number {
114
- return rawTokensSinceCoverage(entries, OM_OBSERVATIONS_DROPPED);
141
+ return rawTokensSinceCoverage(entries, OM_OBSERVATIONS_DROPPED);
115
142
  }
116
143
 
117
144
  export function findLastCompactionIndex(entries: Entry[]): number {
118
- for (let i = entries.length - 1; i >= 0; i--) {
119
- if (entries[i].type === "compaction") return i;
120
- }
121
- return -1;
145
+ for (let i = entries.length - 1; i >= 0; i--) {
146
+ if (entries[i].type === "compaction") return i;
147
+ }
148
+ return -1;
122
149
  }
123
150
 
124
151
  export function rawTokensSinceLastCompaction(entries: Entry[]): number {
125
- const compactionIndex = findLastCompactionIndex(entries);
126
- if (compactionIndex === -1) return rawTokensAfterIndex(entries, -1);
152
+ const compactionIndex = findLastCompactionIndex(entries);
153
+ if (compactionIndex === -1) return rawTokensAfterIndex(entries, -1);
127
154
 
128
- const firstKeptEntryId = entries[compactionIndex].firstKeptEntryId;
129
- const firstKeptIndex = entryIndexForId(entries, firstKeptEntryId);
155
+ const firstKeptEntryId = entries[compactionIndex].firstKeptEntryId;
156
+ const firstKeptIndex = entryIndexForId(entries, firstKeptEntryId);
130
157
 
131
- if (firstKeptIndex === -1) return rawTokensAfterIndex(entries, compactionIndex);
132
- return rawTokensAfterIndex(entries, firstKeptIndex - 1);
158
+ if (firstKeptIndex === -1)
159
+ return rawTokensAfterIndex(entries, compactionIndex);
160
+ return rawTokensAfterIndex(entries, firstKeptIndex - 1);
133
161
  }
134
162
 
135
163
  /**
@@ -138,50 +166,50 @@ export function rawTokensSinceLastCompaction(entries: Entry[]): number {
138
166
  * entries that were appended AFTER the given index.
139
167
  */
140
168
  export function observationsCreatedAfterIndex(
141
- entries: Entry[],
142
- sinceIndex: number,
169
+ entries: Entry[],
170
+ sinceIndex: number,
143
171
  ): Observation[] {
144
- const observations: Observation[] = [];
145
- const seen = new Set<string>();
146
-
147
- for (let i = sinceIndex + 1; i < entries.length; i++) {
148
- const entry = entries[i];
149
- if (entry.type !== "custom") continue;
150
- if (entry.customType !== OM_OBSERVATIONS_RECORDED) continue;
151
- if (!isObservationsRecordedData(entry.data)) continue;
152
- for (const obs of entry.data.observations) {
153
- if (!seen.has(obs.id)) {
154
- seen.add(obs.id);
155
- observations.push(obs);
156
- }
157
- }
158
- }
159
- return observations;
172
+ const observations: Observation[] = [];
173
+ const seen = new Set<string>();
174
+
175
+ for (let i = sinceIndex + 1; i < entries.length; i++) {
176
+ const entry = entries[i];
177
+ if (entry.type !== "custom") continue;
178
+ if (entry.customType !== OM_OBSERVATIONS_RECORDED) continue;
179
+ if (!isObservationsRecordedData(entry.data)) continue;
180
+ for (const obs of entry.data.observations) {
181
+ if (!seen.has(obs.id)) {
182
+ seen.add(obs.id);
183
+ observations.push(obs);
184
+ }
185
+ }
186
+ }
187
+ return observations;
160
188
  }
161
189
 
162
190
  /**
163
191
  * Extract reflections created since the given entry index.
164
192
  */
165
193
  export function reflectionsCreatedAfterIndex(
166
- entries: Entry[],
167
- sinceIndex: number,
194
+ entries: Entry[],
195
+ sinceIndex: number,
168
196
  ): Reflection[] {
169
- const reflections: Reflection[] = [];
170
- const seen = new Set<string>();
171
-
172
- for (let i = sinceIndex + 1; i < entries.length; i++) {
173
- const entry = entries[i];
174
- if (entry.type !== "custom") continue;
175
- if (entry.customType !== OM_REFLECTIONS_RECORDED) continue;
176
- if (!isReflectionsRecordedData(entry.data)) continue;
177
- for (const ref of entry.data.reflections) {
178
- if (!seen.has(ref.id)) {
179
- seen.add(ref.id);
180
- reflections.push(ref);
181
- }
182
- }
183
- }
184
- return reflections;
197
+ const reflections: Reflection[] = [];
198
+ const seen = new Set<string>();
199
+
200
+ for (let i = sinceIndex + 1; i < entries.length; i++) {
201
+ const entry = entries[i];
202
+ if (entry.type !== "custom") continue;
203
+ if (entry.customType !== OM_REFLECTIONS_RECORDED) continue;
204
+ if (!isReflectionsRecordedData(entry.data)) continue;
205
+ for (const ref of entry.data.reflections) {
206
+ if (!seen.has(ref.id)) {
207
+ seen.add(ref.id);
208
+ reflections.push(ref);
209
+ }
210
+ }
211
+ }
212
+ return reflections;
185
213
  }
186
214
 
187
215
  /**
@@ -189,19 +217,19 @@ export function reflectionsCreatedAfterIndex(
189
217
  * Capped at maxTokens.
190
218
  */
191
219
  export function buildExistingObservationsSummary(
192
- observations: Observation[],
193
- maxTokens: number,
220
+ observations: Observation[],
221
+ maxTokens: number,
194
222
  ): string {
195
- const lines: string[] = [];
196
- let tokens = 0;
197
- for (const obs of observations) {
198
- const line = `[${obs.id}] ${obs.timestamp} [${obs.relevance}] ${obs.content}`;
199
- const lineTokens = Math.ceil(line.length / 4);
200
- if (tokens + lineTokens > maxTokens && lines.length > 0) break;
201
- lines.push(line);
202
- tokens += lineTokens;
203
- }
204
- return lines.join("\n");
223
+ const lines: string[] = [];
224
+ let tokens = 0;
225
+ for (const obs of observations) {
226
+ const line = `[${obs.id}] ${obs.timestamp} [${obs.relevance}] ${obs.content}`;
227
+ const lineTokens = Math.ceil(line.length / 4);
228
+ if (tokens + lineTokens > maxTokens && lines.length > 0) break;
229
+ lines.push(line);
230
+ tokens += lineTokens;
231
+ }
232
+ return lines.join("\n");
205
233
  }
206
234
 
207
235
  /**
@@ -209,17 +237,17 @@ export function buildExistingObservationsSummary(
209
237
  * Capped at maxTokens.
210
238
  */
211
239
  export function buildExistingReflectionsSummary(
212
- reflections: Reflection[],
213
- maxTokens: number,
240
+ reflections: Reflection[],
241
+ maxTokens: number,
214
242
  ): string {
215
- const lines: string[] = [];
216
- let tokens = 0;
217
- for (const ref of reflections) {
218
- const line = `[${ref.id}] ${ref.content}`;
219
- const lineTokens = Math.ceil(line.length / 4);
220
- if (tokens + lineTokens > maxTokens && lines.length > 0) break;
221
- lines.push(line);
222
- tokens += lineTokens;
223
- }
224
- return lines.join("\n");
243
+ const lines: string[] = [];
244
+ let tokens = 0;
245
+ for (const ref of reflections) {
246
+ const line = `[${ref.id}] ${ref.content}`;
247
+ const lineTokens = Math.ceil(line.length / 4);
248
+ if (tokens + lineTokens > maxTokens && lines.length > 0) break;
249
+ lines.push(line);
250
+ tokens += lineTokens;
251
+ }
252
+ return lines.join("\n");
225
253
  }