pi-smart-compact 7.9.1 → 7.9.2

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/index.js CHANGED
@@ -197,6 +197,33 @@ function debug(msg, ...args) {
197
197
  }
198
198
 
199
199
  // src/utils/helpers.ts
200
+ function validateSmartCompactConfig(sc) {
201
+ const VALID_PROFILES = ["light", "balanced", "aggressive"];
202
+ if ("profile" in sc && !VALID_PROFILES.includes(sc.profile)) {
203
+ warn("smart-compact config: invalid profile '" + sc.profile + "', expected light|balanced|aggressive. Using default 'balanced'.");
204
+ delete sc.profile;
205
+ }
206
+ if ("autoTrigger" in sc && typeof sc.autoTrigger !== "boolean") {
207
+ warn("smart-compact config: autoTrigger must be boolean, got " + typeof sc.autoTrigger);
208
+ delete sc.autoTrigger;
209
+ }
210
+ if ("backupEnabled" in sc && typeof sc.backupEnabled !== "boolean") {
211
+ warn("smart-compact config: backupEnabled must be boolean, got " + typeof sc.backupEnabled);
212
+ delete sc.backupEnabled;
213
+ }
214
+ if ("summaryModel" in sc && sc.summaryModel !== null && typeof sc.summaryModel !== "string") {
215
+ warn("smart-compact config: summaryModel must be string|null, got " + typeof sc.summaryModel);
216
+ delete sc.summaryModel;
217
+ }
218
+ if ("segmentationModel" in sc && sc.segmentationModel !== null && typeof sc.segmentationModel !== "string") {
219
+ warn("smart-compact config: segmentationModel must be string|null, got " + typeof sc.segmentationModel);
220
+ delete sc.segmentationModel;
221
+ }
222
+ if ("profiles" in sc && (typeof sc.profiles !== "object" || sc.profiles === null || Array.isArray(sc.profiles))) {
223
+ warn("smart-compact config: profiles must be an object, got " + typeof sc.profiles);
224
+ delete sc.profiles;
225
+ }
226
+ }
200
227
  var _cfg = null;
201
228
  var _cfgMtime = 0;
202
229
  function loadConfig() {
@@ -207,6 +234,7 @@ function loadConfig() {
207
234
  return _cfg;
208
235
  const raw = JSON.parse(fs.readFileSync(p, "utf-8"));
209
236
  const sc = raw[CONFIG_KEY] ?? raw[CONFIG_KEY_ALT] ?? {};
237
+ validateSmartCompactConfig(sc);
210
238
  const merged = { ...DEFAULT_CONFIG, ...sc };
211
239
  if (sc.profiles)
212
240
  merged.profiles = { ...PROFILES, ...sc.profiles };
@@ -372,6 +400,24 @@ function buildExtractionContext(extraction, forRange) {
372
400
  ].join(`
373
401
  `);
374
402
  }
403
+ function inferSessionType(extraction, report) {
404
+ if (report?.sessionType)
405
+ return report.sessionType;
406
+ const hasModifications = extraction.modifiedFiles.length > 0;
407
+ const hasUnresolvedErrors = extraction.errors.some((e) => !e.resolved);
408
+ const hasResolvedErrors = extraction.errors.some((e) => e.resolved);
409
+ const hasReadsOnly = extraction.readFiles.length > 2 && !hasModifications;
410
+ const hasDecisions = extraction.decisions.length > 0;
411
+ if (hasUnresolvedErrors && (hasModifications || hasResolvedErrors))
412
+ return "debugging";
413
+ if (hasReadsOnly && !hasDecisions)
414
+ return "review";
415
+ if (hasDecisions && !hasModifications && !hasUnresolvedErrors)
416
+ return "discussion";
417
+ if (hasModifications)
418
+ return "implementation";
419
+ return "implementation";
420
+ }
375
421
  function buildExplorationContext(report) {
376
422
  if (!report.mainGoal && !report.crossReferences.length && !report.enrichedConstraints.length)
377
423
  return "";
@@ -649,15 +695,28 @@ function loadCachedExtraction(sessionId) {
649
695
  }
650
696
  }
651
697
  function mergeExtractions(base, delta, baseMsgCount) {
698
+ const offsetErrors = delta.errors.map((e) => ({ ...e, index: e.index + baseMsgCount }));
699
+ const offsetDecisions = delta.decisions.map((d) => ({ ...d, index: d.index + baseMsgCount }));
700
+ const offsetConstraints = delta.constraints.map((c) => ({ ...c, index: c.index + baseMsgCount }));
701
+ const offsetTopics = delta.topics.map((t) => ({
702
+ ...t,
703
+ startIndex: t.startIndex + baseMsgCount,
704
+ endIndex: t.endIndex + baseMsgCount
705
+ }));
706
+ const offsetTimeline = delta.timeline.map((t) => ({ ...t, index: t.index + baseMsgCount }));
707
+ const offsetModifiedFiles = delta.modifiedFiles.map((f) => ({
708
+ ...f,
709
+ lastModifiedIndex: f.lastModifiedIndex + baseMsgCount
710
+ }));
652
711
  return {
653
- modifiedFiles: [...new Map([...base.modifiedFiles, ...delta.modifiedFiles].map((f) => [f.path, f])).values()],
712
+ modifiedFiles: [...new Map([...base.modifiedFiles, ...offsetModifiedFiles].map((f) => [f.path, f])).values()],
654
713
  readFiles: [...new Set([...base.readFiles, ...delta.readFiles])],
655
714
  deletedFiles: [...new Set([...base.deletedFiles, ...delta.deletedFiles])],
656
- errors: [...base.errors, ...delta.errors],
657
- decisions: [...base.decisions, ...delta.decisions],
658
- constraints: [...base.constraints, ...delta.constraints],
659
- topics: [...base.topics, ...delta.topics],
660
- timeline: [...base.timeline, ...delta.timeline],
715
+ errors: [...base.errors, ...offsetErrors],
716
+ decisions: [...base.decisions, ...offsetDecisions],
717
+ constraints: [...base.constraints, ...offsetConstraints],
718
+ topics: [...base.topics, ...offsetTopics],
719
+ timeline: [...base.timeline, ...offsetTimeline],
661
720
  mainGoal: delta.mainGoal ?? base.mainGoal,
662
721
  lastUserMessages: delta.lastUserMessages.length > 0 ? delta.lastUserMessages : base.lastUserMessages,
663
722
  lastErrors: delta.lastErrors.length > 0 ? delta.lastErrors : base.lastErrors,
@@ -1124,7 +1183,7 @@ function buildCompactionState(extraction, openLoops, report, nextActions, critic
1124
1183
  })),
1125
1184
  nextActions,
1126
1185
  criticalContext,
1127
- sessionType: report?.sessionType ?? "implementation",
1186
+ sessionType: inferSessionType(extraction, report),
1128
1187
  compactionVersion: VERSION,
1129
1188
  updatedAt: Date.now()
1130
1189
  };
@@ -1392,22 +1451,73 @@ var FRAMEWORK_SIGNALS = [
1392
1451
  function getFingerprintPath(projectId) {
1393
1452
  return path5.join(FINGERPRINT_DIR, projectId + ".json");
1394
1453
  }
1454
+ var NOISE_PATH_RE = /(?:node_modules|[/\\]\.pi[/\\]agent|[/\\]\.cache|[/\\]\.npm|[/\\]\.bun|[/\\]\.git[/\\])/;
1455
+ function isProjectPath(filePath) {
1456
+ return !NOISE_PATH_RE.test(filePath);
1457
+ }
1458
+ function hashProjectId(seed) {
1459
+ return "proj-" + crypto3.createHash("sha256").update(seed).digest("hex").slice(0, 12);
1460
+ }
1461
+ function deriveFromAbsolutePaths(paths) {
1462
+ const segments = paths.map((p) => p.replace(/^\/+/, "").split("/").filter(Boolean)).filter((s) => s.length >= 3);
1463
+ if (segments.length < 2)
1464
+ return deriveFromRelativePaths(paths);
1465
+ const dirCounts = new Map;
1466
+ for (const segs of segments) {
1467
+ for (let depth = 3;depth <= segs.length; depth++) {
1468
+ const prefix = segs.slice(0, depth).join("/");
1469
+ dirCounts.set(prefix, (dirCounts.get(prefix) ?? 0) + 1);
1470
+ }
1471
+ }
1472
+ const threshold = Math.ceil(segments.length * 0.5);
1473
+ const candidates = [...dirCounts.entries()].filter(([, count]) => count >= threshold).sort((a, b) => {
1474
+ const depthDiff = b[0].split("/").length - a[0].split("/").length;
1475
+ if (depthDiff !== 0)
1476
+ return depthDiff;
1477
+ return b[1] - a[1];
1478
+ });
1479
+ if (candidates.length)
1480
+ return hashProjectId(candidates[0][0]);
1481
+ const sorted = [...segments].sort((a, b) => a.length - b.length);
1482
+ let commonDepth = 0;
1483
+ for (let d = 0;d < sorted[0].length; d++) {
1484
+ if (segments.every((s) => s[d] === sorted[0][d]))
1485
+ commonDepth = d + 1;
1486
+ else
1487
+ break;
1488
+ }
1489
+ return hashProjectId(sorted[0].slice(0, Math.max(commonDepth, 3)).join("/"));
1490
+ }
1491
+ function deriveFromRelativePaths(paths) {
1492
+ const topEntries = [...new Set(paths.map((p) => p.split("/").filter(Boolean)[0]).filter(Boolean))].sort();
1493
+ const dir2Counts = new Map;
1494
+ for (const p of paths) {
1495
+ const segs = p.split("/").filter(Boolean);
1496
+ if (segs.length >= 2) {
1497
+ const d2 = segs.slice(0, 2).join("/");
1498
+ dir2Counts.set(d2, (dir2Counts.get(d2) ?? 0) + 1);
1499
+ }
1500
+ }
1501
+ const stableDirs = [...dir2Counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 8).map(([d]) => d).sort();
1502
+ const fingerprint = topEntries.join(",") + "|" + stableDirs.join(",");
1503
+ return hashProjectId(fingerprint);
1504
+ }
1395
1505
  function deriveProjectId(extraction) {
1396
1506
  const allPaths = [
1397
1507
  ...extraction.modifiedFiles.map((f) => f.path),
1398
1508
  ...extraction.readFiles
1399
- ];
1509
+ ].filter(isProjectPath);
1400
1510
  if (!allPaths.length)
1401
1511
  return "unknown";
1402
- const roots = new Map;
1403
- for (const p of allPaths) {
1404
- const parts = p.split("/");
1405
- const root = parts.length > 1 ? parts.slice(0, Math.min(2, parts.length - 1)).join("/") : "root";
1406
- roots.set(root, (roots.get(root) ?? 0) + 1);
1512
+ const absolutePaths = allPaths.filter((p) => p.startsWith("/"));
1513
+ const relativePaths = allPaths.filter((p) => !p.startsWith("/"));
1514
+ if (absolutePaths.length >= 2) {
1515
+ return deriveFromAbsolutePaths(absolutePaths);
1516
+ }
1517
+ if (relativePaths.length >= 2) {
1518
+ return deriveFromRelativePaths(relativePaths);
1407
1519
  }
1408
- const topRoot = [...roots.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? "unknown";
1409
- const hash = crypto3.createHash("sha256").update(topRoot).digest("hex").slice(0, 12);
1410
- return "proj-" + hash;
1520
+ return hashProjectId(allPaths.sort().join("|"));
1411
1521
  }
1412
1522
  function detectLanguage(extraction) {
1413
1523
  const extCounts = new Map;
@@ -2044,7 +2154,7 @@ function chunkLlmMessages(msgs, boundaries, pc) {
2044
2154
  async function singlePassCompact(convText, extraction, report, prevContext, model, auth, signal) {
2045
2155
  const extractionCtx = buildExtractionContext(extraction);
2046
2156
  const explorationCtx = report ? buildExplorationContext(report) : "";
2047
- const sessionType = report?.sessionType ?? "implementation";
2157
+ const sessionType = inferSessionType(extraction, report);
2048
2158
  const sessionInstruction = SESSION_TYPE_INSTRUCTIONS[sessionType] ?? SESSION_TYPE_INSTRUCTIONS.implementation;
2049
2159
  const adaptedPrefix = SINGLE_PASS_PREFIX + `
2050
2160
  Session-specific instructions:
@@ -2359,8 +2469,7 @@ function renderContextBar(theme, pct, tokens, barLen = 24) {
2359
2469
  const filled = Math.min(barLen, Math.round(clamped / 100 * barLen));
2360
2470
  const bar = "\u2588".repeat(filled) + "\u2591".repeat(barLen - filled);
2361
2471
  const color = clamped > 80 ? "error" : clamped > 50 ? "warning" : "success";
2362
- const fg = theme.fg;
2363
- return fg("text", " Context: ") + fg(color, bar) + fg("text", " " + clamped + "%") + fg("dim", " (" + (tokens ?? 0).toLocaleString() + "t)");
2472
+ return theme.fg("text", " Context: ") + theme.fg(color, bar) + theme.fg("text", " " + clamped + "%") + theme.fg("dim", " (" + (tokens ?? 0).toLocaleString() + "t)");
2364
2473
  }
2365
2474
  function renderTokenBar(theme, before, after, label, barLen = 30) {
2366
2475
  const ratio = before > 0 ? after / before : 0;
@@ -2489,8 +2598,7 @@ async function showResultScreen(ctx, details, extraction) {
2489
2598
  c.addChild(new Text("", 0, 0));
2490
2599
  const methodColors = { eesv: "accent", "single-pass": "success", heuristic: "warning" };
2491
2600
  const methodColor = methodColors[details.method] ?? "text";
2492
- const fg = theme.fg;
2493
- c.addChild(new Text(theme.fg("text", " Method: ") + fg(methodColor, details.method.toUpperCase()) + theme.fg("dim", " \u2022 " + details.llmCalls + " LLM call(s) \u2022 Profile: " + details.profile), 0, 0));
2601
+ c.addChild(new Text(theme.fg("text", " Method: ") + theme.fg(methodColor, details.method.toUpperCase()) + theme.fg("dim", " \u2022 " + details.llmCalls + " LLM call(s) \u2022 Profile: " + details.profile), 0, 0));
2494
2602
  if (details.model) {
2495
2603
  c.addChild(new Text(theme.fg("dim", " Model: " + details.model), 0, 0));
2496
2604
  }
@@ -1 +1 @@
1
- {"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../../src/ui/overlays.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAI/E,OAAO,KAAK,EACV,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAC9C,mBAAmB,EAAE,oBAAoB,EAC1C,MAAM,aAAa,CAAC;AAIrB,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAO7F;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAO5G;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACvG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA8C7B;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,uBAAuB,EAC5B,aAAa,EAAE,WAAW,EAC1B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GACtD,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA4CpC;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,uBAAuB,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAM5F;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,uBAAuB,EAC5B,OAAO,EAAE,mBAAmB,EAC5B,UAAU,EAAE,oBAAoB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAsJf;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACvG,OAAO,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,GAAG,IAAI,CAAC,CAMrE"}
1
+ {"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../../src/ui/overlays.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAI/E,OAAO,KAAK,EACV,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAC9C,mBAAmB,EAAE,oBAAoB,EAC1C,MAAM,aAAa,CAAC;AAIrB,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAS7F;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAO5G;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACvG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA8C7B;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,uBAAuB,EAC5B,aAAa,EAAE,WAAW,EAC1B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GACtD,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA4CpC;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,uBAAuB,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAM5F;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,uBAAuB,EAC5B,OAAO,EAAE,mBAAmB,EAC5B,UAAU,EAAE,oBAAoB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAsJf;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACvG,OAAO,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,GAAG,IAAI,CAAC,CAMrE"}
@@ -22,6 +22,17 @@ export declare function getMetricsSummary(): {
22
22
  export declare function trackedComplete(phase: LLMCallMetric["phase"], model: Model<Api>, reqBody: Context, opts: CacheAwareOptions): Promise<AssistantMessage>;
23
23
  export declare function saveCachedExtraction(sessionId: string, extraction: StructuredExtraction, msgCount: number): void;
24
24
  export declare function loadCachedExtraction(sessionId: string): CachedExtraction | null;
25
+ /**
26
+ * Merge a delta extraction into a base extraction, offsetting all
27
+ * index-bearing fields so they align with the global message array.
28
+ *
29
+ * When `extractStructured` is called on `msgs.slice(cached.lastMessageIndex + 1)`
30
+ * the delta's indexes start at 0 in the slice — but in the full conversation
31
+ * they start at `baseMsgCount` (= `cached.messageCount` = `cached.lastMessageIndex + 1`).
32
+ *
33
+ * Without this offset, incremental extraction produces corrupted indexes that
34
+ * break timeline ordering, topic segmentation, and downstream verification.
35
+ */
25
36
  export declare function mergeExtractions(base: StructuredExtraction, delta: StructuredExtraction, baseMsgCount: number): StructuredExtraction;
26
37
  export declare function appendMetricsLog(sessionId: string): void;
27
38
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG5G,OAAO,EAAY,KAAK,KAAK,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAO5G,wBAAgB,mBAAmB,IAAI,MAAM,CAK5C;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,iBAAiB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAOhH;AAKD,wBAAgB,YAAY,IAAI,IAAI,CAAyB;AAC7D,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,CAA4F;AAChJ,wBAAgB,UAAU,IAAI,aAAa,EAAE,CAA0B;AAEvE,wBAAgB,iBAAiB,IAAI;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAYpK;AAGD,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,gBAAgB,CAAC,CA2B3B;AAQD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAQhH;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAQ/E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,GAAG,oBAAoB,CAepI;AAGD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAOxD"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG5G,OAAO,EAAY,KAAK,KAAK,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAO5G,wBAAgB,mBAAmB,IAAI,MAAM,CAK5C;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAGD,wBAAgB,SAAS,CAAC,IAAI,EAAE,iBAAiB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAOhH;AAKD,wBAAgB,YAAY,IAAI,IAAI,CAAyB;AAC7D,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,CAA4F;AAChJ,wBAAgB,UAAU,IAAI,aAAa,EAAE,CAA0B;AAEvE,wBAAgB,iBAAiB,IAAI;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAYpK;AAGD,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,gBAAgB,CAAC,CA2B3B;AAQD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAQhH;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAQ/E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,GAAG,oBAAoB,CA8BpI;AAGD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAOxD"}
@@ -13,8 +13,18 @@ export interface ProjectFingerprint {
13
13
  updatedAt: number;
14
14
  }
15
15
  /**
16
- * Generate a project ID from file paths in the extraction.
17
- * Uses the most common root directory as a heuristic.
16
+ * Generate a stable project ID from file paths in the extraction.
17
+ *
18
+ * Strategy (in priority order):
19
+ * 1. **Noise filtering** — exclude node_modules, .cache, .pi/agent, etc.
20
+ * 2. **Absolute paths** (≥ 2) — deep ancestor with majority vote
21
+ * 3. **Relative paths** (≥ 2) — directory structure fingerprint
22
+ * 4. **Fallback** — hash all paths together
23
+ *
24
+ * ⚠️ Breaking change: this replaces the previous shallow-root algorithm
25
+ * that caused cross-project contamination
26
+ * (e.g. hash("root") → proj-4813494d, hash("/Users") → proj-a2a0ee2c).
27
+ * Old fingerprint/state files will be orphaned and expire via TTL.
18
28
  */
19
29
  export declare function deriveProjectId(extraction: StructuredExtraction): string;
20
30
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/utils/fingerprint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAuCD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,oBAAoB,GAAG,MAAM,CAkBxE;AAoDD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CASnF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,GAC/B,IAAI,CAuBN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAQlF"}
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/utils/fingerprint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AA8ID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,oBAAoB,GAAG,MAAM,CAuBxE;AAoDD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CASnF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,GAC/B,IAAI,CAuBN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAQlF"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * General helpers: config, backup, batching, preprocessing.
3
3
  */
4
- import type { CompactConfig, ChunkSummary, LlmChunk, StructuredExtraction, ExplorationReport, SessionMessageEntry } from "../types.ts";
4
+ import type { CompactConfig, ChunkSummary, LlmChunk, StructuredExtraction, ExplorationReport, SessionType, SessionMessageEntry } from "../types.ts";
5
5
  export declare function loadConfig(): CompactConfig;
6
6
  export declare function backupConversation(convText: string, sessionId: string): string | null;
7
7
  export declare function getPreviousCompactionContext(branch: unknown[]): string;
@@ -18,5 +18,20 @@ export declare function buildExtractionContext(extraction: StructuredExtraction,
18
18
  start: number;
19
19
  end: number;
20
20
  }): string;
21
+ /**
22
+ * Infer session type from extraction data when exploration report is absent.
23
+ *
24
+ * Previously defaulted blindly to "implementation", which caused review-only
25
+ * and discussion-only sessions to be summarized with the wrong prompt strategy.
26
+ *
27
+ * Heuristic priority:
28
+ * 1. If exploration report provides a classification → trust it
29
+ * 2. Active errors + code changes → debugging
30
+ * 3. Reads only, no modifications → review
31
+ * 4. Decisions but no code changes → discussion
32
+ * 5. Code modifications → implementation
33
+ * 6. Fallback → implementation (most common agent activity)
34
+ */
35
+ export declare function inferSessionType(extraction: StructuredExtraction, report: ExplorationReport | null): SessionType;
21
36
  export declare function buildExplorationContext(report: ExplorationReport): string;
22
37
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAOvI,wBAAgB,UAAU,IAAI,aAAa,CAiB1C;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUrF;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAQtE;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CA0B5F;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKhE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE,EAAE,CASjF;AAqCD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,YAAY,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM;;;;;EAYnF;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,oBAAoB,EAAE,QAAQ,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAU1H;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAYzE"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAsB,YAAY,EAAE,QAAQ,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AA0CxK,wBAAgB,UAAU,IAAI,aAAa,CAkB1C;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUrF;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAQtE;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CA0B5F;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKhE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE,EAAE,CASjF;AAqCD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,YAAY,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM;;;;;EAYnF;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,oBAAoB,EAAE,QAAQ,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAU1H;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,oBAAoB,EAChC,MAAM,EAAE,iBAAiB,GAAG,IAAI,GAC/B,WAAW,CAeb;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAYzE"}
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/utils/state.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAUtG;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAKnF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAe7E;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,oBAAoB,EAChC,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,WAAW,EAAE,MAAM,EAAE,EACrB,eAAe,EAAE,MAAM,EAAE,GACxB,eAAe,CAgDjB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAsBrF;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,oCAAoC;IACpC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,2CAA2C;IAC3C,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,qBAAqB;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2CAA2C;IAC3C,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,sDAAsD;IACtD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CAmD7F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CA+BjE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,CA2BlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAO5D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhE"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/utils/state.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAe,MAAM,aAAa,CAAC;AAWnH;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAKnF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAe7E;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,oBAAoB,EAChC,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,WAAW,EAAE,MAAM,EAAE,EACrB,eAAe,EAAE,MAAM,EAAE,GACxB,eAAe,CAgDjB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAsBrF;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,oCAAoC;IACpC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,2CAA2C;IAC3C,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,qBAAqB;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2CAA2C;IAC3C,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,sDAAsD;IACtD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CAmD7F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CA+BjE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,CA2BlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAO5D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-smart-compact",
3
- "version": "7.9.1",
3
+ "version": "7.9.2",
4
4
  "description": "EESV smart compaction extension for Pi Coding Agent — deterministic extraction, exploration, synthesis, verification with redundancy pruning, project fingerprinting, and damage detection.",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
@@ -40,7 +40,7 @@
40
40
  "CHANGELOG.md"
41
41
  ],
42
42
  "scripts": {
43
- "build": "rm -rf dist && mkdir dist && bun build ./src/index.ts --outdir ./dist --target bun --external '@earendil-works/*' --external 'typebox' && (bunx tsc --emitDeclarationOnly --outDir dist || true)",
43
+ "build": "rm -rf dist && mkdir dist && bun build ./src/index.ts --outdir ./dist --target bun --external '@earendil-works/*' --external 'typebox' && bunx tsc --emitDeclarationOnly --outDir dist",
44
44
  "test": "bun test",
45
45
  "typecheck": "bunx tsc --noEmit"
46
46
  },