@cortexkit/pi-magic-context 0.30.4 → 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
@@ -156667,8 +156667,9 @@ init_logger();
156667
156667
 
156668
156668
  // src/subagent-runner.ts
156669
156669
  import * as childProcess from "node:child_process";
156670
- import { existsSync as existsSync7 } from "node:fs";
156670
+ import { existsSync as existsSync7, mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
156671
156671
  import { createRequire as createRequire2 } from "node:module";
156672
+ import { tmpdir as tmpdir2 } from "node:os";
156672
156673
  import { basename as basename2, dirname as dirname4, join as join8, resolve as resolvePath } from "node:path";
156673
156674
  import { createInterface } from "node:readline";
156674
156675
  import { fileURLToPath } from "node:url";
@@ -156889,9 +156890,11 @@ class PiSubagentRunner {
156889
156890
  harness = "pi";
156890
156891
  invocation;
156891
156892
  spawnImpl;
156893
+ platform;
156892
156894
  constructor(options = {}) {
156893
156895
  this.invocation = options.piBinary ? { command: options.piBinary, prefixArgs: [] } : resolvePiInvocation();
156894
156896
  this.spawnImpl = options.spawnImpl ?? childProcess.spawn;
156897
+ this.platform = options.platform ?? process.platform;
156895
156898
  }
156896
156899
  async run(options) {
156897
156900
  const models = [options.model, ...options.fallbackModels ?? []].filter((model) => typeof model === "string" && model.length > 0);
@@ -156950,10 +156953,47 @@ class PiSubagentRunner {
156950
156953
  }
156951
156954
  return result;
156952
156955
  }
156956
+ const failBeforeSpawn = (reason, error) => {
156957
+ const result = {
156958
+ ok: false,
156959
+ reason,
156960
+ error,
156961
+ durationMs: Date.now() - startTime
156962
+ };
156963
+ try {
156964
+ recordAccounting(result);
156965
+ } catch (err) {
156966
+ sessionLog(options.accountingSessionId ?? "subagent", `subagent accounting failed (continuing): ${err instanceof Error ? err.message : String(err)}`);
156967
+ }
156968
+ return result;
156969
+ };
156953
156970
  const promptBytes = Buffer.byteLength(options.userMessage, "utf8");
156954
- const deliverViaStdin = promptBytes > PROMPT_ARGV_MAX_BYTES;
156971
+ const deliverViaStdin = promptBytes > PROMPT_ARGV_MAX_BYTES || this.platform === "win32";
156972
+ let systemPromptTempDir;
156973
+ let systemPromptPath;
156974
+ const cleanupSystemPromptFile = () => {
156975
+ if (!systemPromptTempDir)
156976
+ return;
156977
+ const tempDir = systemPromptTempDir;
156978
+ systemPromptTempDir = undefined;
156979
+ systemPromptPath = undefined;
156980
+ try {
156981
+ rmSync2(tempDir, { recursive: true, force: true });
156982
+ } catch {}
156983
+ };
156984
+ if (options.systemPrompt.length > 0) {
156985
+ try {
156986
+ systemPromptTempDir = mkdtempSync2(join8(tmpdir2(), "mc-pi-prompt-"));
156987
+ systemPromptPath = join8(systemPromptTempDir, "system-prompt.txt");
156988
+ writeFileSync5(systemPromptPath, options.systemPrompt, "utf8");
156989
+ } catch (error) {
156990
+ cleanupSystemPromptFile();
156991
+ return failBeforeSpawn("spawn_failed", `failed to prepare pi system prompt file: ${error instanceof Error ? error.message : String(error)}`);
156992
+ }
156993
+ }
156955
156994
  const args = buildArgs(options, {
156956
- omitPositionalMessage: deliverViaStdin
156995
+ omitPositionalMessage: deliverViaStdin,
156996
+ systemPromptPath
156957
156997
  });
156958
156998
  return new Promise((resolve) => {
156959
156999
  let accountingMessages = [];
@@ -156962,6 +157002,7 @@ class PiSubagentRunner {
156962
157002
  if (settled)
156963
157003
  return;
156964
157004
  settled = true;
157005
+ cleanupSystemPromptFile();
156965
157006
  try {
156966
157007
  recordAccounting(result, accountingMessages);
156967
157008
  } catch (err) {
@@ -156987,6 +157028,7 @@ class PiSubagentRunner {
156987
157028
  stdio: [deliverViaStdin ? "pipe" : "ignore", "pipe", "pipe"]
156988
157029
  });
156989
157030
  } catch (error) {
157031
+ cleanupSystemPromptFile();
156990
157032
  settle({
156991
157033
  ok: false,
156992
157034
  reason: "spawn_failed",
@@ -157054,6 +157096,8 @@ class PiSubagentRunner {
157054
157096
  return;
157055
157097
  const parsed = parsePiEventLine(line);
157056
157098
  if (!parsed.ok) {
157099
+ if ("noise" in parsed)
157100
+ return;
157057
157101
  parseError = parsed.error;
157058
157102
  return;
157059
157103
  }
@@ -157280,7 +157324,8 @@ function buildArgs(options, opts) {
157280
157324
  "json",
157281
157325
  "--no-session",
157282
157326
  "--no-skills",
157283
- "--no-prompt-templates"
157327
+ "--no-prompt-templates",
157328
+ "--no-context-files"
157284
157329
  ];
157285
157330
  const shouldLoadSubagentExtension = SUBAGENT_ENTRY_PATH && (SEARCH_ONLY_SUBAGENT_TOOL_AGENTS.has(options.agent) || DREAMER_ACTION_AGENTS.has(options.agent));
157286
157331
  if (shouldLoadSubagentExtension) {
@@ -157300,8 +157345,8 @@ function buildArgs(options, opts) {
157300
157345
  args.push("--no-tools");
157301
157346
  }
157302
157347
  }
157303
- if (options.systemPrompt && options.systemPrompt.length > 0) {
157304
- args.push("--system-prompt", options.systemPrompt);
157348
+ if (opts?.systemPromptPath) {
157349
+ args.push("--system-prompt", opts.systemPromptPath);
157305
157350
  }
157306
157351
  if (typeof options.model === "string" && options.model.length > 0) {
157307
157352
  args.push("--model", resolveModelRefForPi(options.model));
@@ -157353,6 +157398,9 @@ function countToolCalls(messages) {
157353
157398
  return count;
157354
157399
  }
157355
157400
  function parsePiEventLine(line) {
157401
+ if (!line.trimStart().startsWith("{")) {
157402
+ return { ok: false, noise: true };
157403
+ }
157356
157404
  try {
157357
157405
  return { ok: true, event: JSON.parse(line) };
157358
157406
  } catch (error) {
@@ -172538,7 +172586,7 @@ var DreamTasksSchema = exports_external.object({
172538
172586
  }).describe("Per-task scheduling + model config. Each task has its own cron schedule and may override the dreamer-level model.");
172539
172587
  var DreamerConfigSchema = AgentOverrideConfigSchema.merge(exports_external.object({
172540
172588
  tasks: DreamTasksSchema.default(() => DreamTasksSchema.parse({})),
172541
- inject_docs: exports_external.boolean().default(true).describe("Inject ARCHITECTURE.md and STRUCTURE.md into system prompt"),
172589
+ inject_docs: exports_external.boolean().default(true).describe("Inject ARCHITECTURE.md and STRUCTURE.md into the m[0] `<project-docs>` block (default true)"),
172542
172590
  thinking_level: PiThinkingLevelSchema.describe("Pi only: default thinking level for dreamer subagent invocations. See historian.thinking_level.")
172543
172591
  }));
172544
172592
  var SidekickConfigSchema = AgentOverrideConfigSchema.extend({
@@ -174340,6 +174388,7 @@ function enforceProjectCap(db, projectPath, maxCommits) {
174340
174388
  // ../plugin/src/features/magic-context/git-commits/sweep-coordinator.ts
174341
174389
  var GIT_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
174342
174390
  var GIT_SWEEP_LEASE_TTL_MS = 5 * 60 * 1000;
174391
+ var GIT_SWEEP_NON_INDEXABLE_REPROBE_MS = 24 * 60 * 60 * 1000;
174343
174392
  var GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
174344
174393
  function runImmediate(db, body) {
174345
174394
  db.exec("BEGIN IMMEDIATE");
@@ -174446,6 +174495,20 @@ function markGitSweepSuccessAndRelease(db, projectPath, holderId) {
174446
174495
  return result.changes === 1;
174447
174496
  });
174448
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
+ }
174449
174512
  function releaseGitSweepLease(db, projectPath, holderId) {
174450
174513
  runImmediate(db, () => {
174451
174514
  db.prepare(`UPDATE git_sweep_coordinator
@@ -179044,7 +179107,7 @@ Output exactly JSON: {"met": false}`;
179044
179107
 
179045
179108
  // ../plugin/src/features/magic-context/dreamer/maintain-docs-protected-enforcement.ts
179046
179109
  init_logger();
179047
- import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
179110
+ import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
179048
179111
  import { join as join11 } from "node:path";
179049
179112
 
179050
179113
  // ../plugin/src/features/magic-context/dreamer/protected-regions.ts
@@ -179164,7 +179227,7 @@ function enforceMaintainDocsProtectedRegions(args) {
179164
179227
  if (!violated) {
179165
179228
  continue;
179166
179229
  }
179167
- writeFileSync5(path9, text, "utf8");
179230
+ writeFileSync6(path9, text, "utf8");
179168
179231
  log(`[dreamer] maintain-docs altered a protected region in ${fileName} — restored from pre-task snapshot`);
179169
179232
  } catch (error51) {
179170
179233
  log(`[dreamer] maintain-docs protected-region enforcement failed for ${fileName}: ${error51}`);
@@ -181614,11 +181677,21 @@ function recordTransientFailure(db, projectIdentity, due, finishedAt, error51) {
181614
181677
  });
181615
181678
  }
181616
181679
  }
181680
+ var LEASE_WAIT_POLL_MS = 2000;
181681
+ var MANUAL_RUN_LEASE_WAIT_MS = 60000;
181617
181682
  async function runDomainGroup(deps, group, cb) {
181618
181683
  const { db, projectIdentity, executor } = deps;
181619
181684
  const leaseKey = leaseKeyFor(group[0].config.task, projectIdentity);
181620
181685
  const holderId = crypto.randomUUID();
181621
- 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) {
181622
181695
  log(`[dreamer] domain lease busy (${leaseKey}) — deferring ${group.length} task(s)`);
181623
181696
  for (const due of group)
181624
181697
  cb?.onBusy?.(due.config.task);
@@ -181713,6 +181786,7 @@ async function runManualDream(deps) {
181713
181786
  }
181714
181787
  await Promise.all([...groups.values()].map((group) => runDomainGroup({ ...deps, executor: deps.executor }, group, {
181715
181788
  forceGate,
181789
+ leaseWaitMs: MANUAL_RUN_LEASE_WAIT_MS,
181716
181790
  onRan: (t) => result.ran.push(t),
181717
181791
  onFailed: (t) => result.failed.push(t),
181718
181792
  onBusy: (t) => result.deferredBusy.push(t)
@@ -181843,7 +181917,15 @@ var GIT_TIMEOUT_MS3 = 1e4;
181843
181917
  var DEFAULT_MAX_COMMITS = 5000;
181844
181918
  var RECORD_SEPARATOR = "\x1E";
181845
181919
  var FIELD_SEPARATOR = "\x1F";
181846
- 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 = {}) {
181847
181929
  const revision = options.branch ?? "HEAD";
181848
181930
  if (revision.startsWith("-")) {
181849
181931
  throw new Error(`readGitCommits: refusing revision that looks like an option: "${revision}"`);
@@ -181871,13 +181953,18 @@ async function readGitCommits(directory, options = {}) {
181871
181953
  stdout = result.stdout;
181872
181954
  } catch (error51) {
181873
181955
  const message = error51 instanceof Error ? error51.message : String(error51);
181874
- log(`[git-commits] readGitCommits failed for ${projectLabel}: ${message.slice(0, 500)}`);
181875
- 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 };
181876
181963
  }
181877
181964
  if (stdout.trim().length === 0) {
181878
181965
  log(`[git-commits] readGitCommits returned empty stdout for ${projectLabel} (sinceMs=${options.sinceMs ?? "none"} args=${args.slice(0, 4).join(" ")})`);
181879
181966
  }
181880
- return parseGitLogOutput(stdout);
181967
+ return { commits: parseGitLogOutput(stdout), failure: null };
181881
181968
  }
181882
181969
  function parseGitLogOutput(stdout) {
181883
181970
  const commits = [];
@@ -181933,7 +182020,8 @@ async function indexCommitsForProject(db, projectPath, directory, options) {
181933
182020
  inserted: 0,
181934
182021
  updated: 0,
181935
182022
  evicted: 0,
181936
- embedded: 0
182023
+ embedded: 0,
182024
+ nonIndexable: false
181937
182025
  };
181938
182026
  if (indexInProgress.has(projectPath)) {
181939
182027
  log(`[git-commits] index already in progress for ${projectPath}, skipping`);
@@ -181943,12 +182031,17 @@ async function indexCommitsForProject(db, projectPath, directory, options) {
181943
182031
  try {
181944
182032
  const latestIndexed = getLatestIndexedCommitTimeMs(db, projectPath);
181945
182033
  const sinceMs = latestIndexed !== null ? Math.max(latestIndexed - 60000, Date.now() - options.sinceDays * MS_PER_DAY) : Date.now() - options.sinceDays * MS_PER_DAY;
181946
- const commits = await readGitCommits(directory, {
182034
+ const read = await readGitCommitsResult(directory, {
181947
182035
  sinceMs,
181948
182036
  maxCommits: options.maxCommits,
181949
182037
  projectIdentity: projectPath
181950
182038
  });
182039
+ const commits = read.commits;
181951
182040
  result.scanned = commits.length;
182041
+ if (read.failure === "not_a_repo" || read.failure === "no_head") {
182042
+ result.nonIndexable = true;
182043
+ return result;
182044
+ }
181952
182045
  if (commits.length === 0) {
181953
182046
  result.evicted = enforceProjectCap(db, projectPath, options.maxCommits);
181954
182047
  log(`[git-commits] no new commits for ${projectPath} (sinceMs=${sinceMs} latestIndexed=${latestIndexed ?? "none"} evicted=${result.evicted})`);
@@ -182370,6 +182463,12 @@ async function sweepGitCommits(args) {
182370
182463
  sinceDays: gitCommitIndexing.since_days,
182371
182464
  maxCommits: gitCommitIndexing.max_commits
182372
182465
  });
182466
+ if (result.nonIndexable) {
182467
+ if (!parkGitSweepNonIndexable(db, projectIdentity, holderId)) {
182468
+ releaseGitSweepLease(db, projectIdentity, holderId);
182469
+ }
182470
+ return;
182471
+ }
182373
182472
  let drainedEmbeddings = 0;
182374
182473
  if (result.embedded > 0) {
182375
182474
  drainedEmbeddings = await embedUnembeddedCommits(db, projectIdentity);
@@ -184186,7 +184285,7 @@ Unknown task "${requested}".`,
184186
184285
  if (result.skippedNoWork.length > 0)
184187
184286
  lines.push(`Skipped (no work): ${result.skippedNoWork.join(", ")}`);
184188
184287
  if (result.deferredBusy.length > 0)
184189
- 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`);
184190
184289
  if (lines.length === 0)
184191
184290
  lines.push("No enabled dream tasks to run.");
184192
184291
  sendCtxStatusMessage(pi, {
@@ -189868,6 +189967,13 @@ function safeGetActiveUserMemoriesPi(db) {
189868
189967
  throw error51;
189869
189968
  }
189870
189969
  }
189970
+ var EMPTY_PI_PROJECT_DOCS = {
189971
+ renderedBlock: "",
189972
+ canonicalHash: ""
189973
+ };
189974
+ function readProjectDocsForPiM0(state) {
189975
+ return state.injectDocs !== false ? readProjectDocsCanonical(state.projectDirectory) : EMPTY_PI_PROJECT_DOCS;
189976
+ }
189871
189977
  function memoryProjectPath(state) {
189872
189978
  return state.memoryEnabled === false ? undefined : state.projectIdentity;
189873
189979
  }
@@ -189994,7 +190100,7 @@ function readCurrentMarkersFromCompartments(db, state, compartments, projectDocs
189994
190100
  projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
189995
190101
  workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(db, workspace.identities) : null,
189996
190102
  projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
189997
- projectDocsHash: projectDocsHash ?? readProjectDocsCanonical(state.projectDirectory).canonicalHash,
190103
+ projectDocsHash: projectDocsHash ?? readProjectDocsForPiM0(state).canonicalHash,
189998
190104
  sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
189999
190105
  materializedAt: Date.now(),
190000
190106
  upgradeState: `${PI_M0_UPGRADE_STATE}:${compartments.some((c) => c.legacy === 1) ? "legacy" : "ready"}`,
@@ -190055,7 +190161,7 @@ ${memories.map((memory) => `- ${escapeXmlContent(memory.content)}`).join(`
190055
190161
  `)}
190056
190162
  </${wrapper}>`;
190057
190163
  }
190058
- function renderM0Pi(state, db, projectDocs = readProjectDocsCanonical(state.projectDirectory).renderedBlock, decayPressureMultiplier = 1, memoriesOverride, compartmentsOverride, userProfileOverride, workspaceOverride) {
190164
+ function renderM0Pi(state, db, projectDocs = readProjectDocsForPiM0(state).renderedBlock, decayPressureMultiplier = 1, memoriesOverride, compartmentsOverride, userProfileOverride, workspaceOverride) {
190059
190165
  const memPath = memoryProjectPath(state);
190060
190166
  const workspace = workspaceOverride ?? resolveWorkspaceRenderContextPi(state, db);
190061
190167
  const allMemories = memoriesOverride ?? (memPath ? workspace.isWorkspaced ? getMemoriesByProjects(db, workspace.expandedIdentities, ["active", "permanent"], Date.now(), workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(db, memPath, ["active", "permanent"]) : []);
@@ -190123,7 +190229,7 @@ class PiMaterializeContentionError extends Error {
190123
190229
  this.name = "PiMaterializeContentionError";
190124
190230
  }
190125
190231
  }
190126
- function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.projectDirectory), memoryCutoff) {
190232
+ function readFrozenM0InputsPi(state, db, docs = readProjectDocsForPiM0(state), memoryCutoff) {
190127
190233
  const memPath = memoryProjectPath(state);
190128
190234
  const read = db.transaction(() => {
190129
190235
  const workspace = resolveWorkspaceRenderContextPi(state, db);
@@ -190154,7 +190260,7 @@ function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.p
190154
190260
  return read();
190155
190261
  }
190156
190262
  function renderFreshM0PiNonPersisted(state, db) {
190157
- const docs = readProjectDocsCanonical(state.projectDirectory);
190263
+ const docs = readProjectDocsForPiM0(state);
190158
190264
  const cachedMaterializedAt = getOrCreateSessionMeta(db, state.sessionId).cachedM0MaterializedAt ?? 0;
190159
190265
  const frozen = readFrozenM0InputsPi(state, db, docs, cachedMaterializedAt);
190160
190266
  frozen.markers.materializedAt = cachedMaterializedAt;
@@ -190174,7 +190280,7 @@ function renderFreshM0PiNonPersisted(state, db) {
190174
190280
  };
190175
190281
  }
190176
190282
  function materializeM0Pi(state, db) {
190177
- const docs = readProjectDocsCanonical(state.projectDirectory);
190283
+ const docs = readProjectDocsForPiM0(state);
190178
190284
  const foldMaterializedAt = Date.now();
190179
190285
  const frozen = readFrozenM0InputsPi(state, db, docs, foldMaterializedAt);
190180
190286
  const snapshotMarkers = frozen.markers;
@@ -190192,7 +190298,7 @@ function materializeM0Pi(state, db) {
190192
190298
  attempts += 1;
190193
190299
  }
190194
190300
  const m0Bytes = Buffer.from(m0, "utf8");
190195
- const phase3ProjectDocsHash = readProjectDocsCanonical(state.projectDirectory).canonicalHash;
190301
+ const phase3ProjectDocsHash = readProjectDocsForPiM0(state).canonicalHash;
190196
190302
  try {
190197
190303
  db.exec("BEGIN IMMEDIATE");
190198
190304
  } catch (error51) {
@@ -194524,6 +194630,9 @@ function getMessageId(message) {
194524
194630
  }
194525
194631
  return "";
194526
194632
  }
194633
+ function isReplayableAnchor(message) {
194634
+ return message.stopReason !== "aborted" && message.stopReason !== "error";
194635
+ }
194527
194636
  function hasToolCallWithId(message, callId) {
194528
194637
  if (!Array.isArray(message.content))
194529
194638
  return false;
@@ -194580,6 +194689,8 @@ function injectByAssistantId(messages, messageId, part) {
194580
194689
  const assistant = m;
194581
194690
  if (getMessageId(assistant) !== messageId)
194582
194691
  continue;
194692
+ if (!isReplayableAnchor(assistant))
194693
+ return false;
194583
194694
  if (hasToolCallWithId(assistant, part.callID)) {
194584
194695
  if (findToolResultAfter(messages, i, part.callID) >= 0)
194585
194696
  return true;
@@ -194605,6 +194716,8 @@ function injectIntoLatestAssistant(messages, part) {
194605
194716
  if (m.role !== "assistant")
194606
194717
  continue;
194607
194718
  const assistant = m;
194719
+ if (!isReplayableAnchor(assistant))
194720
+ continue;
194608
194721
  const id = getMessageId(assistant);
194609
194722
  if (id.length === 0)
194610
194723
  continue;
@@ -197323,6 +197436,7 @@ async function runPipeline(args) {
197323
197436
  projectIdentity: args.projectIdentity,
197324
197437
  projectDirectory: args.projectDirectory,
197325
197438
  memoryEnabled: args.injection.memoryEnabled,
197439
+ injectDocs: args.injection.injectDocs,
197326
197440
  injectionBudgetTokens: args.injection.injectionBudgetTokens,
197327
197441
  historyBudgetTokens: args.injection.historyBudgetTokens,
197328
197442
  hardSignals: piHardSignals
@@ -197634,7 +197748,7 @@ ${result}`;
197634
197748
  init_logger();
197635
197749
 
197636
197750
  // ../plugin/src/hooks/magic-context/historian-state-file.ts
197637
- import { mkdirSync as mkdirSync8, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
197751
+ import { mkdirSync as mkdirSync8, unlinkSync as unlinkSync2, writeFileSync as writeFileSync7 } from "node:fs";
197638
197752
  init_data_path();
197639
197753
  function cleanupHistorianStateFile(path11) {
197640
197754
  if (!path11)
@@ -197727,7 +197841,7 @@ function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEn
197727
197841
  }
197728
197842
 
197729
197843
  // ../plugin/src/hooks/magic-context/compartment-runner-historian.ts
197730
- import { mkdirSync as mkdirSync9, unlinkSync as unlinkSync3, writeFileSync as writeFileSync7 } from "node:fs";
197844
+ import { mkdirSync as mkdirSync9, unlinkSync as unlinkSync3, writeFileSync as writeFileSync8 } from "node:fs";
197731
197845
  import { join as join12 } from "node:path";
197732
197846
 
197733
197847
  // ../plugin/src/agents/historian.ts
@@ -198047,7 +198161,7 @@ function dumpHistorianResponse(sessionId, directory, label, text) {
198047
198161
  const safeSessionId = sanitizeDumpName(sessionId);
198048
198162
  const safeLabel = sanitizeDumpName(label);
198049
198163
  const dumpPath = join12(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
198050
- writeFileSync7(dumpPath, text, "utf8");
198164
+ writeFileSync8(dumpPath, text, "utf8");
198051
198165
  sessionLog(sessionId, "compartment agent: historian response dumped", {
198052
198166
  label,
198053
198167
  dumpPath
@@ -200012,7 +200126,7 @@ function formatThresholdPercent(value) {
200012
200126
  // package.json
200013
200127
  var package_default = {
200014
200128
  name: "@cortexkit/pi-magic-context",
200015
- version: "0.30.4",
200129
+ version: "0.30.6",
200016
200130
  type: "module",
200017
200131
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
200018
200132
  main: "dist/index.js",
@@ -206458,6 +206572,7 @@ async function src_default2(pi) {
206458
206572
  },
206459
206573
  injection: {
206460
206574
  memoryEnabled: cfg.memory.enabled,
206575
+ injectDocs: cfg.dreamer?.inject_docs !== false,
206461
206576
  injectionBudgetTokens: cfg.memory.injection_budget_tokens,
206462
206577
  temporalAwareness: cfg.temporal_awareness === true
206463
206578
  },
@@ -206686,13 +206801,11 @@ async function src_default2(pi) {
206686
206801
  }
206687
206802
  const isCacheBusting = sessionId ? hasSystemPromptRefresh(sessionId) : true;
206688
206803
  const effectiveDreamerRunnable = switchedProject ? isDreamerRunnable(effectiveConfig) : isDreamerRunnable(config2);
206689
- const injectDocs = switchedProject ? effectiveDreamerRunnable && (effectiveConfig.dreamer?.inject_docs ?? true) : isDreamerRunnable(config2) && (config2.dreamer?.inject_docs ?? true);
206690
206804
  const block = buildMagicContextBlock({
206691
206805
  db,
206692
206806
  cwd: currentProject.projectDir,
206693
206807
  sessionId,
206694
206808
  memoryEnabled: effectiveConfig.memory.enabled,
206695
- injectDocs,
206696
206809
  includeGuidance: true,
206697
206810
  protectedTags: effectiveConfig.protected_tags,
206698
206811
  ctxReduceEnabled: effectiveConfig.ctx_reduce_enabled,
@@ -159656,7 +159656,7 @@ var DreamTasksSchema = exports_external.object({
159656
159656
  }).describe("Per-task scheduling + model config. Each task has its own cron schedule and may override the dreamer-level model.");
159657
159657
  var DreamerConfigSchema = AgentOverrideConfigSchema.merge(exports_external.object({
159658
159658
  tasks: DreamTasksSchema.default(() => DreamTasksSchema.parse({})),
159659
- inject_docs: exports_external.boolean().default(true).describe("Inject ARCHITECTURE.md and STRUCTURE.md into system prompt"),
159659
+ inject_docs: exports_external.boolean().default(true).describe("Inject ARCHITECTURE.md and STRUCTURE.md into the m[0] `<project-docs>` block (default true)"),
159660
159660
  thinking_level: PiThinkingLevelSchema.describe("Pi only: default thinking level for dreamer subagent invocations. See historian.thinking_level.")
159661
159661
  }));
159662
159662
  var SidekickConfigSchema = AgentOverrideConfigSchema.extend({
@@ -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.4",
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",