@cortexkit/pi-magic-context 0.30.5 → 0.30.6

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
@@ -157096,6 +157096,8 @@ class PiSubagentRunner {
157096
157096
  return;
157097
157097
  const parsed = parsePiEventLine(line);
157098
157098
  if (!parsed.ok) {
157099
+ if ("noise" in parsed)
157100
+ return;
157099
157101
  parseError = parsed.error;
157100
157102
  return;
157101
157103
  }
@@ -157396,6 +157398,9 @@ function countToolCalls(messages) {
157396
157398
  return count;
157397
157399
  }
157398
157400
  function parsePiEventLine(line) {
157401
+ if (!line.trimStart().startsWith("{")) {
157402
+ return { ok: false, noise: true };
157403
+ }
157399
157404
  try {
157400
157405
  return { ok: true, event: JSON.parse(line) };
157401
157406
  } catch (error) {
@@ -174383,6 +174388,7 @@ function enforceProjectCap(db, projectPath, maxCommits) {
174383
174388
  // ../plugin/src/features/magic-context/git-commits/sweep-coordinator.ts
174384
174389
  var GIT_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
174385
174390
  var GIT_SWEEP_LEASE_TTL_MS = 5 * 60 * 1000;
174391
+ var GIT_SWEEP_NON_INDEXABLE_REPROBE_MS = 24 * 60 * 60 * 1000;
174386
174392
  var GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
174387
174393
  function runImmediate(db, body) {
174388
174394
  db.exec("BEGIN IMMEDIATE");
@@ -174489,6 +174495,20 @@ function markGitSweepSuccessAndRelease(db, projectPath, holderId) {
174489
174495
  return result.changes === 1;
174490
174496
  });
174491
174497
  }
174498
+ function parkGitSweepNonIndexable(db, projectPath, holderId, reprobeMs = GIT_SWEEP_NON_INDEXABLE_REPROBE_MS) {
174499
+ return runImmediate(db, () => {
174500
+ const now = Date.now();
174501
+ const sweptAt = now + reprobeMs - GIT_SWEEP_COOLDOWN_MS;
174502
+ const result = db.prepare(`UPDATE git_sweep_coordinator
174503
+ SET lease_holder = NULL,
174504
+ lease_expires_at = NULL,
174505
+ last_swept_at = ?
174506
+ WHERE project_path = ?
174507
+ AND lease_holder = ?
174508
+ AND lease_expires_at > ?`).run(sweptAt, projectPath, holderId, now);
174509
+ return result.changes === 1;
174510
+ });
174511
+ }
174492
174512
  function releaseGitSweepLease(db, projectPath, holderId) {
174493
174513
  runImmediate(db, () => {
174494
174514
  db.prepare(`UPDATE git_sweep_coordinator
@@ -181657,11 +181677,21 @@ function recordTransientFailure(db, projectIdentity, due, finishedAt, error51) {
181657
181677
  });
181658
181678
  }
181659
181679
  }
181680
+ var LEASE_WAIT_POLL_MS = 2000;
181681
+ var MANUAL_RUN_LEASE_WAIT_MS = 60000;
181660
181682
  async function runDomainGroup(deps, group, cb) {
181661
181683
  const { db, projectIdentity, executor } = deps;
181662
181684
  const leaseKey = leaseKeyFor(group[0].config.task, projectIdentity);
181663
181685
  const holderId = crypto.randomUUID();
181664
- if (!acquireLease(db, holderId, leaseKey)) {
181686
+ let acquired = acquireLease(db, holderId, leaseKey);
181687
+ if (!acquired && cb?.leaseWaitMs) {
181688
+ const deadline = Date.now() + cb.leaseWaitMs;
181689
+ while (!acquired && Date.now() < deadline) {
181690
+ await new Promise((resolve) => setTimeout(resolve, LEASE_WAIT_POLL_MS));
181691
+ acquired = acquireLease(db, holderId, leaseKey);
181692
+ }
181693
+ }
181694
+ if (!acquired) {
181665
181695
  log(`[dreamer] domain lease busy (${leaseKey}) — deferring ${group.length} task(s)`);
181666
181696
  for (const due of group)
181667
181697
  cb?.onBusy?.(due.config.task);
@@ -181756,6 +181786,7 @@ async function runManualDream(deps) {
181756
181786
  }
181757
181787
  await Promise.all([...groups.values()].map((group) => runDomainGroup({ ...deps, executor: deps.executor }, group, {
181758
181788
  forceGate,
181789
+ leaseWaitMs: MANUAL_RUN_LEASE_WAIT_MS,
181759
181790
  onRan: (t) => result.ran.push(t),
181760
181791
  onFailed: (t) => result.failed.push(t),
181761
181792
  onBusy: (t) => result.deferredBusy.push(t)
@@ -181886,7 +181917,15 @@ var GIT_TIMEOUT_MS3 = 1e4;
181886
181917
  var DEFAULT_MAX_COMMITS = 5000;
181887
181918
  var RECORD_SEPARATOR = "\x1E";
181888
181919
  var FIELD_SEPARATOR = "\x1F";
181889
- async function readGitCommits(directory, options = {}) {
181920
+ function classifyGitLogFailure(message) {
181921
+ if (message.includes("not a git repository"))
181922
+ return "not_a_repo";
181923
+ if (message.includes("unknown revision or path not in the working tree") || message.includes("does not have any commits yet") || message.includes("bad revision")) {
181924
+ return "no_head";
181925
+ }
181926
+ return "transient";
181927
+ }
181928
+ async function readGitCommitsResult(directory, options = {}) {
181890
181929
  const revision = options.branch ?? "HEAD";
181891
181930
  if (revision.startsWith("-")) {
181892
181931
  throw new Error(`readGitCommits: refusing revision that looks like an option: "${revision}"`);
@@ -181914,13 +181953,18 @@ async function readGitCommits(directory, options = {}) {
181914
181953
  stdout = result.stdout;
181915
181954
  } catch (error51) {
181916
181955
  const message = error51 instanceof Error ? error51.message : String(error51);
181917
- log(`[git-commits] readGitCommits failed for ${projectLabel}: ${message.slice(0, 500)}`);
181918
- return [];
181956
+ const failure = classifyGitLogFailure(message);
181957
+ if (failure === "transient") {
181958
+ log(`[git-commits] readGitCommits failed for ${projectLabel}: ${message.slice(0, 500)}`);
181959
+ } else {
181960
+ log(`[git-commits] ${projectLabel} is not indexable (${failure})`);
181961
+ }
181962
+ return { commits: [], failure };
181919
181963
  }
181920
181964
  if (stdout.trim().length === 0) {
181921
181965
  log(`[git-commits] readGitCommits returned empty stdout for ${projectLabel} (sinceMs=${options.sinceMs ?? "none"} args=${args.slice(0, 4).join(" ")})`);
181922
181966
  }
181923
- return parseGitLogOutput(stdout);
181967
+ return { commits: parseGitLogOutput(stdout), failure: null };
181924
181968
  }
181925
181969
  function parseGitLogOutput(stdout) {
181926
181970
  const commits = [];
@@ -181976,7 +182020,8 @@ async function indexCommitsForProject(db, projectPath, directory, options) {
181976
182020
  inserted: 0,
181977
182021
  updated: 0,
181978
182022
  evicted: 0,
181979
- embedded: 0
182023
+ embedded: 0,
182024
+ nonIndexable: false
181980
182025
  };
181981
182026
  if (indexInProgress.has(projectPath)) {
181982
182027
  log(`[git-commits] index already in progress for ${projectPath}, skipping`);
@@ -181986,12 +182031,17 @@ async function indexCommitsForProject(db, projectPath, directory, options) {
181986
182031
  try {
181987
182032
  const latestIndexed = getLatestIndexedCommitTimeMs(db, projectPath);
181988
182033
  const sinceMs = latestIndexed !== null ? Math.max(latestIndexed - 60000, Date.now() - options.sinceDays * MS_PER_DAY) : Date.now() - options.sinceDays * MS_PER_DAY;
181989
- const commits = await readGitCommits(directory, {
182034
+ const read = await readGitCommitsResult(directory, {
181990
182035
  sinceMs,
181991
182036
  maxCommits: options.maxCommits,
181992
182037
  projectIdentity: projectPath
181993
182038
  });
182039
+ const commits = read.commits;
181994
182040
  result.scanned = commits.length;
182041
+ if (read.failure === "not_a_repo" || read.failure === "no_head") {
182042
+ result.nonIndexable = true;
182043
+ return result;
182044
+ }
181995
182045
  if (commits.length === 0) {
181996
182046
  result.evicted = enforceProjectCap(db, projectPath, options.maxCommits);
181997
182047
  log(`[git-commits] no new commits for ${projectPath} (sinceMs=${sinceMs} latestIndexed=${latestIndexed ?? "none"} evicted=${result.evicted})`);
@@ -182413,6 +182463,12 @@ async function sweepGitCommits(args) {
182413
182463
  sinceDays: gitCommitIndexing.since_days,
182414
182464
  maxCommits: gitCommitIndexing.max_commits
182415
182465
  });
182466
+ if (result.nonIndexable) {
182467
+ if (!parkGitSweepNonIndexable(db, projectIdentity, holderId)) {
182468
+ releaseGitSweepLease(db, projectIdentity, holderId);
182469
+ }
182470
+ return;
182471
+ }
182416
182472
  let drainedEmbeddings = 0;
182417
182473
  if (result.embedded > 0) {
182418
182474
  drainedEmbeddings = await embedUnembeddedCommits(db, projectIdentity);
@@ -184229,7 +184285,7 @@ Unknown task "${requested}".`,
184229
184285
  if (result.skippedNoWork.length > 0)
184230
184286
  lines.push(`Skipped (no work): ${result.skippedNoWork.join(", ")}`);
184231
184287
  if (result.deferredBusy.length > 0)
184232
- lines.push(`Busy (already running): ${result.deferredBusy.join(", ")}`);
184288
+ lines.push(`Busy: ${result.deferredBusy.join(", ")} — another dream task holds this domain's lease; retry in a minute`);
184233
184289
  if (lines.length === 0)
184234
184290
  lines.push("No enabled dream tasks to run.");
184235
184291
  sendCtxStatusMessage(pi, {
@@ -194574,6 +194630,9 @@ function getMessageId(message) {
194574
194630
  }
194575
194631
  return "";
194576
194632
  }
194633
+ function isReplayableAnchor(message) {
194634
+ return message.stopReason !== "aborted" && message.stopReason !== "error";
194635
+ }
194577
194636
  function hasToolCallWithId(message, callId) {
194578
194637
  if (!Array.isArray(message.content))
194579
194638
  return false;
@@ -194630,6 +194689,8 @@ function injectByAssistantId(messages, messageId, part) {
194630
194689
  const assistant = m;
194631
194690
  if (getMessageId(assistant) !== messageId)
194632
194691
  continue;
194692
+ if (!isReplayableAnchor(assistant))
194693
+ return false;
194633
194694
  if (hasToolCallWithId(assistant, part.callID)) {
194634
194695
  if (findToolResultAfter(messages, i, part.callID) >= 0)
194635
194696
  return true;
@@ -194655,6 +194716,8 @@ function injectIntoLatestAssistant(messages, part) {
194655
194716
  if (m.role !== "assistant")
194656
194717
  continue;
194657
194718
  const assistant = m;
194719
+ if (!isReplayableAnchor(assistant))
194720
+ continue;
194658
194721
  const id = getMessageId(assistant);
194659
194722
  if (id.length === 0)
194660
194723
  continue;
@@ -200063,7 +200126,7 @@ function formatThresholdPercent(value) {
200063
200126
  // package.json
200064
200127
  var package_default = {
200065
200128
  name: "@cortexkit/pi-magic-context",
200066
- version: "0.30.5",
200129
+ version: "0.30.6",
200067
200130
  type: "module",
200068
200131
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
200069
200132
  main: "dist/index.js",
@@ -161941,6 +161941,7 @@ function enforceProjectCap(db, projectPath, maxCommits) {
161941
161941
  // ../plugin/src/features/magic-context/git-commits/sweep-coordinator.ts
161942
161942
  var GIT_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
161943
161943
  var GIT_SWEEP_LEASE_TTL_MS = 5 * 60 * 1000;
161944
+ var GIT_SWEEP_NON_INDEXABLE_REPROBE_MS = 24 * 60 * 60 * 1000;
161944
161945
  var GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
161945
161946
  function runImmediate(db, body) {
161946
161947
  db.exec("BEGIN IMMEDIATE");
@@ -162047,6 +162048,20 @@ function markGitSweepSuccessAndRelease(db, projectPath, holderId) {
162047
162048
  return result.changes === 1;
162048
162049
  });
162049
162050
  }
162051
+ function parkGitSweepNonIndexable(db, projectPath, holderId, reprobeMs = GIT_SWEEP_NON_INDEXABLE_REPROBE_MS) {
162052
+ return runImmediate(db, () => {
162053
+ const now = Date.now();
162054
+ const sweptAt = now + reprobeMs - GIT_SWEEP_COOLDOWN_MS;
162055
+ const result = db.prepare(`UPDATE git_sweep_coordinator
162056
+ SET lease_holder = NULL,
162057
+ lease_expires_at = NULL,
162058
+ last_swept_at = ?
162059
+ WHERE project_path = ?
162060
+ AND lease_holder = ?
162061
+ AND lease_expires_at > ?`).run(sweptAt, projectPath, holderId, now);
162062
+ return result.changes === 1;
162063
+ });
162064
+ }
162050
162065
  function releaseGitSweepLease(db, projectPath, holderId) {
162051
162066
  runImmediate(db, () => {
162052
162067
  db.prepare(`UPDATE git_sweep_coordinator
@@ -173417,7 +173432,15 @@ var GIT_TIMEOUT_MS3 = 1e4;
173417
173432
  var DEFAULT_MAX_COMMITS = 5000;
173418
173433
  var RECORD_SEPARATOR = "\x1E";
173419
173434
  var FIELD_SEPARATOR = "\x1F";
173420
- async function readGitCommits(directory, options = {}) {
173435
+ function classifyGitLogFailure(message) {
173436
+ if (message.includes("not a git repository"))
173437
+ return "not_a_repo";
173438
+ if (message.includes("unknown revision or path not in the working tree") || message.includes("does not have any commits yet") || message.includes("bad revision")) {
173439
+ return "no_head";
173440
+ }
173441
+ return "transient";
173442
+ }
173443
+ async function readGitCommitsResult(directory, options = {}) {
173421
173444
  const revision = options.branch ?? "HEAD";
173422
173445
  if (revision.startsWith("-")) {
173423
173446
  throw new Error(`readGitCommits: refusing revision that looks like an option: "${revision}"`);
@@ -173445,13 +173468,18 @@ async function readGitCommits(directory, options = {}) {
173445
173468
  stdout = result.stdout;
173446
173469
  } catch (error51) {
173447
173470
  const message = error51 instanceof Error ? error51.message : String(error51);
173448
- log(`[git-commits] readGitCommits failed for ${projectLabel}: ${message.slice(0, 500)}`);
173449
- return [];
173471
+ const failure = classifyGitLogFailure(message);
173472
+ if (failure === "transient") {
173473
+ log(`[git-commits] readGitCommits failed for ${projectLabel}: ${message.slice(0, 500)}`);
173474
+ } else {
173475
+ log(`[git-commits] ${projectLabel} is not indexable (${failure})`);
173476
+ }
173477
+ return { commits: [], failure };
173450
173478
  }
173451
173479
  if (stdout.trim().length === 0) {
173452
173480
  log(`[git-commits] readGitCommits returned empty stdout for ${projectLabel} (sinceMs=${options.sinceMs ?? "none"} args=${args.slice(0, 4).join(" ")})`);
173453
173481
  }
173454
- return parseGitLogOutput(stdout);
173482
+ return { commits: parseGitLogOutput(stdout), failure: null };
173455
173483
  }
173456
173484
  function parseGitLogOutput(stdout) {
173457
173485
  const commits = [];
@@ -173507,7 +173535,8 @@ async function indexCommitsForProject(db, projectPath, directory, options) {
173507
173535
  inserted: 0,
173508
173536
  updated: 0,
173509
173537
  evicted: 0,
173510
- embedded: 0
173538
+ embedded: 0,
173539
+ nonIndexable: false
173511
173540
  };
173512
173541
  if (indexInProgress.has(projectPath)) {
173513
173542
  log(`[git-commits] index already in progress for ${projectPath}, skipping`);
@@ -173517,12 +173546,17 @@ async function indexCommitsForProject(db, projectPath, directory, options) {
173517
173546
  try {
173518
173547
  const latestIndexed = getLatestIndexedCommitTimeMs(db, projectPath);
173519
173548
  const sinceMs = latestIndexed !== null ? Math.max(latestIndexed - 60000, Date.now() - options.sinceDays * MS_PER_DAY) : Date.now() - options.sinceDays * MS_PER_DAY;
173520
- const commits = await readGitCommits(directory, {
173549
+ const read = await readGitCommitsResult(directory, {
173521
173550
  sinceMs,
173522
173551
  maxCommits: options.maxCommits,
173523
173552
  projectIdentity: projectPath
173524
173553
  });
173554
+ const commits = read.commits;
173525
173555
  result.scanned = commits.length;
173556
+ if (read.failure === "not_a_repo" || read.failure === "no_head") {
173557
+ result.nonIndexable = true;
173558
+ return result;
173559
+ }
173526
173560
  if (commits.length === 0) {
173527
173561
  result.evicted = enforceProjectCap(db, projectPath, options.maxCommits);
173528
173562
  log(`[git-commits] no new commits for ${projectPath} (sinceMs=${sinceMs} latestIndexed=${latestIndexed ?? "none"} evicted=${result.evicted})`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/pi-magic-context",
3
- "version": "0.30.5",
3
+ "version": "0.30.6",
4
4
  "type": "module",
5
5
  "description": "Pi coding agent extension for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",