@cortexkit/magic-context 0.21.4 → 0.21.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.
Files changed (2) hide show
  1. package/dist/index.js +155 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -27378,6 +27378,21 @@ import { dirname as dirname7, isAbsolute, resolve as resolve2 } from "node:path"
27378
27378
  function substituteConfigVariables(input) {
27379
27379
  const warnings = [];
27380
27380
  let text2 = input.text;
27381
+ if (input.isProjectConfig) {
27382
+ const hasEnvTokens = ENV_PATTERN.test(text2);
27383
+ const hasFileTokens = FILE_PATTERN.test(text2);
27384
+ ENV_PATTERN.lastIndex = 0;
27385
+ FILE_PATTERN.lastIndex = 0;
27386
+ if (hasEnvTokens || hasFileTokens) {
27387
+ const tokenTypes = [
27388
+ hasEnvTokens ? "{env:}" : undefined,
27389
+ hasFileTokens ? "{file:}" : undefined
27390
+ ].filter(Boolean).join(" and ");
27391
+ warnings.push(`Project-level config no longer supports ${tokenTypes} tokens for security reasons; leaving tokens literal. Move secret expansion to user-level config.`);
27392
+ }
27393
+ return { text: text2, warnings };
27394
+ }
27395
+ text2 = stripJsonComments(text2);
27381
27396
  text2 = text2.replace(ENV_PATTERN, (_, rawName) => {
27382
27397
  const varName = rawName.trim();
27383
27398
  const value = varName ? process.env[varName] : undefined;
@@ -27385,7 +27400,7 @@ function substituteConfigVariables(input) {
27385
27400
  warnings.push(`Environment variable ${varName} is not set (referenced via {env:${varName}}); using empty string`);
27386
27401
  return "";
27387
27402
  }
27388
- return value;
27403
+ return JSON.stringify(value).slice(1, -1);
27389
27404
  });
27390
27405
  const fileMatches = Array.from(text2.matchAll(FILE_PATTERN));
27391
27406
  if (fileMatches.length === 0) {
@@ -27432,6 +27447,7 @@ function substituteConfigVariables(input) {
27432
27447
  }
27433
27448
  var ENV_PATTERN, FILE_PATTERN;
27434
27449
  var init_variable = __esm(() => {
27450
+ init_jsonc_parser();
27435
27451
  ENV_PATTERN = /\{env:([^}]+)\}/g;
27436
27452
  FILE_PATTERN = /\{file:([^}]+)\}/g;
27437
27453
  });
@@ -27447,13 +27463,17 @@ function getUserConfigBasePath() {
27447
27463
  function getProjectConfigBasePath(directory) {
27448
27464
  return join11(directory, ".opencode", CONFIG_FILE_BASENAME);
27449
27465
  }
27450
- function loadConfigFile(configPath) {
27466
+ function loadConfigFile(configPath, isProjectConfig = false) {
27451
27467
  try {
27452
27468
  if (!existsSync13(configPath)) {
27453
27469
  return null;
27454
27470
  }
27455
27471
  const rawText = readFileSync8(configPath, "utf-8");
27456
- const substituted = substituteConfigVariables({ text: rawText, configPath });
27472
+ const substituted = substituteConfigVariables({
27473
+ text: rawText,
27474
+ configPath,
27475
+ isProjectConfig
27476
+ });
27457
27477
  return {
27458
27478
  config: parseJsonc3(substituted.text),
27459
27479
  warnings: substituted.warnings.map((w3) => `${configPath}: ${w3}`)
@@ -27617,7 +27637,7 @@ function loadPluginConfig(directory) {
27617
27637
  const dotOpenCodeDetected = detectConfigFile(getProjectConfigBasePath(directory));
27618
27638
  const projectDetected = rootDetected.format !== "none" ? rootDetected : dotOpenCodeDetected;
27619
27639
  const userLoaded = userDetected.format === "none" ? null : loadConfigFile(userDetected.path);
27620
- const projectLoaded = projectDetected.format === "none" ? null : loadConfigFile(projectDetected.path);
27640
+ const projectLoaded = projectDetected.format === "none" ? null : loadConfigFile(projectDetected.path, true);
27621
27641
  const allWarnings = [];
27622
27642
  let mergedRaw = {};
27623
27643
  if (userLoaded) {
@@ -28543,6 +28563,91 @@ var init_diagnostics_opencode = __esm(() => {
28543
28563
  PLUGIN_ENTRY_WITH_VERSION = `${PLUGIN_NAME5}@latest`;
28544
28564
  });
28545
28565
 
28566
+ // src/lib/issue-body.ts
28567
+ function isErrorLogLine(line) {
28568
+ return ERROR_LOG_PATTERNS.some((rx) => rx.test(line));
28569
+ }
28570
+ function extractRecentErrors(sanitized, limit = 20) {
28571
+ const matches = [];
28572
+ const lines = sanitized.split(/\r?\n/);
28573
+ for (let i = lines.length - 1;i >= 0 && matches.length < limit; i -= 1) {
28574
+ if (isErrorLogLine(lines[i])) {
28575
+ matches.push(lines[i]);
28576
+ }
28577
+ }
28578
+ return matches.reverse();
28579
+ }
28580
+ function capBodyToGithubLimit(body, maxBytes = MAX_GITHUB_BODY_BYTES) {
28581
+ if (Buffer.byteLength(body, "utf8") <= maxBytes)
28582
+ return body;
28583
+ const heading = "## Log (last";
28584
+ const headingIdx = body.indexOf(heading);
28585
+ if (headingIdx === -1) {
28586
+ const marker = `
28587
+
28588
+ [truncated for GitHub 64KB limit]
28589
+ `;
28590
+ const markerBytes2 = Buffer.byteLength(marker, "utf8");
28591
+ return truncateToByteBudget(body, maxBytes - markerBytes2) + marker;
28592
+ }
28593
+ const fenceOpenIdx = body.indexOf("\n```", headingIdx);
28594
+ if (fenceOpenIdx === -1)
28595
+ return body;
28596
+ const logStart = fenceOpenIdx + "\n```\n".length;
28597
+ const fenceCloseIdx = body.indexOf("\n```", logStart);
28598
+ if (fenceCloseIdx === -1)
28599
+ return body;
28600
+ const head = body.slice(0, logStart);
28601
+ const log3 = body.slice(logStart, fenceCloseIdx);
28602
+ const tail = body.slice(fenceCloseIdx);
28603
+ const overheadBytes = Buffer.byteLength(head, "utf8") + Buffer.byteLength(tail, "utf8");
28604
+ const truncationMarker = `[truncated for GitHub 64KB limit — older log lines dropped]
28605
+ `;
28606
+ const markerBytes = Buffer.byteLength(truncationMarker, "utf8");
28607
+ const logBudget = maxBytes - overheadBytes - markerBytes;
28608
+ if (logBudget <= 0) {
28609
+ return `${head}${truncationMarker}${tail}`;
28610
+ }
28611
+ const lines = log3.split(`
28612
+ `);
28613
+ let keepLines = lines;
28614
+ let kept = keepLines.join(`
28615
+ `);
28616
+ while (Buffer.byteLength(kept, "utf8") > logBudget && keepLines.length > 1) {
28617
+ const dropCount = Math.max(1, Math.floor(keepLines.length * 0.05));
28618
+ keepLines = keepLines.slice(dropCount);
28619
+ kept = keepLines.join(`
28620
+ `);
28621
+ }
28622
+ if (Buffer.byteLength(kept, "utf8") > logBudget) {
28623
+ kept = truncateToByteBudget(kept, logBudget);
28624
+ }
28625
+ return `${head}${truncationMarker}${kept}${tail}`;
28626
+ }
28627
+ function truncateToByteBudget(input, maxBytes) {
28628
+ if (maxBytes <= 0)
28629
+ return "";
28630
+ const buf = Buffer.from(input, "utf8");
28631
+ if (buf.length <= maxBytes)
28632
+ return input;
28633
+ let end = maxBytes;
28634
+ while (end > 0 && (buf[end] & 192) === 128) {
28635
+ end -= 1;
28636
+ }
28637
+ return buf.subarray(0, end).toString("utf8");
28638
+ }
28639
+ var MAX_GITHUB_BODY_BYTES = 60000, ERROR_LOG_PATTERNS;
28640
+ var init_issue_body = __esm(() => {
28641
+ ERROR_LOG_PATTERNS = [
28642
+ /\bfailed:/i,
28643
+ /\b(?:[A-Z][a-zA-Z]*)?Error:\s/,
28644
+ /\bEMERGENCY\b/,
28645
+ /\bexception\b/i,
28646
+ /^\s+at\s+[\w.<>$]+\s+\(/,
28647
+ /^\s+at\s+(?:file:|node_modules\/|[^/\s]+:\d+)/
28648
+ ];
28649
+ });
28650
+
28546
28651
  // src/lib/logs-opencode.ts
28547
28652
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "node:fs";
28548
28653
  import { homedir as homedir12 } from "node:os";
@@ -28595,9 +28700,12 @@ async function bundleIssueReport(report, description, _title, sessionFilter = nu
28595
28700
  const historianScanWindow = sanitizeLogContent(logLines.slice(-4000).join(`
28596
28701
  `));
28597
28702
  const historianFailureLines = extractHistorianFailureLines(historianScanWindow, 30);
28703
+ const errorScanWindow = sanitizeLogContent(logLines.slice(-4000).join(`
28704
+ `));
28705
+ const recentErrorLines = extractRecentErrors(errorScanWindow, 20);
28598
28706
  const configBody = JSON.stringify(sanitizeConfigValue(report.magicContextConfig.flags), null, 2);
28599
28707
  const sanitizedConfigPath = report.configPaths.magicContextConfig.replace(homedir12(), "~");
28600
- const bodyMarkdown = [
28708
+ const rawBodyMarkdown = [
28601
28709
  "## Description",
28602
28710
  description,
28603
28711
  "",
@@ -28619,6 +28727,11 @@ async function bundleIssueReport(report, description, _title, sessionFilter = nu
28619
28727
  "## Historian failure signals (log, sanitized)",
28620
28728
  historianFailureLines.length === 0 ? "_No historian failure log lines found in recent history._" : ["```", historianFailureLines.join(`
28621
28729
  `), "```"].join(`
28730
+ `),
28731
+ "",
28732
+ "## Recent errors (last 20, sanitized)",
28733
+ recentErrorLines.length === 0 ? "_No error-shaped log lines found in recent history._" : ["```", recentErrorLines.join(`
28734
+ `), "```"].join(`
28622
28735
  `),
28623
28736
  "",
28624
28737
  `## Log (last ${LOG_TAIL_LINES} lines, sanitized)`,
@@ -28627,6 +28740,7 @@ async function bundleIssueReport(report, description, _title, sessionFilter = nu
28627
28740
  "```"
28628
28741
  ].join(`
28629
28742
  `);
28743
+ const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
28630
28744
  const path4 = join15(process.cwd(), `magic-context-issue-${formatTimestamp(new Date)}.md`);
28631
28745
  writeFileSync9(path4, `${bodyMarkdown}
28632
28746
  `);
@@ -28635,6 +28749,7 @@ async function bundleIssueReport(report, description, _title, sessionFilter = nu
28635
28749
  var HISTORIAN_LOG_PATTERNS;
28636
28750
  var init_logs_opencode = __esm(() => {
28637
28751
  init_diagnostics_opencode();
28752
+ init_issue_body();
28638
28753
  init_redaction();
28639
28754
  HISTORIAN_LOG_PATTERNS = [
28640
28755
  /historian failure:/,
@@ -162015,8 +162130,10 @@ function deleteOrphanProjectKeyFiles(db, now = Date.now()) {
162015
162130
  if (existsSync18(row.projectPath))
162016
162131
  continue;
162017
162132
  try {
162018
- db.prepare("DELETE FROM project_key_files WHERE project_path = ?").run(row.projectPath);
162019
- db.prepare("DELETE FROM project_key_files_version WHERE project_path = ?").run(row.projectPath);
162133
+ db.transaction(() => {
162134
+ db.prepare("DELETE FROM project_key_files WHERE project_path = ?").run(row.projectPath);
162135
+ db.prepare("DELETE FROM project_key_files_version WHERE project_path = ?").run(row.projectPath);
162136
+ })();
162020
162137
  deletedProjects++;
162021
162138
  } catch (error51) {
162022
162139
  log2(`[key-files] orphan GC failed for ${row.projectPath}:`, error51);
@@ -162044,7 +162161,7 @@ function getCurrentVersion(db) {
162044
162161
  const row = db.prepare("SELECT MAX(version) as version FROM schema_migrations").get();
162045
162162
  return row?.version ?? 0;
162046
162163
  }
162047
- function isSiblingMigrationConflict(error51, version2) {
162164
+ function isSiblingMigrationConflict(db, error51, version2) {
162048
162165
  if (!(error51 instanceof Error))
162049
162166
  return false;
162050
162167
  const code = error51.code;
@@ -162056,7 +162173,8 @@ function isSiblingMigrationConflict(error51, version2) {
162056
162173
  return false;
162057
162174
  if (!msg.toLowerCase().includes("version"))
162058
162175
  return false;
162059
- return true;
162176
+ const confirmed = db.prepare("SELECT 1 FROM schema_migrations WHERE version = ?").get(version2);
162177
+ return confirmed != null;
162060
162178
  }
162061
162179
  function runMigrations(db) {
162062
162180
  ensureMigrationsTable(db);
@@ -162077,7 +162195,7 @@ function runMigrations(db) {
162077
162195
  log2(`[migrations] applied v${migration.version}: ${migration.description}`);
162078
162196
  migrationIndex += 1;
162079
162197
  } catch (error51) {
162080
- if (isSiblingMigrationConflict(error51, migration.version)) {
162198
+ if (isSiblingMigrationConflict(db, error51, migration.version)) {
162081
162199
  log2(`[migrations] v${migration.version} already applied by sibling instance — resuming with re-read version`);
162082
162200
  const reReadVersion = getCurrentVersion(db);
162083
162201
  if (reReadVersion <= currentVersion) {
@@ -162483,6 +162601,16 @@ var init_migrations = __esm(async () => {
162483
162601
  WHERE auto_search_hint_decisions IS NULL
162484
162602
  `);
162485
162603
  }
162604
+ },
162605
+ {
162606
+ version: 18,
162607
+ description: "Add pending_pi_compaction_marker_state column for Pi deferred marker drain",
162608
+ up: (db) => {
162609
+ const cols = db.prepare("PRAGMA table_info(session_meta)").all();
162610
+ if (!cols.some((c2) => c2.name === "pending_pi_compaction_marker_state")) {
162611
+ db.exec("ALTER TABLE session_meta ADD COLUMN pending_pi_compaction_marker_state TEXT");
162612
+ }
162613
+ }
162486
162614
  }
162487
162615
  ];
162488
162616
  });
@@ -163046,6 +163174,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
163046
163174
  -- Excluded from healNullTextColumns. Readers filter IS NOT NULL AND
163047
163175
  -- != empty-string defensively. Plan v6 section 3.
163048
163176
  pending_compaction_marker_state TEXT,
163177
+ -- pending_pi_compaction_marker_state: intentionally NULLABLE without a
163178
+ -- default. Absence of a deferred Pi-native marker is SQL NULL; presence
163179
+ -- is a valid JSON blob written via setPendingPiCompactionMarkerState.
163180
+ -- Excluded from healNullTextColumns.
163181
+ pending_pi_compaction_marker_state TEXT,
163049
163182
  -- deferred_execute_state: intentionally NULLABLE without a default.
163050
163183
  -- Absence is SQL NULL; presence is a JSON blob written via
163051
163184
  -- setDeferredExecutePendingIfAbsent. Excluded from healNullTextColumns.
@@ -163142,6 +163275,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
163142
163275
  ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
163143
163276
  ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
163144
163277
  ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
163278
+ ensureColumn(db, "session_meta", "pending_pi_compaction_marker_state", "TEXT");
163145
163279
  ensureColumn(db, "session_meta", "deferred_execute_state", "TEXT");
163146
163280
  ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
163147
163281
  ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
@@ -163969,7 +164103,10 @@ async function bundleIssueReport2(report, description, title, options = {}) {
163969
164103
  const logLines = filterLogLinesBySession2(allLogLines, options.sessionFilter ?? null);
163970
164104
  const recentLog = sanitizeLogContent2(logLines.slice(-LOG_TAIL_LINES).join(`
163971
164105
  `)).trim();
163972
- const bodyMarkdown = [
164106
+ const errorScanWindow = sanitizeLogContent2(logLines.slice(-4000).join(`
164107
+ `));
164108
+ const recentErrorLines = extractRecentErrors(errorScanWindow, 20);
164109
+ const rawBodyMarkdown = [
163973
164110
  "## Title",
163974
164111
  `[pi] ${sanitizeString2(title)}`,
163975
164112
  "",
@@ -163984,6 +164121,11 @@ async function bundleIssueReport2(report, description, title, options = {}) {
163984
164121
  "",
163985
164122
  "## Diagnostics",
163986
164123
  renderDiagnosticsMarkdown2(report),
164124
+ "",
164125
+ "## Recent errors (last 20, sanitized)",
164126
+ recentErrorLines.length === 0 ? "_No error-shaped log lines found in recent history._" : ["```", recentErrorLines.join(`
164127
+ `), "```"].join(`
164128
+ `),
163987
164129
  "",
163988
164130
  `## Log (last ${LOG_TAIL_LINES} lines, sanitized)`,
163989
164131
  "```",
@@ -163991,6 +164133,7 @@ async function bundleIssueReport2(report, description, title, options = {}) {
163991
164133
  "```"
163992
164134
  ].join(`
163993
164135
  `);
164136
+ const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
163994
164137
  const cwd = options.cwd ?? process.cwd();
163995
164138
  const path4 = join21(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
163996
164139
  writeFileSync11(path4, `${bodyMarkdown}
@@ -163999,6 +164142,7 @@ async function bundleIssueReport2(report, description, title, options = {}) {
163999
164142
  }
164000
164143
  var init_logs_pi = __esm(() => {
164001
164144
  init_diagnostics_pi();
164145
+ init_issue_body();
164002
164146
  });
164003
164147
 
164004
164148
  // src/commands/doctor-pi.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/magic-context",
3
- "version": "0.21.4",
3
+ "version": "0.21.6",
4
4
  "description": "Unified CLI for Magic Context — setup, doctor, and migration across OpenCode and Pi",
5
5
  "keywords": [
6
6
  "opencode",