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.
- package/README.md +15 -0
- package/dist/index.js +11660 -0
- package/dist/index.js.map +1 -0
- package/example-config.json +1 -1
- package/index.ts +37 -63
- package/package.json +21 -9
- package/src/commands/cleanup.ts +279 -240
- package/src/commands/memory.ts +236 -184
- package/src/commands/pi-vcc.ts +202 -152
- package/src/commands/vcc-recall.ts +126 -95
- package/src/core/brief.ts +167 -33
- package/src/core/build-sections.ts +8 -2
- package/src/core/config-env.ts +117 -0
- package/src/core/content.ts +31 -7
- package/src/core/drill-down.ts +41 -11
- package/src/core/filter-noise.ts +9 -3
- package/src/core/format-recall.ts +15 -6
- package/src/core/format.ts +14 -4
- package/src/core/lineage.ts +9 -3
- package/src/core/load-messages.ts +24 -5
- package/src/core/normalize.ts +38 -14
- package/src/core/recall-scope.ts +11 -3
- package/src/core/render-entries.ts +22 -6
- package/src/core/sanitize.ts +5 -1
- package/src/core/search-entries.ts +111 -19
- package/src/core/settings.ts +1 -3
- package/src/core/summarize.ts +42 -21
- package/src/core/unified-config.ts +549 -411
- package/src/extract/commits.ts +4 -2
- package/src/extract/files.ts +10 -5
- package/src/extract/goals.ts +7 -2
- package/src/hooks/before-compact.ts +210 -88
- package/src/om/agents/dropper/agent.ts +380 -265
- package/src/om/agents/dropper/coverage.ts +102 -82
- package/src/om/agents/observer/agent.ts +242 -206
- package/src/om/agents/reflector/agent.ts +212 -153
- package/src/om/cleanup.ts +239 -218
- package/src/om/clipboard.ts +59 -51
- package/src/om/compaction-trigger.ts +448 -333
- package/src/om/config.ts +13 -6
- package/src/om/configure-overlay.ts +518 -355
- package/src/om/consolidation.ts +1460 -953
- package/src/om/cooldown.ts +75 -65
- package/src/om/debug-log.ts +86 -68
- package/src/om/ids.ts +1 -1
- package/src/om/ledger/fold.ts +89 -78
- package/src/om/ledger/progress.ts +181 -153
- package/src/om/ledger/projection.ts +248 -185
- package/src/om/ledger/recall.ts +247 -196
- package/src/om/ledger/render-summary.ts +79 -50
- package/src/om/ledger/types.ts +146 -117
- package/src/om/model-budget.ts +23 -13
- package/src/om/pending.ts +243 -179
- package/src/om/provider-stream.ts +52 -7
- package/src/om/retryable-error.ts +12 -16
- package/src/om/reverse-recall.ts +97 -91
- package/src/om/runtime.ts +474 -375
- package/src/om/serialize.ts +190 -166
- package/src/om/status-overlay.ts +246 -195
- package/src/om/tokens.ts +28 -21
- package/src/pi-base/blackhole-settings.ts +437 -0
- package/src/pi-base/config-manager.ts +440 -0
- package/src/pi-base/config.ts +469 -0
- package/src/pi-base/env.ts +43 -0
- package/src/pi-base/paths.ts +47 -0
- package/src/pi-base/settings/body.ts +1648 -0
- package/src/pi-base/settings/fields/action.ts +43 -0
- package/src/pi-base/settings/fields/boolean.ts +47 -0
- package/src/pi-base/settings/fields/custom.ts +72 -0
- package/src/pi-base/settings/fields/enum.ts +310 -0
- package/src/pi-base/settings/fields/index.ts +46 -0
- package/src/pi-base/settings/fields/model.ts +452 -0
- package/src/pi-base/settings/fields/string.ts +527 -0
- package/src/pi-base/settings/fields/text.ts +115 -0
- package/src/pi-base/settings/frame.ts +197 -0
- package/src/pi-base/settings/index.ts +77 -0
- package/src/pi-base/settings/inline-edit.ts +313 -0
- package/src/pi-base/settings/modal.ts +152 -0
- package/src/pi-base/settings/types.ts +500 -0
- package/src/pi-base/settings/validate-field.ts +113 -0
- package/src/pi-base/shell.ts +117 -0
- package/src/pi-base/types.ts +6 -0
- package/src/pi-base/ui.ts +32 -0
- package/src/tools/recall.ts +347 -225
- package/src/types.ts +20 -3
- package/tsup.config.ts +23 -0
- package/vitest.config.ts +15 -15
|
@@ -1,135 +1,163 @@
|
|
|
1
1
|
import { estimateEntryTokens } from "../tokens.js";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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([
|
|
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
|
-
|
|
21
|
+
return SOURCE_ENTRY_TYPES.has(entry.type);
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
export function entryIndexById(entries: Entry[]): Map<string, number> {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
40
|
+
return typeof value === "object" && value !== null;
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
function isNonEmptyArray(value: unknown): value is unknown[] {
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function isValidCoverageEntry(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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(
|
|
102
|
-
|
|
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
|
-
|
|
133
|
+
return rawTokensSinceCoverage(entries, OM_OBSERVATIONS_RECORDED);
|
|
107
134
|
}
|
|
108
135
|
|
|
109
136
|
export function rawTokensSinceReflectionCoverage(entries: Entry[]): number {
|
|
110
|
-
|
|
137
|
+
return rawTokensSinceCoverage(entries, OM_REFLECTIONS_RECORDED);
|
|
111
138
|
}
|
|
112
139
|
|
|
113
140
|
export function rawTokensSinceDropCoverage(entries: Entry[]): number {
|
|
114
|
-
|
|
141
|
+
return rawTokensSinceCoverage(entries, OM_OBSERVATIONS_DROPPED);
|
|
115
142
|
}
|
|
116
143
|
|
|
117
144
|
export function findLastCompactionIndex(entries: Entry[]): number {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
126
|
-
|
|
152
|
+
const compactionIndex = findLastCompactionIndex(entries);
|
|
153
|
+
if (compactionIndex === -1) return rawTokensAfterIndex(entries, -1);
|
|
127
154
|
|
|
128
|
-
|
|
129
|
-
|
|
155
|
+
const firstKeptEntryId = entries[compactionIndex].firstKeptEntryId;
|
|
156
|
+
const firstKeptIndex = entryIndexForId(entries, firstKeptEntryId);
|
|
130
157
|
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
142
|
-
|
|
169
|
+
entries: Entry[],
|
|
170
|
+
sinceIndex: number,
|
|
143
171
|
): Observation[] {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
167
|
-
|
|
194
|
+
entries: Entry[],
|
|
195
|
+
sinceIndex: number,
|
|
168
196
|
): Reflection[] {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
193
|
-
|
|
220
|
+
observations: Observation[],
|
|
221
|
+
maxTokens: number,
|
|
194
222
|
): string {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
213
|
-
|
|
240
|
+
reflections: Reflection[],
|
|
241
|
+
maxTokens: number,
|
|
214
242
|
): string {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
}
|