@cortexkit/magic-context 0.41.3 → 0.41.4

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 +2080 -1429
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2885,7 +2885,7 @@ class OmpAdapter {
2885
2885
  return { path, exists: existsSync5(path), sizeBytes: dirSizeBytes(path) };
2886
2886
  }
2887
2887
  getLogPath() {
2888
- return getMagicContextLogPath2("pi");
2888
+ return getMagicContextLogPath2("omp");
2889
2889
  }
2890
2890
  getInstalledPluginVersion() {
2891
2891
  const omp = this.deps.detectOmpBinary();
@@ -11192,883 +11192,336 @@ var init_opencode = __esm(() => {
11192
11192
  import_comment_json = __toESM(require_src3(), 1);
11193
11193
  });
11194
11194
 
11195
- // ../plugin/src/shared/jsonc-parser.ts
11196
- import { existsSync as existsSync8, readFileSync as readFileSync5 } from "node:fs";
11197
- function stripJsonComments(content) {
11198
- let result = "";
11199
- let inString = false;
11200
- let escaped = false;
11201
- let inLineComment = false;
11202
- let inBlockComment = false;
11203
- for (let index = 0;index < content.length; index += 1) {
11204
- const char = content[index];
11205
- const next = content[index + 1];
11206
- if (inLineComment) {
11207
- if (char === `
11208
- `) {
11209
- inLineComment = false;
11210
- result += char;
11195
+ // ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
11196
+ function createScanner(text, ignoreTrivia = false) {
11197
+ const len = text.length;
11198
+ let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
11199
+ function scanHexDigits(count, exact) {
11200
+ let digits = 0;
11201
+ let value = 0;
11202
+ while (digits < count || !exact) {
11203
+ let ch = text.charCodeAt(pos);
11204
+ if (ch >= 48 && ch <= 57) {
11205
+ value = value * 16 + ch - 48;
11206
+ } else if (ch >= 65 && ch <= 70) {
11207
+ value = value * 16 + ch - 65 + 10;
11208
+ } else if (ch >= 97 && ch <= 102) {
11209
+ value = value * 16 + ch - 97 + 10;
11210
+ } else {
11211
+ break;
11211
11212
  }
11212
- continue;
11213
+ pos++;
11214
+ digits++;
11213
11215
  }
11214
- if (inBlockComment) {
11215
- if (char === "*" && next === "/") {
11216
- inBlockComment = false;
11217
- index += 1;
11218
- }
11219
- continue;
11216
+ if (digits < count) {
11217
+ value = -1;
11220
11218
  }
11221
- if (inString) {
11222
- result += char;
11223
- if (escaped) {
11224
- escaped = false;
11225
- } else if (char === "\\") {
11226
- escaped = true;
11227
- } else if (char === '"') {
11228
- inString = false;
11219
+ return value;
11220
+ }
11221
+ function setPosition(newPosition) {
11222
+ pos = newPosition;
11223
+ value = "";
11224
+ tokenOffset = 0;
11225
+ token = 16;
11226
+ scanError = 0;
11227
+ }
11228
+ function scanNumber() {
11229
+ let start = pos;
11230
+ if (text.charCodeAt(pos) === 48) {
11231
+ pos++;
11232
+ } else {
11233
+ pos++;
11234
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
11235
+ pos++;
11229
11236
  }
11230
- continue;
11231
- }
11232
- if (char === '"') {
11233
- inString = true;
11234
- result += char;
11235
- continue;
11236
11237
  }
11237
- if (char === "/" && next === "/") {
11238
- inLineComment = true;
11239
- index += 1;
11240
- continue;
11238
+ if (pos < text.length && text.charCodeAt(pos) === 46) {
11239
+ pos++;
11240
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
11241
+ pos++;
11242
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
11243
+ pos++;
11244
+ }
11245
+ } else {
11246
+ scanError = 3;
11247
+ return text.substring(start, pos);
11248
+ }
11241
11249
  }
11242
- if (char === "/" && next === "*") {
11243
- inBlockComment = true;
11244
- index += 1;
11245
- continue;
11250
+ let end = pos;
11251
+ if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
11252
+ pos++;
11253
+ if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
11254
+ pos++;
11255
+ }
11256
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
11257
+ pos++;
11258
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
11259
+ pos++;
11260
+ }
11261
+ end = pos;
11262
+ } else {
11263
+ scanError = 3;
11264
+ }
11246
11265
  }
11247
- result += char;
11266
+ return text.substring(start, end);
11248
11267
  }
11249
- return result;
11250
- }
11251
- function stripTrailingCommas(content) {
11252
- let result = "";
11253
- let inString = false;
11254
- let escaped = false;
11255
- for (let index = 0;index < content.length; index += 1) {
11256
- const char = content[index];
11257
- if (inString) {
11258
- result += char;
11259
- if (escaped) {
11260
- escaped = false;
11261
- } else if (char === "\\") {
11262
- escaped = true;
11263
- } else if (char === '"') {
11264
- inString = false;
11268
+ function scanString() {
11269
+ let result = "", start = pos;
11270
+ while (true) {
11271
+ if (pos >= len) {
11272
+ result += text.substring(start, pos);
11273
+ scanError = 2;
11274
+ break;
11265
11275
  }
11266
- continue;
11267
- }
11268
- if (char === '"') {
11269
- inString = true;
11270
- result += char;
11271
- continue;
11272
- }
11273
- if (char === ",") {
11274
- let lookahead = index + 1;
11275
- while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
11276
- lookahead += 1;
11276
+ const ch = text.charCodeAt(pos);
11277
+ if (ch === 34) {
11278
+ result += text.substring(start, pos);
11279
+ pos++;
11280
+ break;
11277
11281
  }
11278
- const next = content[lookahead];
11279
- if (next === "}" || next === "]") {
11282
+ if (ch === 92) {
11283
+ result += text.substring(start, pos);
11284
+ pos++;
11285
+ if (pos >= len) {
11286
+ scanError = 2;
11287
+ break;
11288
+ }
11289
+ const ch2 = text.charCodeAt(pos++);
11290
+ switch (ch2) {
11291
+ case 34:
11292
+ result += '"';
11293
+ break;
11294
+ case 92:
11295
+ result += "\\";
11296
+ break;
11297
+ case 47:
11298
+ result += "/";
11299
+ break;
11300
+ case 98:
11301
+ result += "\b";
11302
+ break;
11303
+ case 102:
11304
+ result += "\f";
11305
+ break;
11306
+ case 110:
11307
+ result += `
11308
+ `;
11309
+ break;
11310
+ case 114:
11311
+ result += "\r";
11312
+ break;
11313
+ case 116:
11314
+ result += "\t";
11315
+ break;
11316
+ case 117:
11317
+ const ch3 = scanHexDigits(4, true);
11318
+ if (ch3 >= 0) {
11319
+ result += String.fromCharCode(ch3);
11320
+ } else {
11321
+ scanError = 4;
11322
+ }
11323
+ break;
11324
+ default:
11325
+ scanError = 5;
11326
+ }
11327
+ start = pos;
11280
11328
  continue;
11281
11329
  }
11330
+ if (ch >= 0 && ch <= 31) {
11331
+ if (isLineBreak(ch)) {
11332
+ result += text.substring(start, pos);
11333
+ scanError = 2;
11334
+ break;
11335
+ } else {
11336
+ scanError = 6;
11337
+ }
11338
+ }
11339
+ pos++;
11282
11340
  }
11283
- result += char;
11284
- }
11285
- return result;
11286
- }
11287
- function isPrototypePollutionKey(key) {
11288
- return PROTOTYPE_POLLUTION_KEYS.has(key);
11289
- }
11290
- function sanitizeParsedJson(value, options = {}, path = []) {
11291
- if (Array.isArray(value)) {
11292
- return value.map((entry, index) => sanitizeParsedJson(entry, options, [...path, index]));
11293
- }
11294
- if (value === null || typeof value !== "object")
11295
- return value;
11296
- const source = value;
11297
- const sourcePrototype = Object.getPrototypeOf(source);
11298
- if (sourcePrototype !== null && sourcePrototype !== Object.prototype) {
11299
- options.onRejectedKey?.([...path, "__proto__"]);
11341
+ return result;
11300
11342
  }
11301
- const sanitized = {};
11302
- for (const key of Object.keys(source)) {
11303
- if (isPrototypePollutionKey(key)) {
11304
- options.onRejectedKey?.([...path, key]);
11305
- continue;
11343
+ function scanNext() {
11344
+ value = "";
11345
+ scanError = 0;
11346
+ tokenOffset = pos;
11347
+ lineStartOffset = lineNumber;
11348
+ prevTokenLineStartOffset = tokenLineStartOffset;
11349
+ if (pos >= len) {
11350
+ tokenOffset = len;
11351
+ return token = 17;
11352
+ }
11353
+ let code = text.charCodeAt(pos);
11354
+ if (isWhiteSpace(code)) {
11355
+ do {
11356
+ pos++;
11357
+ value += String.fromCharCode(code);
11358
+ code = text.charCodeAt(pos);
11359
+ } while (isWhiteSpace(code));
11360
+ return token = 15;
11361
+ }
11362
+ if (isLineBreak(code)) {
11363
+ pos++;
11364
+ value += String.fromCharCode(code);
11365
+ if (code === 13 && text.charCodeAt(pos) === 10) {
11366
+ pos++;
11367
+ value += `
11368
+ `;
11369
+ }
11370
+ lineNumber++;
11371
+ tokenLineStartOffset = pos;
11372
+ return token = 14;
11373
+ }
11374
+ switch (code) {
11375
+ case 123:
11376
+ pos++;
11377
+ return token = 1;
11378
+ case 125:
11379
+ pos++;
11380
+ return token = 2;
11381
+ case 91:
11382
+ pos++;
11383
+ return token = 3;
11384
+ case 93:
11385
+ pos++;
11386
+ return token = 4;
11387
+ case 58:
11388
+ pos++;
11389
+ return token = 6;
11390
+ case 44:
11391
+ pos++;
11392
+ return token = 5;
11393
+ case 34:
11394
+ pos++;
11395
+ value = scanString();
11396
+ return token = 10;
11397
+ case 47:
11398
+ const start = pos - 1;
11399
+ if (text.charCodeAt(pos + 1) === 47) {
11400
+ pos += 2;
11401
+ while (pos < len) {
11402
+ if (isLineBreak(text.charCodeAt(pos))) {
11403
+ break;
11404
+ }
11405
+ pos++;
11406
+ }
11407
+ value = text.substring(start, pos);
11408
+ return token = 12;
11409
+ }
11410
+ if (text.charCodeAt(pos + 1) === 42) {
11411
+ pos += 2;
11412
+ const safeLength = len - 1;
11413
+ let commentClosed = false;
11414
+ while (pos < safeLength) {
11415
+ const ch = text.charCodeAt(pos);
11416
+ if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
11417
+ pos += 2;
11418
+ commentClosed = true;
11419
+ break;
11420
+ }
11421
+ pos++;
11422
+ if (isLineBreak(ch)) {
11423
+ if (ch === 13 && text.charCodeAt(pos) === 10) {
11424
+ pos++;
11425
+ }
11426
+ lineNumber++;
11427
+ tokenLineStartOffset = pos;
11428
+ }
11429
+ }
11430
+ if (!commentClosed) {
11431
+ pos++;
11432
+ scanError = 1;
11433
+ }
11434
+ value = text.substring(start, pos);
11435
+ return token = 13;
11436
+ }
11437
+ value += String.fromCharCode(code);
11438
+ pos++;
11439
+ return token = 16;
11440
+ case 45:
11441
+ value += String.fromCharCode(code);
11442
+ pos++;
11443
+ if (pos === len || !isDigit(text.charCodeAt(pos))) {
11444
+ return token = 16;
11445
+ }
11446
+ case 48:
11447
+ case 49:
11448
+ case 50:
11449
+ case 51:
11450
+ case 52:
11451
+ case 53:
11452
+ case 54:
11453
+ case 55:
11454
+ case 56:
11455
+ case 57:
11456
+ value += scanNumber();
11457
+ return token = 11;
11458
+ default:
11459
+ while (pos < len && isUnknownContentCharacter(code)) {
11460
+ pos++;
11461
+ code = text.charCodeAt(pos);
11462
+ }
11463
+ if (tokenOffset !== pos) {
11464
+ value = text.substring(tokenOffset, pos);
11465
+ switch (value) {
11466
+ case "true":
11467
+ return token = 8;
11468
+ case "false":
11469
+ return token = 9;
11470
+ case "null":
11471
+ return token = 7;
11472
+ }
11473
+ return token = 16;
11474
+ }
11475
+ value += String.fromCharCode(code);
11476
+ pos++;
11477
+ return token = 16;
11306
11478
  }
11307
- Object.defineProperty(sanitized, key, {
11308
- value: sanitizeParsedJson(source[key], options, [...path, key]),
11309
- enumerable: true,
11310
- configurable: true,
11311
- writable: true
11312
- });
11313
- }
11314
- return sanitized;
11315
- }
11316
- function parseJsonc2(content, options = {}) {
11317
- const normalized = stripTrailingCommas(stripJsonComments(content));
11318
- return sanitizeParsedJson(JSON.parse(normalized), options);
11319
- }
11320
- function readJsoncFile(filePath) {
11321
- try {
11322
- return parseJsonc2(readFileSync5(filePath, "utf-8"));
11323
- } catch (_error) {
11324
- return null;
11325
- }
11326
- }
11327
- function detectConfigFile(basePath) {
11328
- const jsoncPath = `${basePath}.jsonc`;
11329
- const jsonPath = `${basePath}.json`;
11330
- if (existsSync8(jsoncPath)) {
11331
- return { format: "jsonc", path: jsoncPath };
11332
- }
11333
- if (existsSync8(jsonPath)) {
11334
- return { format: "json", path: jsonPath };
11335
- }
11336
- return { format: "none", path: jsoncPath };
11337
- }
11338
- var PROTOTYPE_POLLUTION_KEYS;
11339
- var init_jsonc_parser = __esm(() => {
11340
- PROTOTYPE_POLLUTION_KEYS = new Set(["__proto__", "constructor", "prototype"]);
11341
- });
11342
-
11343
- // src/lib/jsonc-config.ts
11344
- import { existsSync as existsSync9, readFileSync as readFileSync6 } from "node:fs";
11345
- function parseErrorLocation(content, error) {
11346
- const lines = content.split(`
11347
- `);
11348
- const message = error instanceof Error ? error.message : String(error);
11349
- if (message.includes("Unexpected end of JSON input")) {
11350
- return { line: lines.length, column: (lines.at(-1)?.length ?? 0) + 1 };
11351
- }
11352
- const parserLocation = error;
11353
- if (typeof parserLocation.line === "number" && parserLocation.line >= 1 && parserLocation.line <= lines.length && typeof parserLocation.column === "number" && parserLocation.column >= 0) {
11354
- return { line: parserLocation.line, column: parserLocation.column + 1 };
11355
11479
  }
11356
- const messageLine = /Line (\d+)/.exec(message)?.[1];
11357
- return { line: messageLine ? Number.parseInt(messageLine, 10) : 1, column: 1 };
11358
- }
11359
- function readJsoncConfig(path) {
11360
- if (!existsSync9(path))
11361
- return { kind: "missing" };
11362
- const content = readFileSync6(path, "utf-8");
11363
- try {
11364
- const rejectedKeyPaths = [];
11365
- const parsed = sanitizeParsedJson(import_comment_json2.parse(content), {
11366
- onRejectedKey: (keyPath) => rejectedKeyPaths.push(keyPath.join("."))
11367
- });
11368
- if (rejectedKeyPaths.length > 0) {
11369
- throw new Error(`unsafe prototype-pollution key at ${rejectedKeyPaths.join(", ")}`);
11480
+ function isUnknownContentCharacter(code) {
11481
+ if (isWhiteSpace(code) || isLineBreak(code)) {
11482
+ return false;
11370
11483
  }
11371
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
11372
- throw new Error("expected a JSON object at the document root");
11484
+ switch (code) {
11485
+ case 125:
11486
+ case 93:
11487
+ case 123:
11488
+ case 91:
11489
+ case 34:
11490
+ case 58:
11491
+ case 44:
11492
+ case 47:
11493
+ return false;
11373
11494
  }
11374
- return { kind: "parsed", value: parsed };
11375
- } catch (error) {
11376
- return { kind: "parse-error", error: new ConfigParseError(path, content, error) };
11495
+ return true;
11377
11496
  }
11497
+ function scanNextNonTrivia() {
11498
+ let result;
11499
+ do {
11500
+ result = scanNext();
11501
+ } while (result >= 12 && result <= 15);
11502
+ return result;
11503
+ }
11504
+ return {
11505
+ setPosition,
11506
+ getPosition: () => pos,
11507
+ scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
11508
+ getToken: () => token,
11509
+ getTokenValue: () => value,
11510
+ getTokenOffset: () => tokenOffset,
11511
+ getTokenLength: () => pos - tokenOffset,
11512
+ getTokenStartLine: () => lineStartOffset,
11513
+ getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,
11514
+ getTokenError: () => scanError
11515
+ };
11378
11516
  }
11379
- function readJsoncConfigForUpdate(path) {
11380
- const result = readJsoncConfig(path);
11381
- if (result.kind === "missing")
11382
- return {};
11383
- if (result.kind === "parse-error")
11384
- throw result.error;
11385
- return result.value;
11517
+ function isWhiteSpace(ch) {
11518
+ return ch === 32 || ch === 9;
11386
11519
  }
11387
- function assertJsoncConfigsParseable(paths) {
11388
- for (const path of paths) {
11389
- const result = readJsoncConfig(path);
11390
- if (result.kind === "parse-error")
11391
- throw result.error;
11392
- }
11520
+ function isLineBreak(ch) {
11521
+ return ch === 10 || ch === 13;
11393
11522
  }
11394
- var import_comment_json2, ConfigParseError;
11395
- var init_jsonc_config = __esm(() => {
11396
- init_jsonc_parser();
11397
- import_comment_json2 = __toESM(require_src3(), 1);
11398
- ConfigParseError = class ConfigParseError extends Error {
11399
- path;
11400
- constructor(path, content, cause) {
11401
- const detail = cause instanceof Error ? cause.message : String(cause);
11402
- const location = parseErrorLocation(content, cause);
11403
- super(`Refusing to overwrite unparseable config ${path} at line ${location.line}, column ${location.column}: ${detail}`, { cause });
11404
- this.name = "ConfigParseError";
11405
- this.path = path;
11406
- }
11407
- };
11408
- });
11409
-
11410
- // src/lib/pi-package-entry.ts
11411
- function stripNpmPrefix(value) {
11412
- return value.startsWith("npm:") ? value.slice("npm:".length) : value;
11413
- }
11414
- function packageNameFromSpecifier(value) {
11415
- const normalized = stripNpmPrefix(value.trim());
11416
- if (!normalized)
11417
- return normalized;
11418
- if (normalized.startsWith("@")) {
11419
- const slash = normalized.indexOf("/");
11420
- if (slash < 0)
11421
- return normalized;
11422
- const versionAt = normalized.indexOf("@", slash + 1);
11423
- return versionAt > 0 ? normalized.slice(0, versionAt) : normalized;
11424
- }
11425
- const versionAt = normalized.indexOf("@");
11426
- return versionAt > 0 ? normalized.slice(0, versionAt) : normalized;
11427
- }
11428
- function getPiPackageEntryName(entry) {
11429
- if (typeof entry === "string")
11430
- return packageNameFromSpecifier(entry);
11431
- if (entry && typeof entry === "object" && !Array.isArray(entry)) {
11432
- const object = entry;
11433
- for (const key of ["name", "source"]) {
11434
- const name = getPiPackageEntryName(object[key]);
11435
- if (name)
11436
- return name;
11437
- }
11438
- }
11439
- return null;
11440
- }
11441
- function isPiMagicContextPackageEntry(entry) {
11442
- if (typeof entry === "string") {
11443
- return packageNameFromSpecifier(entry) === PI_MAGIC_CONTEXT_PACKAGE_NAME;
11444
- }
11445
- if (entry && typeof entry === "object" && !Array.isArray(entry)) {
11446
- const object = entry;
11447
- return isPiMagicContextPackageEntry(object.name) || isPiMagicContextPackageEntry(object.source);
11448
- }
11449
- return false;
11450
- }
11451
- function getPiMagicContextPackageSpecifier(entry) {
11452
- if (typeof entry === "string") {
11453
- return isPiMagicContextPackageEntry(entry) ? entry.trim() : null;
11454
- }
11455
- if (entry && typeof entry === "object" && !Array.isArray(entry)) {
11456
- const object = entry;
11457
- return getPiMagicContextPackageSpecifier(object.source) ?? getPiMagicContextPackageSpecifier(object.name);
11458
- }
11459
- return null;
11460
- }
11461
- function hasPiMagicContextPackage(entries) {
11462
- return entries.some(isPiMagicContextPackageEntry);
11463
- }
11464
- function describePiPackageEntry(entry) {
11465
- if (typeof entry === "string")
11466
- return entry;
11467
- const name = getPiPackageEntryName(entry);
11468
- if (name)
11469
- return name;
11470
- try {
11471
- return JSON.stringify(entry);
11472
- } catch {
11473
- return String(entry);
11474
- }
11475
- }
11476
- var PI_MAGIC_CONTEXT_PACKAGE_NAME = "@cortexkit/pi-magic-context";
11477
-
11478
- // src/adapters/pi.ts
11479
- import { existsSync as existsSync10 } from "node:fs";
11480
- import { dirname as dirname5 } from "node:path";
11481
-
11482
- class PiAdapter {
11483
- kind = "pi";
11484
- displayName = "Pi";
11485
- pluginPackageName = PLUGIN_NAME;
11486
- isInstalled() {
11487
- return detectPiBinary() !== null;
11488
- }
11489
- hasPluginEntry() {
11490
- const settings = readPiSettings();
11491
- if (!settings)
11492
- return false;
11493
- const packages = settings.packages ?? [];
11494
- return packages.some((entry) => isPiMagicContextPackageEntry(entry));
11495
- }
11496
- getConfigPaths() {
11497
- const dir = getPiAgentConfigDir();
11498
- return {
11499
- configDir: dir,
11500
- pluginConfigPath: getPiUserExtensionsPath(),
11501
- magicContextConfigPath: getPiUserConfigPath(),
11502
- secondaryConfigPath: null
11503
- };
11504
- }
11505
- async ensurePluginEntry() {
11506
- const settingsPath = getPiUserExtensionsPath();
11507
- try {
11508
- const settings = readPiSettingsForUpdate();
11509
- const packages = Array.isArray(settings.packages) ? settings.packages : [];
11510
- const idx = packages.findIndex((entry) => isPiMagicContextPackageEntry(entry));
11511
- if (idx === -1) {
11512
- packages.push(PI_PACKAGE_SOURCE);
11513
- settings.packages = packages;
11514
- writePiSettings(settings);
11515
- return {
11516
- ok: true,
11517
- action: "added",
11518
- message: `Added ${PI_PACKAGE_SOURCE} to ${settingsPath}.`,
11519
- configPath: settingsPath
11520
- };
11521
- }
11522
- return {
11523
- ok: true,
11524
- action: "already_present",
11525
- message: `Plugin entry already present in ${settingsPath}.`,
11526
- configPath: settingsPath
11527
- };
11528
- } catch (err) {
11529
- return {
11530
- ok: false,
11531
- action: "error",
11532
- message: `Failed to update ${settingsPath}: ${err.message}`,
11533
- configPath: settingsPath
11534
- };
11535
- }
11536
- }
11537
- async removePluginEntry() {
11538
- const settingsPath = getPiUserExtensionsPath();
11539
- try {
11540
- const settings = readPiSettingsForUpdate();
11541
- if (!Array.isArray(settings.packages)) {
11542
- return {
11543
- ok: true,
11544
- action: "already_present",
11545
- message: `No packages array in ${settingsPath}.`,
11546
- configPath: settingsPath
11547
- };
11548
- }
11549
- const before = settings.packages.length;
11550
- settings.packages = settings.packages.filter((entry) => !isPiMagicContextPackageEntry(entry));
11551
- if (settings.packages.length === before) {
11552
- return {
11553
- ok: true,
11554
- action: "already_present",
11555
- message: `Plugin entry not present in ${settingsPath}.`,
11556
- configPath: settingsPath
11557
- };
11558
- }
11559
- writePiSettings(settings);
11560
- return {
11561
- ok: true,
11562
- action: "updated",
11563
- message: `Removed ${PLUGIN_NAME} from ${settingsPath}.`,
11564
- configPath: settingsPath
11565
- };
11566
- } catch (err) {
11567
- return {
11568
- ok: false,
11569
- action: "error",
11570
- message: `Failed to update ${settingsPath}: ${err.message}`,
11571
- configPath: settingsPath
11572
- };
11573
- }
11574
- }
11575
- getInstallHint() {
11576
- return "Install Pi: https://pi.coding/install (npm: @earendil-works/pi-coding-agent)";
11577
- }
11578
- getPluginCacheInfo() {
11579
- return { path: null, exists: false, sizeBytes: 0 };
11580
- }
11581
- getLogPath() {
11582
- return getMagicContextLogPath2("pi");
11583
- }
11584
- getInstalledPluginVersion() {
11585
- const piBin = detectPiBinary();
11586
- if (!piBin)
11587
- return null;
11588
- try {
11589
- const output = runPiCommand(piBin.path, ["list"], 5000);
11590
- if (output === null)
11591
- return null;
11592
- const re = new RegExp(`${PLUGIN_NAME.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&")}.*?(\\d+\\.\\d+\\.\\d+(?:[-+][\\w.-]+)?)`);
11593
- const match = re.exec(output);
11594
- if (match)
11595
- return match[1] ?? null;
11596
- } catch {}
11597
- return null;
11598
- }
11599
- }
11600
- function readPiSettings() {
11601
- const result = readJsoncConfig(getPiUserExtensionsPath());
11602
- return result.kind === "parsed" ? result.value : null;
11603
- }
11604
- function readPiSettingsForUpdate() {
11605
- return readJsoncConfigForUpdate(getPiUserExtensionsPath());
11606
- }
11607
- function writePiSettings(settings) {
11608
- const settingsPath = getPiUserExtensionsPath();
11609
- ensureDir2(settingsPath);
11610
- const text = import_comment_json3.stringify(settings, null, 2);
11611
- writeFileAtomic(settingsPath, `${text}
11612
- `);
11613
- }
11614
- function ensureDir2(filePath) {
11615
- const dir = dirname5(filePath);
11616
- if (!existsSync10(dir)) {
11617
- const { mkdirSync } = __require("node:fs");
11618
- mkdirSync(dir, { recursive: true });
11619
- }
11620
- }
11621
- var import_comment_json3, PLUGIN_NAME = "@cortexkit/pi-magic-context";
11622
- var init_pi = __esm(() => {
11623
- init_atomic_write();
11624
- init_jsonc_config();
11625
- init_paths();
11626
- init_pi_helpers();
11627
- import_comment_json3 = __toESM(require_src3(), 1);
11628
- });
11629
-
11630
- // src/adapters/index.ts
11631
- function getAdapter(kind) {
11632
- const found = ALL.find((a) => a.kind === kind);
11633
- if (!found)
11634
- throw new Error(`Unknown harness: ${kind}`);
11635
- return found;
11636
- }
11637
- function getInstalledAdapters() {
11638
- return ALL.filter((a) => a.isInstalled());
11639
- }
11640
- var ALL;
11641
- var init_adapters = __esm(() => {
11642
- init_omp();
11643
- init_opencode();
11644
- init_pi();
11645
- ALL = [new OpenCodeAdapter, new PiAdapter, new OmpAdapter];
11646
- });
11647
-
11648
- // src/lib/harness-select.ts
11649
- function parseHarnessFlag(argv) {
11650
- const idx = argv.indexOf("--harness");
11651
- if (idx === -1)
11652
- return { kind: "absent" };
11653
- const value = argv[idx + 1];
11654
- if (!value || value.startsWith("--"))
11655
- return { kind: "invalid", value: null };
11656
- if (value === "opencode" || value === "pi" || value === "omp") {
11657
- return { kind: "valid", harness: value };
11658
- }
11659
- return { kind: "invalid", value };
11660
- }
11661
- async function resolveAdaptersForCommand(argv, options) {
11662
- const flag = parseHarnessFlag(argv);
11663
- if (flag.kind === "valid")
11664
- return [getAdapter(flag.harness)];
11665
- if (flag.kind === "invalid") {
11666
- throw new Error(flag.value === null ? "Missing value for --harness (expected opencode, pi, or omp)" : `Invalid --harness value: ${flag.value} (expected opencode, pi, or omp)`);
11667
- }
11668
- const installed = getInstalledAdapters();
11669
- if (installed.length === 0) {
11670
- log2.warn("No supported harness was detected on PATH (opencode, pi, omp).");
11671
- const pick = await selectOne(`Which harness do you want to ${options.verb}?`, [
11672
- {
11673
- label: "OpenCode",
11674
- value: "opencode",
11675
- hint: "@cortexkit/opencode-magic-context"
11676
- },
11677
- {
11678
- label: "Pi",
11679
- value: "pi",
11680
- hint: "@cortexkit/pi-magic-context"
11681
- },
11682
- {
11683
- label: "Oh My Pi (OMP)",
11684
- value: "omp",
11685
- hint: "@cortexkit/pi-magic-context"
11686
- }
11687
- ]);
11688
- return [getAdapter(pick)];
11689
- }
11690
- if (installed.length === 1) {
11691
- const only = installed[0];
11692
- log2.info(`Detected ${only.displayName} — using it for ${options.verb}.`);
11693
- return [only];
11694
- }
11695
- if (options.allowMulti) {
11696
- const picks = await selectMany(`Multiple harnesses detected — which to ${options.verb}?`, installed.map((a) => ({ label: a.displayName, value: a.kind })), installed.map((a) => a.kind));
11697
- if (picks.length === 0) {
11698
- log2.warn("No harness selected; nothing to do.");
11699
- return [];
11700
- }
11701
- return picks.map((kind) => getAdapter(kind));
11702
- }
11703
- const pick = await selectOne(`Multiple harnesses detected — which one to ${options.verb}?`, installed.map((a) => ({ label: a.displayName, value: a.kind })));
11704
- return [getAdapter(pick)];
11705
- }
11706
- var init_harness_select = __esm(() => {
11707
- init_adapters();
11708
- init_prompts();
11709
- });
11710
-
11711
- // ../plugin/src/shared/harness-provider-map.ts
11712
- function remapProviderPrefix(ref, map) {
11713
- if (typeof ref !== "string")
11714
- return ref;
11715
- const slash = ref.indexOf("/");
11716
- if (slash <= 0)
11717
- return ref;
11718
- const provider = ref.slice(0, slash);
11719
- if (!Object.hasOwn(map, provider))
11720
- return ref;
11721
- return `${map[provider]}${ref.slice(slash)}`;
11722
- }
11723
- function piModelRefToCanonical(ref) {
11724
- return remapProviderPrefix(ref, PI_TO_CANONICAL_PROVIDER);
11725
- }
11726
- function ompModelRefToCanonical(ref) {
11727
- return remapProviderPrefix(ref, OMP_TO_CANONICAL_PROVIDER);
11728
- }
11729
- var PI_TO_CANONICAL_PROVIDER, OMP_TO_CANONICAL_PROVIDER;
11730
- var init_harness_provider_map = __esm(() => {
11731
- PI_TO_CANONICAL_PROVIDER = {
11732
- "openai-codex": "openai",
11733
- "google-antigravity": "google"
11734
- };
11735
- OMP_TO_CANONICAL_PROVIDER = {
11736
- "openai-codex": "openai",
11737
- "google-antigravity": "google",
11738
- "opencode-zen": "opencode"
11739
- };
11740
- });
11741
-
11742
- // ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
11743
- function createScanner(text, ignoreTrivia = false) {
11744
- const len = text.length;
11745
- let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
11746
- function scanHexDigits(count, exact) {
11747
- let digits = 0;
11748
- let value = 0;
11749
- while (digits < count || !exact) {
11750
- let ch = text.charCodeAt(pos);
11751
- if (ch >= 48 && ch <= 57) {
11752
- value = value * 16 + ch - 48;
11753
- } else if (ch >= 65 && ch <= 70) {
11754
- value = value * 16 + ch - 65 + 10;
11755
- } else if (ch >= 97 && ch <= 102) {
11756
- value = value * 16 + ch - 97 + 10;
11757
- } else {
11758
- break;
11759
- }
11760
- pos++;
11761
- digits++;
11762
- }
11763
- if (digits < count) {
11764
- value = -1;
11765
- }
11766
- return value;
11767
- }
11768
- function setPosition(newPosition) {
11769
- pos = newPosition;
11770
- value = "";
11771
- tokenOffset = 0;
11772
- token = 16;
11773
- scanError = 0;
11774
- }
11775
- function scanNumber() {
11776
- let start = pos;
11777
- if (text.charCodeAt(pos) === 48) {
11778
- pos++;
11779
- } else {
11780
- pos++;
11781
- while (pos < text.length && isDigit(text.charCodeAt(pos))) {
11782
- pos++;
11783
- }
11784
- }
11785
- if (pos < text.length && text.charCodeAt(pos) === 46) {
11786
- pos++;
11787
- if (pos < text.length && isDigit(text.charCodeAt(pos))) {
11788
- pos++;
11789
- while (pos < text.length && isDigit(text.charCodeAt(pos))) {
11790
- pos++;
11791
- }
11792
- } else {
11793
- scanError = 3;
11794
- return text.substring(start, pos);
11795
- }
11796
- }
11797
- let end = pos;
11798
- if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
11799
- pos++;
11800
- if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
11801
- pos++;
11802
- }
11803
- if (pos < text.length && isDigit(text.charCodeAt(pos))) {
11804
- pos++;
11805
- while (pos < text.length && isDigit(text.charCodeAt(pos))) {
11806
- pos++;
11807
- }
11808
- end = pos;
11809
- } else {
11810
- scanError = 3;
11811
- }
11812
- }
11813
- return text.substring(start, end);
11814
- }
11815
- function scanString() {
11816
- let result = "", start = pos;
11817
- while (true) {
11818
- if (pos >= len) {
11819
- result += text.substring(start, pos);
11820
- scanError = 2;
11821
- break;
11822
- }
11823
- const ch = text.charCodeAt(pos);
11824
- if (ch === 34) {
11825
- result += text.substring(start, pos);
11826
- pos++;
11827
- break;
11828
- }
11829
- if (ch === 92) {
11830
- result += text.substring(start, pos);
11831
- pos++;
11832
- if (pos >= len) {
11833
- scanError = 2;
11834
- break;
11835
- }
11836
- const ch2 = text.charCodeAt(pos++);
11837
- switch (ch2) {
11838
- case 34:
11839
- result += '"';
11840
- break;
11841
- case 92:
11842
- result += "\\";
11843
- break;
11844
- case 47:
11845
- result += "/";
11846
- break;
11847
- case 98:
11848
- result += "\b";
11849
- break;
11850
- case 102:
11851
- result += "\f";
11852
- break;
11853
- case 110:
11854
- result += `
11855
- `;
11856
- break;
11857
- case 114:
11858
- result += "\r";
11859
- break;
11860
- case 116:
11861
- result += "\t";
11862
- break;
11863
- case 117:
11864
- const ch3 = scanHexDigits(4, true);
11865
- if (ch3 >= 0) {
11866
- result += String.fromCharCode(ch3);
11867
- } else {
11868
- scanError = 4;
11869
- }
11870
- break;
11871
- default:
11872
- scanError = 5;
11873
- }
11874
- start = pos;
11875
- continue;
11876
- }
11877
- if (ch >= 0 && ch <= 31) {
11878
- if (isLineBreak(ch)) {
11879
- result += text.substring(start, pos);
11880
- scanError = 2;
11881
- break;
11882
- } else {
11883
- scanError = 6;
11884
- }
11885
- }
11886
- pos++;
11887
- }
11888
- return result;
11889
- }
11890
- function scanNext() {
11891
- value = "";
11892
- scanError = 0;
11893
- tokenOffset = pos;
11894
- lineStartOffset = lineNumber;
11895
- prevTokenLineStartOffset = tokenLineStartOffset;
11896
- if (pos >= len) {
11897
- tokenOffset = len;
11898
- return token = 17;
11899
- }
11900
- let code = text.charCodeAt(pos);
11901
- if (isWhiteSpace(code)) {
11902
- do {
11903
- pos++;
11904
- value += String.fromCharCode(code);
11905
- code = text.charCodeAt(pos);
11906
- } while (isWhiteSpace(code));
11907
- return token = 15;
11908
- }
11909
- if (isLineBreak(code)) {
11910
- pos++;
11911
- value += String.fromCharCode(code);
11912
- if (code === 13 && text.charCodeAt(pos) === 10) {
11913
- pos++;
11914
- value += `
11915
- `;
11916
- }
11917
- lineNumber++;
11918
- tokenLineStartOffset = pos;
11919
- return token = 14;
11920
- }
11921
- switch (code) {
11922
- case 123:
11923
- pos++;
11924
- return token = 1;
11925
- case 125:
11926
- pos++;
11927
- return token = 2;
11928
- case 91:
11929
- pos++;
11930
- return token = 3;
11931
- case 93:
11932
- pos++;
11933
- return token = 4;
11934
- case 58:
11935
- pos++;
11936
- return token = 6;
11937
- case 44:
11938
- pos++;
11939
- return token = 5;
11940
- case 34:
11941
- pos++;
11942
- value = scanString();
11943
- return token = 10;
11944
- case 47:
11945
- const start = pos - 1;
11946
- if (text.charCodeAt(pos + 1) === 47) {
11947
- pos += 2;
11948
- while (pos < len) {
11949
- if (isLineBreak(text.charCodeAt(pos))) {
11950
- break;
11951
- }
11952
- pos++;
11953
- }
11954
- value = text.substring(start, pos);
11955
- return token = 12;
11956
- }
11957
- if (text.charCodeAt(pos + 1) === 42) {
11958
- pos += 2;
11959
- const safeLength = len - 1;
11960
- let commentClosed = false;
11961
- while (pos < safeLength) {
11962
- const ch = text.charCodeAt(pos);
11963
- if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
11964
- pos += 2;
11965
- commentClosed = true;
11966
- break;
11967
- }
11968
- pos++;
11969
- if (isLineBreak(ch)) {
11970
- if (ch === 13 && text.charCodeAt(pos) === 10) {
11971
- pos++;
11972
- }
11973
- lineNumber++;
11974
- tokenLineStartOffset = pos;
11975
- }
11976
- }
11977
- if (!commentClosed) {
11978
- pos++;
11979
- scanError = 1;
11980
- }
11981
- value = text.substring(start, pos);
11982
- return token = 13;
11983
- }
11984
- value += String.fromCharCode(code);
11985
- pos++;
11986
- return token = 16;
11987
- case 45:
11988
- value += String.fromCharCode(code);
11989
- pos++;
11990
- if (pos === len || !isDigit(text.charCodeAt(pos))) {
11991
- return token = 16;
11992
- }
11993
- case 48:
11994
- case 49:
11995
- case 50:
11996
- case 51:
11997
- case 52:
11998
- case 53:
11999
- case 54:
12000
- case 55:
12001
- case 56:
12002
- case 57:
12003
- value += scanNumber();
12004
- return token = 11;
12005
- default:
12006
- while (pos < len && isUnknownContentCharacter(code)) {
12007
- pos++;
12008
- code = text.charCodeAt(pos);
12009
- }
12010
- if (tokenOffset !== pos) {
12011
- value = text.substring(tokenOffset, pos);
12012
- switch (value) {
12013
- case "true":
12014
- return token = 8;
12015
- case "false":
12016
- return token = 9;
12017
- case "null":
12018
- return token = 7;
12019
- }
12020
- return token = 16;
12021
- }
12022
- value += String.fromCharCode(code);
12023
- pos++;
12024
- return token = 16;
12025
- }
12026
- }
12027
- function isUnknownContentCharacter(code) {
12028
- if (isWhiteSpace(code) || isLineBreak(code)) {
12029
- return false;
12030
- }
12031
- switch (code) {
12032
- case 125:
12033
- case 93:
12034
- case 123:
12035
- case 91:
12036
- case 34:
12037
- case 58:
12038
- case 44:
12039
- case 47:
12040
- return false;
12041
- }
12042
- return true;
12043
- }
12044
- function scanNextNonTrivia() {
12045
- let result;
12046
- do {
12047
- result = scanNext();
12048
- } while (result >= 12 && result <= 15);
12049
- return result;
12050
- }
12051
- return {
12052
- setPosition,
12053
- getPosition: () => pos,
12054
- scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
12055
- getToken: () => token,
12056
- getTokenValue: () => value,
12057
- getTokenOffset: () => tokenOffset,
12058
- getTokenLength: () => pos - tokenOffset,
12059
- getTokenStartLine: () => lineStartOffset,
12060
- getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,
12061
- getTokenError: () => scanError
12062
- };
12063
- }
12064
- function isWhiteSpace(ch) {
12065
- return ch === 32 || ch === 9;
12066
- }
12067
- function isLineBreak(ch) {
12068
- return ch === 10 || ch === 13;
12069
- }
12070
- function isDigit(ch) {
12071
- return ch >= 48 && ch <= 57;
11523
+ function isDigit(ch) {
11524
+ return ch >= 48 && ch <= 57;
12072
11525
  }
12073
11526
  var CharacterCodes;
12074
11527
  var init_scanner = __esm(() => {
@@ -12440,6 +11893,49 @@ var init_format = __esm(() => {
12440
11893
  });
12441
11894
 
12442
11895
  // ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/parser.js
11896
+ function parse(text, errors = [], options = ParseOptions.DEFAULT) {
11897
+ let currentProperty = null;
11898
+ let currentParent = [];
11899
+ const previousParents = [];
11900
+ function onValue(value) {
11901
+ if (Array.isArray(currentParent)) {
11902
+ currentParent.push(value);
11903
+ } else if (currentProperty !== null) {
11904
+ currentParent[currentProperty] = value;
11905
+ }
11906
+ }
11907
+ const visitor = {
11908
+ onObjectBegin: () => {
11909
+ const object = {};
11910
+ onValue(object);
11911
+ previousParents.push(currentParent);
11912
+ currentParent = object;
11913
+ currentProperty = null;
11914
+ },
11915
+ onObjectProperty: (name) => {
11916
+ currentProperty = name;
11917
+ },
11918
+ onObjectEnd: () => {
11919
+ currentParent = previousParents.pop();
11920
+ },
11921
+ onArrayBegin: () => {
11922
+ const array = [];
11923
+ onValue(array);
11924
+ previousParents.push(currentParent);
11925
+ currentParent = array;
11926
+ currentProperty = null;
11927
+ },
11928
+ onArrayEnd: () => {
11929
+ currentParent = previousParents.pop();
11930
+ },
11931
+ onLiteralValue: onValue,
11932
+ onError: (error, offset, length) => {
11933
+ errors.push({ error, offset, length });
11934
+ }
11935
+ };
11936
+ visit(text, visitor, options);
11937
+ return currentParent[0];
11938
+ }
12443
11939
  function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
12444
11940
  let currentParent = { type: "array", offset: -1, length: -1, children: [], parent: undefined };
12445
11941
  function ensurePropertyComplete(endOffset) {
@@ -12721,346 +12217,981 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
12721
12217
  } else if (needsComma) {
12722
12218
  handleError(6, [], []);
12723
12219
  }
12724
- if (!parseProperty()) {
12725
- handleError(4, [], [2, 5]);
12220
+ if (!parseProperty()) {
12221
+ handleError(4, [], [2, 5]);
12222
+ }
12223
+ needsComma = true;
12224
+ }
12225
+ onObjectEnd();
12226
+ if (_scanner.getToken() !== 2) {
12227
+ handleError(7, [2], []);
12228
+ } else {
12229
+ scanNext();
12230
+ }
12231
+ return true;
12232
+ }
12233
+ function parseArray() {
12234
+ onArrayBegin();
12235
+ scanNext();
12236
+ let isFirstElement = true;
12237
+ let needsComma = false;
12238
+ while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
12239
+ if (_scanner.getToken() === 5) {
12240
+ if (!needsComma) {
12241
+ handleError(4, [], []);
12242
+ }
12243
+ onSeparator(",");
12244
+ scanNext();
12245
+ if (_scanner.getToken() === 4 && allowTrailingComma) {
12246
+ break;
12247
+ }
12248
+ } else if (needsComma) {
12249
+ handleError(6, [], []);
12250
+ }
12251
+ if (isFirstElement) {
12252
+ _jsonPath.push(0);
12253
+ isFirstElement = false;
12254
+ } else {
12255
+ _jsonPath[_jsonPath.length - 1]++;
12256
+ }
12257
+ if (!parseValue()) {
12258
+ handleError(4, [], [4, 5]);
12259
+ }
12260
+ needsComma = true;
12261
+ }
12262
+ onArrayEnd();
12263
+ if (!isFirstElement) {
12264
+ _jsonPath.pop();
12265
+ }
12266
+ if (_scanner.getToken() !== 4) {
12267
+ handleError(8, [4], []);
12268
+ } else {
12269
+ scanNext();
12270
+ }
12271
+ return true;
12272
+ }
12273
+ function parseValue() {
12274
+ switch (_scanner.getToken()) {
12275
+ case 3:
12276
+ return parseArray();
12277
+ case 1:
12278
+ return parseObject();
12279
+ case 10:
12280
+ return parseString(true);
12281
+ default:
12282
+ return parseLiteral();
12283
+ }
12284
+ }
12285
+ scanNext();
12286
+ if (_scanner.getToken() === 17) {
12287
+ if (options.allowEmptyContent) {
12288
+ return true;
12289
+ }
12290
+ handleError(4, [], []);
12291
+ return false;
12292
+ }
12293
+ if (!parseValue()) {
12294
+ handleError(4, [], []);
12295
+ return false;
12296
+ }
12297
+ if (_scanner.getToken() !== 17) {
12298
+ handleError(9, [], []);
12299
+ }
12300
+ return true;
12301
+ }
12302
+ function getNodeType(value) {
12303
+ switch (typeof value) {
12304
+ case "boolean":
12305
+ return "boolean";
12306
+ case "number":
12307
+ return "number";
12308
+ case "string":
12309
+ return "string";
12310
+ case "object": {
12311
+ if (!value) {
12312
+ return "null";
12313
+ } else if (Array.isArray(value)) {
12314
+ return "array";
12315
+ }
12316
+ return "object";
12317
+ }
12318
+ default:
12319
+ return "null";
12320
+ }
12321
+ }
12322
+ var ParseOptions;
12323
+ var init_parser = __esm(() => {
12324
+ init_scanner();
12325
+ (function(ParseOptions) {
12326
+ ParseOptions.DEFAULT = {
12327
+ allowTrailingComma: false
12328
+ };
12329
+ })(ParseOptions || (ParseOptions = {}));
12330
+ });
12331
+
12332
+ // ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/edit.js
12333
+ function setProperty(text, originalPath, value, options) {
12334
+ const path = originalPath.slice();
12335
+ const errors = [];
12336
+ const root = parseTree(text, errors);
12337
+ let parent = undefined;
12338
+ let lastSegment = undefined;
12339
+ while (path.length > 0) {
12340
+ lastSegment = path.pop();
12341
+ parent = findNodeAtLocation(root, path);
12342
+ if (parent === undefined && value !== undefined) {
12343
+ if (typeof lastSegment === "string") {
12344
+ value = { [lastSegment]: value };
12345
+ } else {
12346
+ value = [value];
12347
+ }
12348
+ } else {
12349
+ break;
12350
+ }
12351
+ }
12352
+ if (!parent) {
12353
+ if (value === undefined) {
12354
+ throw new Error("Can not delete in empty document");
12355
+ }
12356
+ return withFormatting(text, { offset: root ? root.offset : 0, length: root ? root.length : 0, content: JSON.stringify(value) }, options);
12357
+ } else if (parent.type === "object" && typeof lastSegment === "string" && Array.isArray(parent.children)) {
12358
+ const existing = findNodeAtLocation(parent, [lastSegment]);
12359
+ if (existing !== undefined) {
12360
+ if (value === undefined) {
12361
+ if (!existing.parent) {
12362
+ throw new Error("Malformed AST");
12363
+ }
12364
+ const propertyIndex = parent.children.indexOf(existing.parent);
12365
+ let removeBegin;
12366
+ let removeEnd = existing.parent.offset + existing.parent.length;
12367
+ if (propertyIndex > 0) {
12368
+ let previous = parent.children[propertyIndex - 1];
12369
+ removeBegin = previous.offset + previous.length;
12370
+ } else {
12371
+ removeBegin = parent.offset + 1;
12372
+ if (parent.children.length > 1) {
12373
+ let next = parent.children[1];
12374
+ removeEnd = next.offset;
12375
+ }
12376
+ }
12377
+ return withFormatting(text, { offset: removeBegin, length: removeEnd - removeBegin, content: "" }, options);
12378
+ } else {
12379
+ return withFormatting(text, { offset: existing.offset, length: existing.length, content: JSON.stringify(value) }, options);
12380
+ }
12381
+ } else {
12382
+ if (value === undefined) {
12383
+ return [];
12384
+ }
12385
+ const newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
12386
+ const index = options.getInsertionIndex ? options.getInsertionIndex(parent.children.map((p) => p.children[0].value)) : parent.children.length;
12387
+ let edit;
12388
+ if (index > 0) {
12389
+ let previous = parent.children[index - 1];
12390
+ edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
12391
+ } else if (parent.children.length === 0) {
12392
+ edit = { offset: parent.offset + 1, length: 0, content: newProperty };
12393
+ } else {
12394
+ edit = { offset: parent.offset + 1, length: 0, content: newProperty + "," };
12395
+ }
12396
+ return withFormatting(text, edit, options);
12397
+ }
12398
+ } else if (parent.type === "array" && typeof lastSegment === "number" && Array.isArray(parent.children)) {
12399
+ const insertIndex = lastSegment;
12400
+ if (insertIndex === -1) {
12401
+ const newProperty = `${JSON.stringify(value)}`;
12402
+ let edit;
12403
+ if (parent.children.length === 0) {
12404
+ edit = { offset: parent.offset + 1, length: 0, content: newProperty };
12405
+ } else {
12406
+ const previous = parent.children[parent.children.length - 1];
12407
+ edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
12408
+ }
12409
+ return withFormatting(text, edit, options);
12410
+ } else if (value === undefined && parent.children.length >= 0) {
12411
+ const removalIndex = lastSegment;
12412
+ const toRemove = parent.children[removalIndex];
12413
+ let edit;
12414
+ if (parent.children.length === 1) {
12415
+ edit = { offset: parent.offset + 1, length: parent.length - 2, content: "" };
12416
+ } else if (parent.children.length - 1 === removalIndex) {
12417
+ let previous = parent.children[removalIndex - 1];
12418
+ let offset = previous.offset + previous.length;
12419
+ let parentEndOffset = parent.offset + parent.length;
12420
+ edit = { offset, length: parentEndOffset - 2 - offset, content: "" };
12421
+ } else {
12422
+ edit = { offset: toRemove.offset, length: parent.children[removalIndex + 1].offset - toRemove.offset, content: "" };
12423
+ }
12424
+ return withFormatting(text, edit, options);
12425
+ } else if (value !== undefined) {
12426
+ let edit;
12427
+ const newProperty = `${JSON.stringify(value)}`;
12428
+ if (!options.isArrayInsertion && parent.children.length > lastSegment) {
12429
+ const toModify = parent.children[lastSegment];
12430
+ edit = { offset: toModify.offset, length: toModify.length, content: newProperty };
12431
+ } else if (parent.children.length === 0 || lastSegment === 0) {
12432
+ edit = { offset: parent.offset + 1, length: 0, content: parent.children.length === 0 ? newProperty : newProperty + "," };
12433
+ } else {
12434
+ const index = lastSegment > parent.children.length ? parent.children.length : lastSegment;
12435
+ const previous = parent.children[index - 1];
12436
+ edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
12437
+ }
12438
+ return withFormatting(text, edit, options);
12439
+ } else {
12440
+ throw new Error(`Can not ${value === undefined ? "remove" : options.isArrayInsertion ? "insert" : "modify"} Array index ${insertIndex} as length is not sufficient`);
12441
+ }
12442
+ } else {
12443
+ throw new Error(`Can not add ${typeof lastSegment !== "number" ? "index" : "property"} to parent of type ${parent.type}`);
12444
+ }
12445
+ }
12446
+ function withFormatting(text, edit, options) {
12447
+ if (!options.formattingOptions) {
12448
+ return [edit];
12449
+ }
12450
+ let newText = applyEdit(text, edit);
12451
+ let begin = edit.offset;
12452
+ let end = edit.offset + edit.content.length;
12453
+ if (edit.length === 0 || edit.content.length === 0) {
12454
+ while (begin > 0 && !isEOL(newText, begin - 1)) {
12455
+ begin--;
12456
+ }
12457
+ while (end < newText.length && !isEOL(newText, end)) {
12458
+ end++;
12459
+ }
12460
+ }
12461
+ const edits = format(newText, { offset: begin, length: end - begin }, { ...options.formattingOptions, keepLines: false });
12462
+ for (let i = edits.length - 1;i >= 0; i--) {
12463
+ const edit = edits[i];
12464
+ newText = applyEdit(newText, edit);
12465
+ begin = Math.min(begin, edit.offset);
12466
+ end = Math.max(end, edit.offset + edit.length);
12467
+ end += edit.content.length - edit.length;
12468
+ }
12469
+ const editLength = text.length - (newText.length - end) - begin;
12470
+ return [{ offset: begin, length: editLength, content: newText.substring(begin, end) }];
12471
+ }
12472
+ function applyEdit(text, edit) {
12473
+ return text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);
12474
+ }
12475
+ var init_edit = __esm(() => {
12476
+ init_format();
12477
+ init_parser();
12478
+ });
12479
+
12480
+ // ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js
12481
+ function printParseErrorCode(code) {
12482
+ switch (code) {
12483
+ case 1:
12484
+ return "InvalidSymbol";
12485
+ case 2:
12486
+ return "InvalidNumberFormat";
12487
+ case 3:
12488
+ return "PropertyNameExpected";
12489
+ case 4:
12490
+ return "ValueExpected";
12491
+ case 5:
12492
+ return "ColonExpected";
12493
+ case 6:
12494
+ return "CommaExpected";
12495
+ case 7:
12496
+ return "CloseBraceExpected";
12497
+ case 8:
12498
+ return "CloseBracketExpected";
12499
+ case 9:
12500
+ return "EndOfFileExpected";
12501
+ case 10:
12502
+ return "InvalidCommentToken";
12503
+ case 11:
12504
+ return "UnexpectedEndOfComment";
12505
+ case 12:
12506
+ return "UnexpectedEndOfString";
12507
+ case 13:
12508
+ return "UnexpectedEndOfNumber";
12509
+ case 14:
12510
+ return "InvalidUnicode";
12511
+ case 15:
12512
+ return "InvalidEscapeCharacter";
12513
+ case 16:
12514
+ return "InvalidCharacter";
12515
+ }
12516
+ return "<unknown ParseErrorCode>";
12517
+ }
12518
+ function modify(text, path, value, options) {
12519
+ return setProperty(text, path, value, options);
12520
+ }
12521
+ function applyEdits(text, edits) {
12522
+ let sortedEdits = edits.slice(0).sort((a, b) => {
12523
+ const diff = a.offset - b.offset;
12524
+ if (diff === 0) {
12525
+ return a.length - b.length;
12526
+ }
12527
+ return diff;
12528
+ });
12529
+ let lastModifiedOffset = text.length;
12530
+ for (let i = sortedEdits.length - 1;i >= 0; i--) {
12531
+ let e = sortedEdits[i];
12532
+ if (e.offset + e.length <= lastModifiedOffset) {
12533
+ text = applyEdit(text, e);
12534
+ } else {
12535
+ throw new Error("Overlapping edit");
12536
+ }
12537
+ lastModifiedOffset = e.offset;
12538
+ }
12539
+ return text;
12540
+ }
12541
+ var createScanner2, ScanError, SyntaxKind, parse2, parseTree2, findNodeAtLocation2, getNodeValue2, ParseErrorCode;
12542
+ var init_main2 = __esm(() => {
12543
+ init_format();
12544
+ init_edit();
12545
+ init_scanner();
12546
+ init_parser();
12547
+ createScanner2 = createScanner;
12548
+ (function(ScanError) {
12549
+ ScanError[ScanError["None"] = 0] = "None";
12550
+ ScanError[ScanError["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
12551
+ ScanError[ScanError["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
12552
+ ScanError[ScanError["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
12553
+ ScanError[ScanError["InvalidUnicode"] = 4] = "InvalidUnicode";
12554
+ ScanError[ScanError["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
12555
+ ScanError[ScanError["InvalidCharacter"] = 6] = "InvalidCharacter";
12556
+ })(ScanError || (ScanError = {}));
12557
+ (function(SyntaxKind) {
12558
+ SyntaxKind[SyntaxKind["OpenBraceToken"] = 1] = "OpenBraceToken";
12559
+ SyntaxKind[SyntaxKind["CloseBraceToken"] = 2] = "CloseBraceToken";
12560
+ SyntaxKind[SyntaxKind["OpenBracketToken"] = 3] = "OpenBracketToken";
12561
+ SyntaxKind[SyntaxKind["CloseBracketToken"] = 4] = "CloseBracketToken";
12562
+ SyntaxKind[SyntaxKind["CommaToken"] = 5] = "CommaToken";
12563
+ SyntaxKind[SyntaxKind["ColonToken"] = 6] = "ColonToken";
12564
+ SyntaxKind[SyntaxKind["NullKeyword"] = 7] = "NullKeyword";
12565
+ SyntaxKind[SyntaxKind["TrueKeyword"] = 8] = "TrueKeyword";
12566
+ SyntaxKind[SyntaxKind["FalseKeyword"] = 9] = "FalseKeyword";
12567
+ SyntaxKind[SyntaxKind["StringLiteral"] = 10] = "StringLiteral";
12568
+ SyntaxKind[SyntaxKind["NumericLiteral"] = 11] = "NumericLiteral";
12569
+ SyntaxKind[SyntaxKind["LineCommentTrivia"] = 12] = "LineCommentTrivia";
12570
+ SyntaxKind[SyntaxKind["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
12571
+ SyntaxKind[SyntaxKind["LineBreakTrivia"] = 14] = "LineBreakTrivia";
12572
+ SyntaxKind[SyntaxKind["Trivia"] = 15] = "Trivia";
12573
+ SyntaxKind[SyntaxKind["Unknown"] = 16] = "Unknown";
12574
+ SyntaxKind[SyntaxKind["EOF"] = 17] = "EOF";
12575
+ })(SyntaxKind || (SyntaxKind = {}));
12576
+ parse2 = parse;
12577
+ parseTree2 = parseTree;
12578
+ findNodeAtLocation2 = findNodeAtLocation;
12579
+ getNodeValue2 = getNodeValue;
12580
+ (function(ParseErrorCode) {
12581
+ ParseErrorCode[ParseErrorCode["InvalidSymbol"] = 1] = "InvalidSymbol";
12582
+ ParseErrorCode[ParseErrorCode["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
12583
+ ParseErrorCode[ParseErrorCode["PropertyNameExpected"] = 3] = "PropertyNameExpected";
12584
+ ParseErrorCode[ParseErrorCode["ValueExpected"] = 4] = "ValueExpected";
12585
+ ParseErrorCode[ParseErrorCode["ColonExpected"] = 5] = "ColonExpected";
12586
+ ParseErrorCode[ParseErrorCode["CommaExpected"] = 6] = "CommaExpected";
12587
+ ParseErrorCode[ParseErrorCode["CloseBraceExpected"] = 7] = "CloseBraceExpected";
12588
+ ParseErrorCode[ParseErrorCode["CloseBracketExpected"] = 8] = "CloseBracketExpected";
12589
+ ParseErrorCode[ParseErrorCode["EndOfFileExpected"] = 9] = "EndOfFileExpected";
12590
+ ParseErrorCode[ParseErrorCode["InvalidCommentToken"] = 10] = "InvalidCommentToken";
12591
+ ParseErrorCode[ParseErrorCode["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
12592
+ ParseErrorCode[ParseErrorCode["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
12593
+ ParseErrorCode[ParseErrorCode["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
12594
+ ParseErrorCode[ParseErrorCode["InvalidUnicode"] = 14] = "InvalidUnicode";
12595
+ ParseErrorCode[ParseErrorCode["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
12596
+ ParseErrorCode[ParseErrorCode["InvalidCharacter"] = 16] = "InvalidCharacter";
12597
+ })(ParseErrorCode || (ParseErrorCode = {}));
12598
+ });
12599
+
12600
+ // ../plugin/src/shared/jsonc-parser.ts
12601
+ import { existsSync as existsSync8, readFileSync as readFileSync5 } from "node:fs";
12602
+ function stripJsonComments(content) {
12603
+ let result = "";
12604
+ let inString = false;
12605
+ let escaped = false;
12606
+ let inLineComment = false;
12607
+ let inBlockComment = false;
12608
+ for (let index = 0;index < content.length; index += 1) {
12609
+ const char = content[index];
12610
+ const next = content[index + 1];
12611
+ if (inLineComment) {
12612
+ if (char === `
12613
+ `) {
12614
+ inLineComment = false;
12615
+ result += char;
12616
+ }
12617
+ continue;
12618
+ }
12619
+ if (inBlockComment) {
12620
+ if (char === "*" && next === "/") {
12621
+ inBlockComment = false;
12622
+ index += 1;
12623
+ }
12624
+ continue;
12625
+ }
12626
+ if (inString) {
12627
+ result += char;
12628
+ if (escaped) {
12629
+ escaped = false;
12630
+ } else if (char === "\\") {
12631
+ escaped = true;
12632
+ } else if (char === '"') {
12633
+ inString = false;
12726
12634
  }
12727
- needsComma = true;
12635
+ continue;
12728
12636
  }
12729
- onObjectEnd();
12730
- if (_scanner.getToken() !== 2) {
12731
- handleError(7, [2], []);
12732
- } else {
12733
- scanNext();
12637
+ if (char === '"') {
12638
+ inString = true;
12639
+ result += char;
12640
+ continue;
12734
12641
  }
12735
- return true;
12642
+ if (char === "/" && next === "/") {
12643
+ inLineComment = true;
12644
+ index += 1;
12645
+ continue;
12646
+ }
12647
+ if (char === "/" && next === "*") {
12648
+ inBlockComment = true;
12649
+ index += 1;
12650
+ continue;
12651
+ }
12652
+ result += char;
12736
12653
  }
12737
- function parseArray() {
12738
- onArrayBegin();
12739
- scanNext();
12740
- let isFirstElement = true;
12741
- let needsComma = false;
12742
- while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
12743
- if (_scanner.getToken() === 5) {
12744
- if (!needsComma) {
12745
- handleError(4, [], []);
12746
- }
12747
- onSeparator(",");
12748
- scanNext();
12749
- if (_scanner.getToken() === 4 && allowTrailingComma) {
12750
- break;
12751
- }
12752
- } else if (needsComma) {
12753
- handleError(6, [], []);
12754
- }
12755
- if (isFirstElement) {
12756
- _jsonPath.push(0);
12757
- isFirstElement = false;
12758
- } else {
12759
- _jsonPath[_jsonPath.length - 1]++;
12760
- }
12761
- if (!parseValue()) {
12762
- handleError(4, [], [4, 5]);
12654
+ return result;
12655
+ }
12656
+ function stripTrailingCommas(content) {
12657
+ let result = "";
12658
+ let inString = false;
12659
+ let escaped = false;
12660
+ for (let index = 0;index < content.length; index += 1) {
12661
+ const char = content[index];
12662
+ if (inString) {
12663
+ result += char;
12664
+ if (escaped) {
12665
+ escaped = false;
12666
+ } else if (char === "\\") {
12667
+ escaped = true;
12668
+ } else if (char === '"') {
12669
+ inString = false;
12763
12670
  }
12764
- needsComma = true;
12671
+ continue;
12765
12672
  }
12766
- onArrayEnd();
12767
- if (!isFirstElement) {
12768
- _jsonPath.pop();
12673
+ if (char === '"') {
12674
+ inString = true;
12675
+ result += char;
12676
+ continue;
12769
12677
  }
12770
- if (_scanner.getToken() !== 4) {
12771
- handleError(8, [4], []);
12772
- } else {
12773
- scanNext();
12678
+ if (char === ",") {
12679
+ let lookahead = index + 1;
12680
+ while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
12681
+ lookahead += 1;
12682
+ }
12683
+ const next = content[lookahead];
12684
+ if (next === "}" || next === "]") {
12685
+ continue;
12686
+ }
12774
12687
  }
12775
- return true;
12688
+ result += char;
12776
12689
  }
12777
- function parseValue() {
12778
- switch (_scanner.getToken()) {
12779
- case 3:
12780
- return parseArray();
12781
- case 1:
12782
- return parseObject();
12783
- case 10:
12784
- return parseString(true);
12785
- default:
12786
- return parseLiteral();
12787
- }
12690
+ return result;
12691
+ }
12692
+ function isPrototypePollutionKey(key) {
12693
+ return PROTOTYPE_POLLUTION_KEYS.has(key);
12694
+ }
12695
+ function sanitizeParsedJson(value, options = {}, path = []) {
12696
+ if (Array.isArray(value)) {
12697
+ return value.map((entry, index) => sanitizeParsedJson(entry, options, [...path, index]));
12788
12698
  }
12789
- scanNext();
12790
- if (_scanner.getToken() === 17) {
12791
- if (options.allowEmptyContent) {
12792
- return true;
12699
+ if (value === null || typeof value !== "object")
12700
+ return value;
12701
+ const source = value;
12702
+ const sourcePrototype = Object.getPrototypeOf(source);
12703
+ if (sourcePrototype !== null && sourcePrototype !== Object.prototype) {
12704
+ options.onRejectedKey?.([...path, "__proto__"]);
12705
+ }
12706
+ const sanitized = {};
12707
+ for (const key of Object.keys(source)) {
12708
+ if (isPrototypePollutionKey(key)) {
12709
+ options.onRejectedKey?.([...path, key]);
12710
+ continue;
12793
12711
  }
12794
- handleError(4, [], []);
12795
- return false;
12712
+ Object.defineProperty(sanitized, key, {
12713
+ value: sanitizeParsedJson(source[key], options, [...path, key]),
12714
+ enumerable: true,
12715
+ configurable: true,
12716
+ writable: true
12717
+ });
12796
12718
  }
12797
- if (!parseValue()) {
12798
- handleError(4, [], []);
12799
- return false;
12719
+ return sanitized;
12720
+ }
12721
+ function lineAndColumnAt(content, offset) {
12722
+ const before = content.slice(0, Math.max(0, offset));
12723
+ const lines = before.split(/\r?\n/);
12724
+ return { line: lines.length, column: (lines.at(-1)?.length ?? 0) + 1 };
12725
+ }
12726
+ function parseIssue(content, error) {
12727
+ const location = lineAndColumnAt(content, error.offset);
12728
+ const code = printParseErrorCode(error.error);
12729
+ const message = code.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
12730
+ return {
12731
+ ...location,
12732
+ offset: error.offset,
12733
+ length: error.length,
12734
+ message
12735
+ };
12736
+ }
12737
+ function normalizeJsoncParserObjects(value, options, path = []) {
12738
+ if (Array.isArray(value)) {
12739
+ return value.map((entry, index) => normalizeJsoncParserObjects(entry, options, [...path, String(index)]));
12800
12740
  }
12801
- if (_scanner.getToken() !== 17) {
12802
- handleError(9, [], []);
12741
+ if (value === null || typeof value !== "object")
12742
+ return value;
12743
+ const prototype = Object.getPrototypeOf(value);
12744
+ if (prototype !== Object.prototype && prototype !== null) {
12745
+ options.onRejectedKey?.([...path, "__proto__"]);
12803
12746
  }
12804
- return true;
12747
+ const normalized = {};
12748
+ for (const [key, entry] of Object.entries(value)) {
12749
+ Object.defineProperty(normalized, key, {
12750
+ configurable: true,
12751
+ enumerable: true,
12752
+ writable: true,
12753
+ value: normalizeJsoncParserObjects(entry, options, [...path, key])
12754
+ });
12755
+ }
12756
+ return normalized;
12805
12757
  }
12806
- function getNodeType(value) {
12807
- switch (typeof value) {
12808
- case "boolean":
12809
- return "boolean";
12810
- case "number":
12811
- return "number";
12812
- case "string":
12813
- return "string";
12814
- case "object": {
12815
- if (!value) {
12816
- return "null";
12817
- } else if (Array.isArray(value)) {
12818
- return "array";
12819
- }
12820
- return "object";
12821
- }
12822
- default:
12823
- return "null";
12758
+ function parseJsoncRecovering(content, options = {}) {
12759
+ const errors = [];
12760
+ const parsed = parse2(content, errors, {
12761
+ allowTrailingComma: true,
12762
+ disallowComments: false,
12763
+ allowEmptyContent: false
12764
+ });
12765
+ return {
12766
+ value: sanitizeParsedJson(normalizeJsoncParserObjects(parsed, options), options),
12767
+ issues: errors.map((error) => parseIssue(content, error))
12768
+ };
12769
+ }
12770
+ function parseJsonc2(content, options = {}) {
12771
+ const normalized = stripTrailingCommas(stripJsonComments(content));
12772
+ return sanitizeParsedJson(JSON.parse(normalized), options);
12773
+ }
12774
+ function readJsoncFile(filePath) {
12775
+ try {
12776
+ return parseJsonc2(readFileSync5(filePath, "utf-8"));
12777
+ } catch (_error) {
12778
+ return null;
12824
12779
  }
12825
12780
  }
12826
- var ParseOptions;
12827
- var init_parser = __esm(() => {
12828
- init_scanner();
12829
- (function(ParseOptions) {
12830
- ParseOptions.DEFAULT = {
12831
- allowTrailingComma: false
12832
- };
12833
- })(ParseOptions || (ParseOptions = {}));
12781
+ function detectConfigFile(basePath) {
12782
+ const jsoncPath = `${basePath}.jsonc`;
12783
+ const jsonPath = `${basePath}.json`;
12784
+ if (existsSync8(jsoncPath)) {
12785
+ return { format: "jsonc", path: jsoncPath };
12786
+ }
12787
+ if (existsSync8(jsonPath)) {
12788
+ return { format: "json", path: jsonPath };
12789
+ }
12790
+ return { format: "none", path: jsoncPath };
12791
+ }
12792
+ var PROTOTYPE_POLLUTION_KEYS;
12793
+ var init_jsonc_parser = __esm(() => {
12794
+ init_main2();
12795
+ PROTOTYPE_POLLUTION_KEYS = new Set(["__proto__", "constructor", "prototype"]);
12834
12796
  });
12835
12797
 
12836
- // ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/edit.js
12837
- function setProperty(text, originalPath, value, options) {
12838
- const path = originalPath.slice();
12839
- const errors = [];
12840
- const root = parseTree(text, errors);
12841
- let parent = undefined;
12842
- let lastSegment = undefined;
12843
- while (path.length > 0) {
12844
- lastSegment = path.pop();
12845
- parent = findNodeAtLocation(root, path);
12846
- if (parent === undefined && value !== undefined) {
12847
- if (typeof lastSegment === "string") {
12848
- value = { [lastSegment]: value };
12849
- } else {
12850
- value = [value];
12851
- }
12852
- } else {
12853
- break;
12798
+ // src/lib/jsonc-config.ts
12799
+ import { existsSync as existsSync9, readFileSync as readFileSync6 } from "node:fs";
12800
+ function parseErrorLocation(content, error) {
12801
+ const lines = content.split(`
12802
+ `);
12803
+ const message = error instanceof Error ? error.message : String(error);
12804
+ if (message.includes("Unexpected end of JSON input")) {
12805
+ return { line: lines.length, column: (lines.at(-1)?.length ?? 0) + 1 };
12806
+ }
12807
+ const parserLocation = error;
12808
+ if (typeof parserLocation.line === "number" && parserLocation.line >= 1 && parserLocation.line <= lines.length && typeof parserLocation.column === "number" && parserLocation.column >= 0) {
12809
+ return { line: parserLocation.line, column: parserLocation.column + 1 };
12810
+ }
12811
+ const messageLine = /Line (\d+)/.exec(message)?.[1];
12812
+ return { line: messageLine ? Number.parseInt(messageLine, 10) : 1, column: 1 };
12813
+ }
12814
+ function readJsoncConfig(path) {
12815
+ if (!existsSync9(path))
12816
+ return { kind: "missing" };
12817
+ const content = readFileSync6(path, "utf-8");
12818
+ try {
12819
+ const rejectedKeyPaths = [];
12820
+ const parsed = sanitizeParsedJson(import_comment_json2.parse(content), {
12821
+ onRejectedKey: (keyPath) => rejectedKeyPaths.push(keyPath.join("."))
12822
+ });
12823
+ if (rejectedKeyPaths.length > 0) {
12824
+ throw new Error(`unsafe prototype-pollution key at ${rejectedKeyPaths.join(", ")}`);
12825
+ }
12826
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
12827
+ throw new Error("expected a JSON object at the document root");
12854
12828
  }
12829
+ return { kind: "parsed", value: parsed };
12830
+ } catch (error) {
12831
+ return { kind: "parse-error", error: new ConfigParseError(path, content, error) };
12855
12832
  }
12856
- if (!parent) {
12857
- if (value === undefined) {
12858
- throw new Error("Can not delete in empty document");
12833
+ }
12834
+ function readJsoncConfigForUpdate(path) {
12835
+ const result = readJsoncConfig(path);
12836
+ if (result.kind === "missing")
12837
+ return {};
12838
+ if (result.kind === "parse-error")
12839
+ throw result.error;
12840
+ return result.value;
12841
+ }
12842
+ function assertJsoncConfigsParseable(paths) {
12843
+ for (const path of paths) {
12844
+ const result = readJsoncConfig(path);
12845
+ if (result.kind === "parse-error")
12846
+ throw result.error;
12847
+ }
12848
+ }
12849
+ var import_comment_json2, ConfigParseError;
12850
+ var init_jsonc_config = __esm(() => {
12851
+ init_jsonc_parser();
12852
+ import_comment_json2 = __toESM(require_src3(), 1);
12853
+ ConfigParseError = class ConfigParseError extends Error {
12854
+ path;
12855
+ constructor(path, content, cause) {
12856
+ const detail = cause instanceof Error ? cause.message : String(cause);
12857
+ const location = parseErrorLocation(content, cause);
12858
+ super(`Refusing to overwrite unparseable config ${path} at line ${location.line}, column ${location.column}: ${detail}`, { cause });
12859
+ this.name = "ConfigParseError";
12860
+ this.path = path;
12859
12861
  }
12860
- return withFormatting(text, { offset: root ? root.offset : 0, length: root ? root.length : 0, content: JSON.stringify(value) }, options);
12861
- } else if (parent.type === "object" && typeof lastSegment === "string" && Array.isArray(parent.children)) {
12862
- const existing = findNodeAtLocation(parent, [lastSegment]);
12863
- if (existing !== undefined) {
12864
- if (value === undefined) {
12865
- if (!existing.parent) {
12866
- throw new Error("Malformed AST");
12867
- }
12868
- const propertyIndex = parent.children.indexOf(existing.parent);
12869
- let removeBegin;
12870
- let removeEnd = existing.parent.offset + existing.parent.length;
12871
- if (propertyIndex > 0) {
12872
- let previous = parent.children[propertyIndex - 1];
12873
- removeBegin = previous.offset + previous.length;
12874
- } else {
12875
- removeBegin = parent.offset + 1;
12876
- if (parent.children.length > 1) {
12877
- let next = parent.children[1];
12878
- removeEnd = next.offset;
12879
- }
12880
- }
12881
- return withFormatting(text, { offset: removeBegin, length: removeEnd - removeBegin, content: "" }, options);
12882
- } else {
12883
- return withFormatting(text, { offset: existing.offset, length: existing.length, content: JSON.stringify(value) }, options);
12884
- }
12885
- } else {
12886
- if (value === undefined) {
12887
- return [];
12888
- }
12889
- const newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
12890
- const index = options.getInsertionIndex ? options.getInsertionIndex(parent.children.map((p) => p.children[0].value)) : parent.children.length;
12891
- let edit;
12892
- if (index > 0) {
12893
- let previous = parent.children[index - 1];
12894
- edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
12895
- } else if (parent.children.length === 0) {
12896
- edit = { offset: parent.offset + 1, length: 0, content: newProperty };
12897
- } else {
12898
- edit = { offset: parent.offset + 1, length: 0, content: newProperty + "," };
12899
- }
12900
- return withFormatting(text, edit, options);
12862
+ };
12863
+ });
12864
+
12865
+ // src/lib/pi-package-entry.ts
12866
+ function stripNpmPrefix(value) {
12867
+ return value.startsWith("npm:") ? value.slice("npm:".length) : value;
12868
+ }
12869
+ function packageNameFromSpecifier(value) {
12870
+ const normalized = stripNpmPrefix(value.trim());
12871
+ if (!normalized)
12872
+ return normalized;
12873
+ if (normalized.startsWith("@")) {
12874
+ const slash = normalized.indexOf("/");
12875
+ if (slash < 0)
12876
+ return normalized;
12877
+ const versionAt = normalized.indexOf("@", slash + 1);
12878
+ return versionAt > 0 ? normalized.slice(0, versionAt) : normalized;
12879
+ }
12880
+ const versionAt = normalized.indexOf("@");
12881
+ return versionAt > 0 ? normalized.slice(0, versionAt) : normalized;
12882
+ }
12883
+ function getPiPackageEntryName(entry) {
12884
+ if (typeof entry === "string")
12885
+ return packageNameFromSpecifier(entry);
12886
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
12887
+ const object = entry;
12888
+ for (const key of ["name", "source"]) {
12889
+ const name = getPiPackageEntryName(object[key]);
12890
+ if (name)
12891
+ return name;
12901
12892
  }
12902
- } else if (parent.type === "array" && typeof lastSegment === "number" && Array.isArray(parent.children)) {
12903
- const insertIndex = lastSegment;
12904
- if (insertIndex === -1) {
12905
- const newProperty = `${JSON.stringify(value)}`;
12906
- let edit;
12907
- if (parent.children.length === 0) {
12908
- edit = { offset: parent.offset + 1, length: 0, content: newProperty };
12909
- } else {
12910
- const previous = parent.children[parent.children.length - 1];
12911
- edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
12893
+ }
12894
+ return null;
12895
+ }
12896
+ function isPiMagicContextPackageEntry(entry) {
12897
+ if (typeof entry === "string") {
12898
+ return packageNameFromSpecifier(entry) === PI_MAGIC_CONTEXT_PACKAGE_NAME;
12899
+ }
12900
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
12901
+ const object = entry;
12902
+ return isPiMagicContextPackageEntry(object.name) || isPiMagicContextPackageEntry(object.source);
12903
+ }
12904
+ return false;
12905
+ }
12906
+ function getPiMagicContextPackageSpecifier(entry) {
12907
+ if (typeof entry === "string") {
12908
+ return isPiMagicContextPackageEntry(entry) ? entry.trim() : null;
12909
+ }
12910
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
12911
+ const object = entry;
12912
+ return getPiMagicContextPackageSpecifier(object.source) ?? getPiMagicContextPackageSpecifier(object.name);
12913
+ }
12914
+ return null;
12915
+ }
12916
+ function hasPiMagicContextPackage(entries) {
12917
+ return entries.some(isPiMagicContextPackageEntry);
12918
+ }
12919
+ function describePiPackageEntry(entry) {
12920
+ if (typeof entry === "string")
12921
+ return entry;
12922
+ const name = getPiPackageEntryName(entry);
12923
+ if (name)
12924
+ return name;
12925
+ try {
12926
+ return JSON.stringify(entry);
12927
+ } catch {
12928
+ return String(entry);
12929
+ }
12930
+ }
12931
+ var PI_MAGIC_CONTEXT_PACKAGE_NAME = "@cortexkit/pi-magic-context";
12932
+
12933
+ // src/adapters/pi.ts
12934
+ import { existsSync as existsSync10 } from "node:fs";
12935
+ import { dirname as dirname5 } from "node:path";
12936
+
12937
+ class PiAdapter {
12938
+ kind = "pi";
12939
+ displayName = "Pi";
12940
+ pluginPackageName = PLUGIN_NAME;
12941
+ isInstalled() {
12942
+ return detectPiBinary() !== null;
12943
+ }
12944
+ hasPluginEntry() {
12945
+ const settings = readPiSettings();
12946
+ if (!settings)
12947
+ return false;
12948
+ const packages = settings.packages ?? [];
12949
+ return packages.some((entry) => isPiMagicContextPackageEntry(entry));
12950
+ }
12951
+ getConfigPaths() {
12952
+ const dir = getPiAgentConfigDir();
12953
+ return {
12954
+ configDir: dir,
12955
+ pluginConfigPath: getPiUserExtensionsPath(),
12956
+ magicContextConfigPath: getPiUserConfigPath(),
12957
+ secondaryConfigPath: null
12958
+ };
12959
+ }
12960
+ async ensurePluginEntry() {
12961
+ const settingsPath = getPiUserExtensionsPath();
12962
+ try {
12963
+ const settings = readPiSettingsForUpdate();
12964
+ const packages = Array.isArray(settings.packages) ? settings.packages : [];
12965
+ const idx = packages.findIndex((entry) => isPiMagicContextPackageEntry(entry));
12966
+ if (idx === -1) {
12967
+ packages.push(PI_PACKAGE_SOURCE);
12968
+ settings.packages = packages;
12969
+ writePiSettings(settings);
12970
+ return {
12971
+ ok: true,
12972
+ action: "added",
12973
+ message: `Added ${PI_PACKAGE_SOURCE} to ${settingsPath}.`,
12974
+ configPath: settingsPath
12975
+ };
12912
12976
  }
12913
- return withFormatting(text, edit, options);
12914
- } else if (value === undefined && parent.children.length >= 0) {
12915
- const removalIndex = lastSegment;
12916
- const toRemove = parent.children[removalIndex];
12917
- let edit;
12918
- if (parent.children.length === 1) {
12919
- edit = { offset: parent.offset + 1, length: parent.length - 2, content: "" };
12920
- } else if (parent.children.length - 1 === removalIndex) {
12921
- let previous = parent.children[removalIndex - 1];
12922
- let offset = previous.offset + previous.length;
12923
- let parentEndOffset = parent.offset + parent.length;
12924
- edit = { offset, length: parentEndOffset - 2 - offset, content: "" };
12925
- } else {
12926
- edit = { offset: toRemove.offset, length: parent.children[removalIndex + 1].offset - toRemove.offset, content: "" };
12977
+ return {
12978
+ ok: true,
12979
+ action: "already_present",
12980
+ message: `Plugin entry already present in ${settingsPath}.`,
12981
+ configPath: settingsPath
12982
+ };
12983
+ } catch (err) {
12984
+ return {
12985
+ ok: false,
12986
+ action: "error",
12987
+ message: `Failed to update ${settingsPath}: ${err.message}`,
12988
+ configPath: settingsPath
12989
+ };
12990
+ }
12991
+ }
12992
+ async removePluginEntry() {
12993
+ const settingsPath = getPiUserExtensionsPath();
12994
+ try {
12995
+ const settings = readPiSettingsForUpdate();
12996
+ if (!Array.isArray(settings.packages)) {
12997
+ return {
12998
+ ok: true,
12999
+ action: "already_present",
13000
+ message: `No packages array in ${settingsPath}.`,
13001
+ configPath: settingsPath
13002
+ };
12927
13003
  }
12928
- return withFormatting(text, edit, options);
12929
- } else if (value !== undefined) {
12930
- let edit;
12931
- const newProperty = `${JSON.stringify(value)}`;
12932
- if (!options.isArrayInsertion && parent.children.length > lastSegment) {
12933
- const toModify = parent.children[lastSegment];
12934
- edit = { offset: toModify.offset, length: toModify.length, content: newProperty };
12935
- } else if (parent.children.length === 0 || lastSegment === 0) {
12936
- edit = { offset: parent.offset + 1, length: 0, content: parent.children.length === 0 ? newProperty : newProperty + "," };
12937
- } else {
12938
- const index = lastSegment > parent.children.length ? parent.children.length : lastSegment;
12939
- const previous = parent.children[index - 1];
12940
- edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
13004
+ const before = settings.packages.length;
13005
+ settings.packages = settings.packages.filter((entry) => !isPiMagicContextPackageEntry(entry));
13006
+ if (settings.packages.length === before) {
13007
+ return {
13008
+ ok: true,
13009
+ action: "already_present",
13010
+ message: `Plugin entry not present in ${settingsPath}.`,
13011
+ configPath: settingsPath
13012
+ };
12941
13013
  }
12942
- return withFormatting(text, edit, options);
12943
- } else {
12944
- throw new Error(`Can not ${value === undefined ? "remove" : options.isArrayInsertion ? "insert" : "modify"} Array index ${insertIndex} as length is not sufficient`);
13014
+ writePiSettings(settings);
13015
+ return {
13016
+ ok: true,
13017
+ action: "updated",
13018
+ message: `Removed ${PLUGIN_NAME} from ${settingsPath}.`,
13019
+ configPath: settingsPath
13020
+ };
13021
+ } catch (err) {
13022
+ return {
13023
+ ok: false,
13024
+ action: "error",
13025
+ message: `Failed to update ${settingsPath}: ${err.message}`,
13026
+ configPath: settingsPath
13027
+ };
12945
13028
  }
12946
- } else {
12947
- throw new Error(`Can not add ${typeof lastSegment !== "number" ? "index" : "property"} to parent of type ${parent.type}`);
12948
13029
  }
12949
- }
12950
- function withFormatting(text, edit, options) {
12951
- if (!options.formattingOptions) {
12952
- return [edit];
13030
+ getInstallHint() {
13031
+ return "Install Pi: https://pi.coding/install (npm: @earendil-works/pi-coding-agent)";
12953
13032
  }
12954
- let newText = applyEdit(text, edit);
12955
- let begin = edit.offset;
12956
- let end = edit.offset + edit.content.length;
12957
- if (edit.length === 0 || edit.content.length === 0) {
12958
- while (begin > 0 && !isEOL(newText, begin - 1)) {
12959
- begin--;
12960
- }
12961
- while (end < newText.length && !isEOL(newText, end)) {
12962
- end++;
12963
- }
13033
+ getPluginCacheInfo() {
13034
+ return { path: null, exists: false, sizeBytes: 0 };
12964
13035
  }
12965
- const edits = format(newText, { offset: begin, length: end - begin }, { ...options.formattingOptions, keepLines: false });
12966
- for (let i = edits.length - 1;i >= 0; i--) {
12967
- const edit = edits[i];
12968
- newText = applyEdit(newText, edit);
12969
- begin = Math.min(begin, edit.offset);
12970
- end = Math.max(end, edit.offset + edit.length);
12971
- end += edit.content.length - edit.length;
13036
+ getLogPath() {
13037
+ return getMagicContextLogPath2("pi");
13038
+ }
13039
+ getInstalledPluginVersion() {
13040
+ const piBin = detectPiBinary();
13041
+ if (!piBin)
13042
+ return null;
13043
+ try {
13044
+ const output = runPiCommand(piBin.path, ["list"], 5000);
13045
+ if (output === null)
13046
+ return null;
13047
+ const re = new RegExp(`${PLUGIN_NAME.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&")}.*?(\\d+\\.\\d+\\.\\d+(?:[-+][\\w.-]+)?)`);
13048
+ const match = re.exec(output);
13049
+ if (match)
13050
+ return match[1] ?? null;
13051
+ } catch {}
13052
+ return null;
12972
13053
  }
12973
- const editLength = text.length - (newText.length - end) - begin;
12974
- return [{ offset: begin, length: editLength, content: newText.substring(begin, end) }];
12975
13054
  }
12976
- function applyEdit(text, edit) {
12977
- return text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);
13055
+ function readPiSettings() {
13056
+ const result = readJsoncConfig(getPiUserExtensionsPath());
13057
+ return result.kind === "parsed" ? result.value : null;
12978
13058
  }
12979
- var init_edit = __esm(() => {
12980
- init_format();
12981
- init_parser();
13059
+ function readPiSettingsForUpdate() {
13060
+ return readJsoncConfigForUpdate(getPiUserExtensionsPath());
13061
+ }
13062
+ function writePiSettings(settings) {
13063
+ const settingsPath = getPiUserExtensionsPath();
13064
+ ensureDir2(settingsPath);
13065
+ const text = import_comment_json3.stringify(settings, null, 2);
13066
+ writeFileAtomic(settingsPath, `${text}
13067
+ `);
13068
+ }
13069
+ function ensureDir2(filePath) {
13070
+ const dir = dirname5(filePath);
13071
+ if (!existsSync10(dir)) {
13072
+ const { mkdirSync } = __require("node:fs");
13073
+ mkdirSync(dir, { recursive: true });
13074
+ }
13075
+ }
13076
+ var import_comment_json3, PLUGIN_NAME = "@cortexkit/pi-magic-context";
13077
+ var init_pi = __esm(() => {
13078
+ init_atomic_write();
13079
+ init_jsonc_config();
13080
+ init_paths();
13081
+ init_pi_helpers();
13082
+ import_comment_json3 = __toESM(require_src3(), 1);
12982
13083
  });
12983
13084
 
12984
- // ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js
12985
- function modify(text, path, value, options) {
12986
- return setProperty(text, path, value, options);
13085
+ // src/adapters/index.ts
13086
+ function getAdapter(kind) {
13087
+ const found = ALL.find((a) => a.kind === kind);
13088
+ if (!found)
13089
+ throw new Error(`Unknown harness: ${kind}`);
13090
+ return found;
12987
13091
  }
12988
- function applyEdits(text, edits) {
12989
- let sortedEdits = edits.slice(0).sort((a, b) => {
12990
- const diff = a.offset - b.offset;
12991
- if (diff === 0) {
12992
- return a.length - b.length;
12993
- }
12994
- return diff;
12995
- });
12996
- let lastModifiedOffset = text.length;
12997
- for (let i = sortedEdits.length - 1;i >= 0; i--) {
12998
- let e = sortedEdits[i];
12999
- if (e.offset + e.length <= lastModifiedOffset) {
13000
- text = applyEdit(text, e);
13001
- } else {
13002
- throw new Error("Overlapping edit");
13092
+ function getInstalledAdapters() {
13093
+ return ALL.filter((a) => a.isInstalled());
13094
+ }
13095
+ var ALL;
13096
+ var init_adapters = __esm(() => {
13097
+ init_omp();
13098
+ init_opencode();
13099
+ init_pi();
13100
+ ALL = [new OpenCodeAdapter, new PiAdapter, new OmpAdapter];
13101
+ });
13102
+
13103
+ // src/lib/harness-select.ts
13104
+ function parseHarnessFlag(argv) {
13105
+ const idx = argv.indexOf("--harness");
13106
+ if (idx === -1)
13107
+ return { kind: "absent" };
13108
+ const value = argv[idx + 1];
13109
+ if (!value || value.startsWith("--"))
13110
+ return { kind: "invalid", value: null };
13111
+ if (value === "opencode" || value === "pi" || value === "omp") {
13112
+ return { kind: "valid", harness: value };
13113
+ }
13114
+ return { kind: "invalid", value };
13115
+ }
13116
+ async function resolveAdaptersForCommand(argv, options) {
13117
+ const flag = parseHarnessFlag(argv);
13118
+ if (flag.kind === "valid")
13119
+ return [getAdapter(flag.harness)];
13120
+ if (flag.kind === "invalid") {
13121
+ throw new Error(flag.value === null ? "Missing value for --harness (expected opencode, pi, or omp)" : `Invalid --harness value: ${flag.value} (expected opencode, pi, or omp)`);
13122
+ }
13123
+ const installed = getInstalledAdapters();
13124
+ if (installed.length === 0) {
13125
+ log2.warn("No supported harness was detected on PATH (opencode, pi, omp).");
13126
+ const pick = await selectOne(`Which harness do you want to ${options.verb}?`, [
13127
+ {
13128
+ label: "OpenCode",
13129
+ value: "opencode",
13130
+ hint: "@cortexkit/opencode-magic-context"
13131
+ },
13132
+ {
13133
+ label: "Pi",
13134
+ value: "pi",
13135
+ hint: "@cortexkit/pi-magic-context"
13136
+ },
13137
+ {
13138
+ label: "Oh My Pi (OMP)",
13139
+ value: "omp",
13140
+ hint: "@cortexkit/pi-magic-context"
13141
+ }
13142
+ ]);
13143
+ return [getAdapter(pick)];
13144
+ }
13145
+ if (installed.length === 1) {
13146
+ const only = installed[0];
13147
+ log2.info(`Detected ${only.displayName} — using it for ${options.verb}.`);
13148
+ return [only];
13149
+ }
13150
+ if (options.allowMulti) {
13151
+ const picks = await selectMany(`Multiple harnesses detected — which to ${options.verb}?`, installed.map((a) => ({ label: a.displayName, value: a.kind })), installed.map((a) => a.kind));
13152
+ if (picks.length === 0) {
13153
+ log2.warn("No harness selected; nothing to do.");
13154
+ return [];
13003
13155
  }
13004
- lastModifiedOffset = e.offset;
13156
+ return picks.map((kind) => getAdapter(kind));
13005
13157
  }
13006
- return text;
13158
+ const pick = await selectOne(`Multiple harnesses detected — which one to ${options.verb}?`, installed.map((a) => ({ label: a.displayName, value: a.kind })));
13159
+ return [getAdapter(pick)];
13007
13160
  }
13008
- var createScanner2, ScanError, SyntaxKind, parseTree2, findNodeAtLocation2, getNodeValue2, ParseErrorCode;
13009
- var init_main2 = __esm(() => {
13010
- init_format();
13011
- init_edit();
13012
- init_scanner();
13013
- init_parser();
13014
- createScanner2 = createScanner;
13015
- (function(ScanError) {
13016
- ScanError[ScanError["None"] = 0] = "None";
13017
- ScanError[ScanError["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
13018
- ScanError[ScanError["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
13019
- ScanError[ScanError["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
13020
- ScanError[ScanError["InvalidUnicode"] = 4] = "InvalidUnicode";
13021
- ScanError[ScanError["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
13022
- ScanError[ScanError["InvalidCharacter"] = 6] = "InvalidCharacter";
13023
- })(ScanError || (ScanError = {}));
13024
- (function(SyntaxKind) {
13025
- SyntaxKind[SyntaxKind["OpenBraceToken"] = 1] = "OpenBraceToken";
13026
- SyntaxKind[SyntaxKind["CloseBraceToken"] = 2] = "CloseBraceToken";
13027
- SyntaxKind[SyntaxKind["OpenBracketToken"] = 3] = "OpenBracketToken";
13028
- SyntaxKind[SyntaxKind["CloseBracketToken"] = 4] = "CloseBracketToken";
13029
- SyntaxKind[SyntaxKind["CommaToken"] = 5] = "CommaToken";
13030
- SyntaxKind[SyntaxKind["ColonToken"] = 6] = "ColonToken";
13031
- SyntaxKind[SyntaxKind["NullKeyword"] = 7] = "NullKeyword";
13032
- SyntaxKind[SyntaxKind["TrueKeyword"] = 8] = "TrueKeyword";
13033
- SyntaxKind[SyntaxKind["FalseKeyword"] = 9] = "FalseKeyword";
13034
- SyntaxKind[SyntaxKind["StringLiteral"] = 10] = "StringLiteral";
13035
- SyntaxKind[SyntaxKind["NumericLiteral"] = 11] = "NumericLiteral";
13036
- SyntaxKind[SyntaxKind["LineCommentTrivia"] = 12] = "LineCommentTrivia";
13037
- SyntaxKind[SyntaxKind["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
13038
- SyntaxKind[SyntaxKind["LineBreakTrivia"] = 14] = "LineBreakTrivia";
13039
- SyntaxKind[SyntaxKind["Trivia"] = 15] = "Trivia";
13040
- SyntaxKind[SyntaxKind["Unknown"] = 16] = "Unknown";
13041
- SyntaxKind[SyntaxKind["EOF"] = 17] = "EOF";
13042
- })(SyntaxKind || (SyntaxKind = {}));
13043
- parseTree2 = parseTree;
13044
- findNodeAtLocation2 = findNodeAtLocation;
13045
- getNodeValue2 = getNodeValue;
13046
- (function(ParseErrorCode) {
13047
- ParseErrorCode[ParseErrorCode["InvalidSymbol"] = 1] = "InvalidSymbol";
13048
- ParseErrorCode[ParseErrorCode["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
13049
- ParseErrorCode[ParseErrorCode["PropertyNameExpected"] = 3] = "PropertyNameExpected";
13050
- ParseErrorCode[ParseErrorCode["ValueExpected"] = 4] = "ValueExpected";
13051
- ParseErrorCode[ParseErrorCode["ColonExpected"] = 5] = "ColonExpected";
13052
- ParseErrorCode[ParseErrorCode["CommaExpected"] = 6] = "CommaExpected";
13053
- ParseErrorCode[ParseErrorCode["CloseBraceExpected"] = 7] = "CloseBraceExpected";
13054
- ParseErrorCode[ParseErrorCode["CloseBracketExpected"] = 8] = "CloseBracketExpected";
13055
- ParseErrorCode[ParseErrorCode["EndOfFileExpected"] = 9] = "EndOfFileExpected";
13056
- ParseErrorCode[ParseErrorCode["InvalidCommentToken"] = 10] = "InvalidCommentToken";
13057
- ParseErrorCode[ParseErrorCode["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
13058
- ParseErrorCode[ParseErrorCode["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
13059
- ParseErrorCode[ParseErrorCode["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
13060
- ParseErrorCode[ParseErrorCode["InvalidUnicode"] = 14] = "InvalidUnicode";
13061
- ParseErrorCode[ParseErrorCode["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
13062
- ParseErrorCode[ParseErrorCode["InvalidCharacter"] = 16] = "InvalidCharacter";
13063
- })(ParseErrorCode || (ParseErrorCode = {}));
13161
+ var init_harness_select = __esm(() => {
13162
+ init_adapters();
13163
+ init_prompts();
13164
+ });
13165
+
13166
+ // ../plugin/src/shared/harness-provider-map.ts
13167
+ function remapProviderPrefix(ref, map) {
13168
+ if (typeof ref !== "string")
13169
+ return ref;
13170
+ const slash = ref.indexOf("/");
13171
+ if (slash <= 0)
13172
+ return ref;
13173
+ const provider = ref.slice(0, slash);
13174
+ if (!Object.hasOwn(map, provider))
13175
+ return ref;
13176
+ return `${map[provider]}${ref.slice(slash)}`;
13177
+ }
13178
+ function piModelRefToCanonical(ref) {
13179
+ return remapProviderPrefix(ref, PI_TO_CANONICAL_PROVIDER);
13180
+ }
13181
+ function ompModelRefToCanonical(ref) {
13182
+ return remapProviderPrefix(ref, OMP_TO_CANONICAL_PROVIDER);
13183
+ }
13184
+ var PI_TO_CANONICAL_PROVIDER, OMP_TO_CANONICAL_PROVIDER;
13185
+ var init_harness_provider_map = __esm(() => {
13186
+ PI_TO_CANONICAL_PROVIDER = {
13187
+ "openai-codex": "openai",
13188
+ "google-antigravity": "google"
13189
+ };
13190
+ OMP_TO_CANONICAL_PROVIDER = {
13191
+ "openai-codex": "openai",
13192
+ "google-antigravity": "google",
13193
+ "opencode-zen": "opencode"
13194
+ };
13064
13195
  });
13065
13196
 
13066
13197
  // ../plugin/src/shared/jsonc-edit.ts
@@ -14458,6 +14589,17 @@ var init_setup_omp = __esm(() => {
14458
14589
  OMP_HOST = createOmpHost(DEFAULT_DEPS2);
14459
14590
  });
14460
14591
 
14592
+ // ../plugin/src/shared/config-diagnostics.ts
14593
+ var CONFIG_WARNING_CLASS, claimedFailures;
14594
+ var init_config_diagnostics = __esm(() => {
14595
+ CONFIG_WARNING_CLASS = {
14596
+ FILE_PARSE: "file-parse",
14597
+ FILE_IO: "file-io",
14598
+ INVALID_LEAF: "invalid-leaf"
14599
+ };
14600
+ claimedFailures = new Set;
14601
+ });
14602
+
14461
14603
  // ../plugin/src/shared/redaction.ts
14462
14604
  import { homedir as homedir7, userInfo } from "node:os";
14463
14605
  function escapeRegex(value) {
@@ -19223,11 +19365,11 @@ var init_errors2 = __esm(() => {
19223
19365
  });
19224
19366
 
19225
19367
  // ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/parse.js
19226
- var parse4, parseAsync2, safeParse2, safeParseAsync2, encode, decode, encodeAsync, decodeAsync, safeEncode, safeDecode, safeEncodeAsync, safeDecodeAsync;
19368
+ var parse5, parseAsync2, safeParse2, safeParseAsync2, encode, decode, encodeAsync, decodeAsync, safeEncode, safeDecode, safeEncodeAsync, safeDecodeAsync;
19227
19369
  var init_parse2 = __esm(() => {
19228
19370
  init_core2();
19229
19371
  init_errors2();
19230
- parse4 = /* @__PURE__ */ _parse(ZodRealError);
19372
+ parse5 = /* @__PURE__ */ _parse(ZodRealError);
19231
19373
  parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
19232
19374
  safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
19233
19375
  safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
@@ -19453,7 +19595,7 @@ var init_schemas2 = __esm(() => {
19453
19595
  inst.def = def;
19454
19596
  inst.type = def.type;
19455
19597
  Object.defineProperty(inst, "_def", { value: def });
19456
- inst.parse = (data, params) => parse4(inst, data, params, { callee: inst.parse });
19598
+ inst.parse = (data, params) => parse5(inst, data, params, { callee: inst.parse });
19457
19599
  inst.safeParse = (data, params) => safeParse2(inst, data, params);
19458
19600
  inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
19459
19601
  inst.safeParseAsync = async (data, params) => safeParseAsync2(inst, data, params);
@@ -21317,10 +21459,13 @@ function loadConfigFileDetailed(configPath, source) {
21317
21459
  rawText = raw.text;
21318
21460
  rawWarnings = raw.warnings;
21319
21461
  } catch (error) {
21462
+ const message = `failed to read config: ${error instanceof Error ? error.message : String(error)}`;
21320
21463
  return {
21321
21464
  config: {},
21322
- warnings: [
21323
- `${configPath}: failed to read config: ${error instanceof Error ? error.message : String(error)}`
21465
+ warnings: [`${configPath}: ${message}`],
21466
+ parseFailures: [],
21467
+ warningDetails: [
21468
+ { warningClass: CONFIG_WARNING_CLASS.FILE_IO, source, path: configPath, message }
21324
21469
  ],
21325
21470
  outcome: "project-file-io-error",
21326
21471
  source
@@ -21333,22 +21478,56 @@ function loadConfigFileDetailed(configPath, source) {
21333
21478
  isProjectConfig: source === "project"
21334
21479
  });
21335
21480
  const rejectedKeyPaths = [];
21336
- const config = parseJsonc2(substituted.text, {
21481
+ const parsed = parseJsoncRecovering(substituted.text, {
21337
21482
  onRejectedKey: (path) => rejectedKeyPaths.push(path.join("."))
21338
21483
  });
21484
+ const config = parsed.value && typeof parsed.value === "object" && !Array.isArray(parsed.value) ? parsed.value : {};
21339
21485
  const unsafeKeyWarnings = rejectedKeyPaths.map((path) => `Ignored unsafe config key "${path}" (security: prototype-pollution keys are not allowed).`);
21486
+ const firstIssue = parsed.issues[0];
21487
+ const recovered = firstIssue !== undefined && Object.keys(config).length > 0;
21488
+ const parseFailures = firstIssue ? [
21489
+ {
21490
+ warningClass: CONFIG_WARNING_CLASS.FILE_PARSE,
21491
+ source,
21492
+ path: configPath,
21493
+ line: firstIssue.line,
21494
+ column: firstIssue.column,
21495
+ message: firstIssue.message,
21496
+ recovered,
21497
+ warning: `${configPath}:${firstIssue.line}:${firstIssue.column}: ${firstIssue.message}; ${recovered ? "recovered values were applied, but the file must be fixed." : "using defaults for this file."}`
21498
+ }
21499
+ ] : [];
21340
21500
  return {
21341
21501
  config,
21342
- warnings: [...rawWarnings, ...substituted.warnings, ...unsafeKeyWarnings].map((warning) => `${configPath}: ${warning}`),
21343
- outcome: rejectedKeyPaths.length > 0 ? "schema-recovery" : substituted.warnings.length > 0 ? "substitution-failure" : "ok",
21502
+ warnings: [
21503
+ ...parseFailures.map((failure) => failure.warning),
21504
+ ...rawWarnings.map((warning) => `${configPath}: ${warning}`),
21505
+ ...substituted.warnings.map((warning) => `${configPath}: ${warning}`),
21506
+ ...unsafeKeyWarnings.map((warning) => `${configPath}: ${warning}`)
21507
+ ],
21508
+ parseFailures,
21509
+ warningDetails: parseFailures,
21510
+ outcome: parseFailures.length > 0 ? "project-file-parse-error" : rejectedKeyPaths.length > 0 ? "schema-recovery" : substituted.warnings.length > 0 ? "substitution-failure" : "ok",
21344
21511
  source
21345
21512
  };
21346
21513
  } catch (error) {
21514
+ const message = error instanceof Error ? error.message : String(error);
21515
+ const warning = `${configPath}:1:1: ${message}; using defaults for this file.`;
21516
+ const failure = {
21517
+ warningClass: CONFIG_WARNING_CLASS.FILE_PARSE,
21518
+ source,
21519
+ path: configPath,
21520
+ line: 1,
21521
+ column: 1,
21522
+ message,
21523
+ recovered: false,
21524
+ warning
21525
+ };
21347
21526
  return {
21348
21527
  config: {},
21349
- warnings: [
21350
- `${configPath}: failed to load config: ${error instanceof Error ? error.message : String(error)}`
21351
- ],
21528
+ warnings: [warning],
21529
+ parseFailures: [failure],
21530
+ warningDetails: [failure],
21352
21531
  outcome: "project-file-parse-error",
21353
21532
  source
21354
21533
  };
@@ -21610,11 +21789,13 @@ function loadPluginConfigDetailed(directory) {
21610
21789
  }
21611
21790
  }
21612
21791
  const recoveredTopLevelKeys = [];
21792
+ const cacheTtlConfigured = Object.hasOwn(mergedRaw, "cache_ttl");
21613
21793
  const config = parsePluginConfig(mergedRaw, recoveredTopLevelKeys);
21614
21794
  if (profileResolution.activeProfile)
21615
21795
  config.profile = profileResolution.activeProfile;
21616
21796
  setOutputReserveConfig(config.output_reserve);
21617
21797
  setWindowOverlayPath(config.models?.window_overlay_path);
21798
+ const leafValidationWarnings = [...config.configWarnings ?? []];
21618
21799
  if (config.configWarnings?.length) {
21619
21800
  allWarnings.push(...config.configWarnings.map((w) => {
21620
21801
  if (userLoaded && projectLoaded)
@@ -21640,6 +21821,21 @@ function loadPluginConfigDetailed(directory) {
21640
21821
  ...bindSubstitutionFailures(userLoaded),
21641
21822
  ...bindSubstitutionFailures(projectLoaded)
21642
21823
  ];
21824
+ const configParseFailures = [
21825
+ ...userLoaded?.parseFailures ?? [],
21826
+ ...projectLoaded?.parseFailures ?? []
21827
+ ];
21828
+ const warningDetails = [
21829
+ ...userLoaded?.warningDetails ?? [],
21830
+ ...projectLoaded?.warningDetails ?? [],
21831
+ ...leafValidationWarnings.map((message) => ({
21832
+ warningClass: CONFIG_WARNING_CLASS.INVALID_LEAF,
21833
+ message
21834
+ }))
21835
+ ];
21836
+ config.configParseFailures = configParseFailures;
21837
+ config.configWarningDetails = warningDetails;
21838
+ config.cacheTtlConfigured = cacheTtlConfigured;
21643
21839
  const sources = {
21644
21840
  userConfig: userLoaded?.outcome ?? (legacyUserUnmigrated ? "legacy-config-unmigrated" : "ok"),
21645
21841
  projectConfig: projectLoaded?.outcome ?? (legacyProjectUnmigrated ? "legacy-config-unmigrated" : "ok")
@@ -21650,10 +21846,14 @@ function loadPluginConfigDetailed(directory) {
21650
21846
  loadOutcome: combinedOutcome({ sources, substitutionFailures, recoveredTopLevelKeys }),
21651
21847
  sources,
21652
21848
  substitutionFailures,
21653
- recoveredTopLevelKeys
21849
+ recoveredTopLevelKeys,
21850
+ configParseFailures,
21851
+ warningDetails,
21852
+ cacheTtlConfigured
21654
21853
  };
21655
21854
  }
21656
21855
  var init_config = __esm(() => {
21856
+ init_config_diagnostics();
21657
21857
  init_jsonc_parser();
21658
21858
  init_models_dev_cache();
21659
21859
  init_window_geometry();
@@ -25904,6 +26104,18 @@ var init_module_transport = __esm(() => {
25904
26104
  init_dist5();
25905
26105
  init_data_path();
25906
26106
  });
26107
+ // ../plugin/src/shared/pi-executable.ts
26108
+ function piHarnessKindFromExecutable(value) {
26109
+ const executable = (value ?? "").trim().replace(/^['"]|['"]$/g, "").replaceAll("\\", "/").split("/").at(-1)?.toLowerCase().replace(/\.(?:exe|cmd)$/, "");
26110
+ if (!executable || !PI_IMAGE_NAMES.has(executable))
26111
+ return;
26112
+ return executable === "pi" ? "pi" : "omp";
26113
+ }
26114
+ var PI_IMAGE_NAMES;
26115
+ var init_pi_executable = __esm(() => {
26116
+ PI_IMAGE_NAMES = new Set(["pi", "pi.cmd", "omp", "oh-my-pi"]);
26117
+ });
26118
+
25907
26119
  // ../plugin/src/shared/rpc-utils.ts
25908
26120
  import { execFileSync as execFileSync4 } from "node:child_process";
25909
26121
  import { readFileSync as readFileSync11 } from "node:fs";
@@ -26089,7 +26301,7 @@ function commandHasOpenCodeExecutable(tokens) {
26089
26301
  function commandHasPiExecutable(tokens) {
26090
26302
  for (let index = 0;index < tokens.length; index += 1) {
26091
26303
  const executable = executableName(tokens[index]).replace(/\.(?:exe|cmd)$/, "");
26092
- if (["pi", "omp", "oh-my-pi"].includes(executable))
26304
+ if (piHarnessKindFromExecutable(executable) !== undefined)
26093
26305
  return true;
26094
26306
  if (["node", "bun", "deno"].includes(executable)) {
26095
26307
  const script = executableName(tokens[index + 1]).replace(/\.(?:exe|cmd)$/, "");
@@ -26429,9 +26641,10 @@ function parseRpcPortFile(content, fallbackPid = 0) {
26429
26641
  function isValidPort(port) {
26430
26642
  return Number.isInteger(port) && port > 0 && port <= 65535;
26431
26643
  }
26432
- var RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, WINDOWS_CIM_PROBE_TIMEOUT_MS = 5000, MAX_ANCESTOR_WALK_DEPTH = 16, OPEN_CODE_COMMAND_MARKERS, TASKLIST_NO_TASKS_PATTERN, WINDOWS_CIM_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress", PI_HARNESS_ARC_MARKERS, PI_IMAGE_NAMES, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcIdentityProcessKill, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now(), windowsProcessFactsCache = null;
26644
+ var RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, WINDOWS_CIM_PROBE_TIMEOUT_MS = 5000, MAX_ANCESTOR_WALK_DEPTH = 16, OPEN_CODE_COMMAND_MARKERS, TASKLIST_NO_TASKS_PATTERN, WINDOWS_CIM_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress", PI_HARNESS_ARC_MARKERS, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcIdentityProcessKill, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now(), windowsProcessFactsCache = null;
26433
26645
  var init_rpc_utils = __esm(() => {
26434
26646
  init_logger();
26647
+ init_pi_executable();
26435
26648
  OPEN_CODE_COMMAND_MARKERS = ["opencode", "node", "bun", "electron"];
26436
26649
  TASKLIST_NO_TASKS_PATTERN = /^INFO:\s+No tasks are running which match the specified criteria\.?$/im;
26437
26650
  PI_HARNESS_ARC_MARKERS = [
@@ -26441,7 +26654,6 @@ var init_rpc_utils = __esm(() => {
26441
26654
  "cljs/dist",
26442
26655
  "dist/bundle/cli"
26443
26656
  ];
26444
- PI_IMAGE_NAMES = new Set(["pi", "pi.cmd", "omp", "oh-my-pi"]);
26445
26657
  rpcIdentityReadFileSync = readFileSync11;
26446
26658
  rpcIdentityExecFileSync = execFileSync4;
26447
26659
  rpcIdentityProcessKill = process.kill;
@@ -33455,39 +33667,91 @@ function resolvePiLegacyFallback(sources) {
33455
33667
  return sources.find((source) => existsSync23(source.path)) ?? null;
33456
33668
  }
33457
33669
  function loadConfigFile(path, scope) {
33670
+ let raw;
33458
33671
  try {
33459
- const raw = loadRawConfigFile({ configPath: path, tier: scope });
33672
+ raw = loadRawConfigFile({ configPath: path, tier: scope });
33460
33673
  if (!raw)
33461
33674
  return null;
33675
+ } catch (error) {
33676
+ const message = `failed to read config: ${error instanceof Error ? error.message : String(error)}`;
33677
+ return {
33678
+ path,
33679
+ scope,
33680
+ config: {},
33681
+ warnings: [`${path}: ${message}`],
33682
+ parseFailures: [],
33683
+ warningDetails: [
33684
+ {
33685
+ warningClass: CONFIG_WARNING_CLASS.FILE_IO,
33686
+ source: scope,
33687
+ path,
33688
+ message
33689
+ }
33690
+ ],
33691
+ loadOutcome: "project-file-io-error"
33692
+ };
33693
+ }
33694
+ try {
33462
33695
  const substituted = substituteConfigVariables({
33463
33696
  text: raw.text,
33464
33697
  configPath: path,
33465
33698
  isProjectConfig: scope === "project"
33466
33699
  });
33467
33700
  const rejectedKeyPaths = [];
33468
- const config = sanitizeParsedJson(import_comment_json7.parse(substituted.text), { onRejectedKey: (keyPath) => rejectedKeyPaths.push(keyPath.join(".")) });
33701
+ const parsed = parseJsoncRecovering(substituted.text, {
33702
+ onRejectedKey: (keyPath) => rejectedKeyPaths.push(keyPath.join("."))
33703
+ });
33704
+ const config = parsed.value && typeof parsed.value === "object" && !Array.isArray(parsed.value) ? parsed.value : {};
33469
33705
  const unsafeKeyWarnings = rejectedKeyPaths.map((keyPath) => `Ignored unsafe config key "${keyPath}" (security: prototype-pollution keys are not allowed).`);
33706
+ const firstIssue = parsed.issues[0];
33707
+ const recovered = firstIssue !== undefined && Object.keys(config).length > 0;
33708
+ const parseFailures = firstIssue ? [
33709
+ {
33710
+ warningClass: CONFIG_WARNING_CLASS.FILE_PARSE,
33711
+ source: scope,
33712
+ path,
33713
+ line: firstIssue.line,
33714
+ column: firstIssue.column,
33715
+ message: firstIssue.message,
33716
+ recovered,
33717
+ warning: `${path}:${firstIssue.line}:${firstIssue.column}: ${firstIssue.message}; ${recovered ? "recovered values were applied, but the file must be fixed." : "using defaults for this file."}`
33718
+ }
33719
+ ] : [];
33470
33720
  return {
33471
33721
  path,
33472
33722
  scope,
33473
33723
  config,
33474
33724
  warnings: [
33475
- ...raw.warnings,
33476
- ...substituted.warnings,
33477
- ...unsafeKeyWarnings
33478
- ].map((warning) => `${path}: ${warning}`),
33479
- loadOutcome: rejectedKeyPaths.length > 0 ? "schema-recovery" : substituted.warnings.length > 0 ? "substitution-failure" : "ok"
33725
+ ...parseFailures.map((failure) => failure.warning),
33726
+ ...raw.warnings.map((warning) => `${path}: ${warning}`),
33727
+ ...substituted.warnings.map((warning) => `${path}: ${warning}`),
33728
+ ...unsafeKeyWarnings.map((warning) => `${path}: ${warning}`)
33729
+ ],
33730
+ parseFailures,
33731
+ warningDetails: parseFailures,
33732
+ loadOutcome: parseFailures.length > 0 ? "project-file-parse-error" : rejectedKeyPaths.length > 0 ? "schema-recovery" : substituted.warnings.length > 0 ? "substitution-failure" : "ok"
33480
33733
  };
33481
33734
  } catch (error) {
33482
33735
  const message = error instanceof Error ? error.message : String(error);
33736
+ const warning = `${path}:1:1: ${message}; using defaults for this file.`;
33737
+ const failure = {
33738
+ warningClass: CONFIG_WARNING_CLASS.FILE_PARSE,
33739
+ source: scope,
33740
+ path,
33741
+ line: 1,
33742
+ column: 1,
33743
+ message,
33744
+ recovered: false,
33745
+ warning
33746
+ };
33483
33747
  return {
33484
33748
  path,
33485
33749
  scope,
33486
33750
  config: {},
33487
- warnings: [
33488
- `${path}: failed to load config: ${message}; using defaults for this file.`
33489
- ],
33490
- loadOutcome: typeof error.code === "string" ? "project-file-io-error" : "project-file-parse-error"
33751
+ warnings: [warning],
33752
+ parseFailures: [failure],
33753
+ warningDetails: [failure],
33754
+ loadOutcome: "project-file-parse-error"
33491
33755
  };
33492
33756
  }
33493
33757
  }
@@ -33610,6 +33874,63 @@ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
33610
33874
  return { config: defaults, warnings };
33611
33875
  }
33612
33876
  function loadPiConfig(opts = {}) {
33877
+ const detailed = loadPiConfigDetailed(opts);
33878
+ return {
33879
+ config: detailed.config,
33880
+ registrationPromptSurface: detailed.registrationPromptSurface,
33881
+ warnings: detailed.warnings,
33882
+ loadedFromPaths: detailed.loadedFromPaths,
33883
+ configParseFailures: detailed.configParseFailures,
33884
+ warningDetails: detailed.warningDetails,
33885
+ cacheTtlConfigured: detailed.cacheTtlConfigured
33886
+ };
33887
+ }
33888
+ function collectEmptyStringPaths2(value, prefix = "") {
33889
+ if (typeof value === "string") {
33890
+ return value === "" && prefix ? [prefix] : [];
33891
+ }
33892
+ if (Array.isArray(value) || value === null || typeof value !== "object") {
33893
+ return [];
33894
+ }
33895
+ const paths = [];
33896
+ for (const [key, child] of Object.entries(value)) {
33897
+ const nextPrefix = prefix ? `${prefix}.${key}` : key;
33898
+ paths.push(...collectEmptyStringPaths2(child, nextPrefix));
33899
+ }
33900
+ return paths;
33901
+ }
33902
+ function bindSubstitutionFailures2(loaded) {
33903
+ if (loaded.warnings.length === 0 || loaded.loadOutcome !== "substitution-failure") {
33904
+ return [];
33905
+ }
33906
+ const emptyPaths = collectEmptyStringPaths2(loaded.config);
33907
+ return loaded.warnings.map((message) => {
33908
+ const matchedPath = emptyPaths.find((path) => {
33909
+ const tail = path.split(".").at(-1) ?? path;
33910
+ return message.includes(path) || message.toLowerCase().includes(tail.toLowerCase());
33911
+ });
33912
+ return {
33913
+ keyPath: matchedPath ?? "<unknown>",
33914
+ source: loaded.scope,
33915
+ message
33916
+ };
33917
+ });
33918
+ }
33919
+ function combinedOutcome2(args) {
33920
+ const sourceOutcomes = Object.values(args.sources);
33921
+ if (sourceOutcomes.includes("project-file-parse-error"))
33922
+ return "project-file-parse-error";
33923
+ if (sourceOutcomes.includes("project-file-io-error"))
33924
+ return "project-file-io-error";
33925
+ if (sourceOutcomes.includes("legacy-config-unmigrated"))
33926
+ return "legacy-config-unmigrated";
33927
+ if (args.recoveredTopLevelKeys.length > 0)
33928
+ return "schema-recovery";
33929
+ if (args.substitutionFailures.length > 0)
33930
+ return "substitution-failure";
33931
+ return "ok";
33932
+ }
33933
+ function loadPiConfigDetailed(opts = {}) {
33613
33934
  const cwd = opts.cwd ?? process.cwd();
33614
33935
  const loadedFiles = [];
33615
33936
  const warnings = [];
@@ -33649,7 +33970,7 @@ function loadPiConfig(opts = {}) {
33649
33970
  return a.scope === "user" ? -1 : 1;
33650
33971
  });
33651
33972
  const userRaw = mergeFiles.find((f) => f.scope === "user")?.config ?? {};
33652
- const projectLoaded = mergeFiles.find((f) => f.scope === "project");
33973
+ const projectLayer = mergeFiles.find((f) => f.scope === "project");
33653
33974
  let projectRaw = {};
33654
33975
  for (const loaded of mergeFiles) {
33655
33976
  const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
@@ -33666,7 +33987,7 @@ function loadPiConfig(opts = {}) {
33666
33987
  const trustedProfiledRaw = mergeRawConfigs(profileResolution.userBase, profileResolution.overlay);
33667
33988
  let rawConfig = trustedProfiledRaw;
33668
33989
  const trustedBaseConfig = parsePiConfig(trustedProfiledRaw).config;
33669
- if (projectLoaded) {
33990
+ if (projectLayer) {
33670
33991
  rawConfig = mergeRawConfigs(rawConfig, profileResolution.projectBase);
33671
33992
  for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, profileResolution.userBase)) {
33672
33993
  warnings.push(`[project config] ${warning}`);
@@ -33679,20 +34000,47 @@ function loadPiConfig(opts = {}) {
33679
34000
  warnings.push(`[project config] ${warning}`);
33680
34001
  }
33681
34002
  }
33682
- const parsed = parsePiConfig(rawConfig);
34003
+ const recoveredTopLevelKeys = [];
34004
+ const cacheTtlConfigured = Object.hasOwn(rawConfig, "cache_ttl");
34005
+ const parsed = parsePiConfig(rawConfig, recoveredTopLevelKeys);
33683
34006
  if (profileResolution.activeProfile)
33684
34007
  parsed.config.profile = profileResolution.activeProfile;
33685
34008
  setOutputReserveConfig(parsed.config.output_reserve);
33686
34009
  setWindowOverlayPath(parsed.config.models?.window_overlay_path);
33687
34010
  warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
34011
+ const substitutionFailures = loadedFiles.flatMap(bindSubstitutionFailures2);
34012
+ const userLoaded = loadedFiles.find((loaded) => loaded.scope === "user");
34013
+ const projectLoaded = loadedFiles.find((loaded) => loaded.scope === "project");
34014
+ const configParseFailures = loadedFiles.flatMap((loaded) => loaded.parseFailures);
34015
+ const warningDetails = [
34016
+ ...loadedFiles.flatMap((loaded) => loaded.warningDetails),
34017
+ ...parsed.warnings.map((message) => ({
34018
+ warningClass: CONFIG_WARNING_CLASS.INVALID_LEAF,
34019
+ message
34020
+ }))
34021
+ ];
34022
+ const sources = {
34023
+ userConfig: userLoaded?.loadOutcome ?? (legacyUserUnmigrated ? "legacy-config-unmigrated" : "ok"),
34024
+ projectConfig: projectLoaded?.loadOutcome ?? (legacyProjectUnmigrated ? "legacy-config-unmigrated" : "ok")
34025
+ };
33688
34026
  return {
33689
34027
  config: parsed.config,
33690
34028
  registrationPromptSurface: trustedBaseConfig.prompt_surface,
33691
34029
  warnings,
33692
- loadedFromPaths: loadedFiles.map((loaded) => loaded.path)
34030
+ loadedFromPaths: loadedFiles.map((loaded) => loaded.path),
34031
+ loadOutcome: combinedOutcome2({
34032
+ sources,
34033
+ substitutionFailures,
34034
+ recoveredTopLevelKeys
34035
+ }),
34036
+ sources,
34037
+ substitutionFailures,
34038
+ recoveredTopLevelKeys,
34039
+ configParseFailures,
34040
+ warningDetails,
34041
+ cacheTtlConfigured
33693
34042
  };
33694
34043
  }
33695
- var import_comment_json7;
33696
34044
  var init_config2 = __esm(() => {
33697
34045
  init_migrate_config_location();
33698
34046
  init_agent_disable();
@@ -33702,10 +34050,10 @@ var init_config2 = __esm(() => {
33702
34050
  init_raw_loader();
33703
34051
  init_magic_context();
33704
34052
  init_variable();
34053
+ init_config_diagnostics();
33705
34054
  init_jsonc_parser();
33706
34055
  init_models_dev_cache();
33707
34056
  init_window_geometry();
33708
- import_comment_json7 = __toESM(require_src3(), 1);
33709
34057
  });
33710
34058
 
33711
34059
  // src/lib/database-repair-guidance.ts
@@ -33799,6 +34147,243 @@ function formatGithubIssueFallback(submission, fallbackPath) {
33799
34147
  var MAX_GITHUB_ISSUE_BODY_CHARS = 65536;
33800
34148
  var init_github_issue = () => {};
33801
34149
 
34150
+ // src/lib/log-lines.ts
34151
+ import { existsSync as existsSync24, readFileSync as readFileSync14, statSync as statSync11 } from "node:fs";
34152
+ import { tmpdir as tmpdir2 } from "node:os";
34153
+ import { join as join21 } from "node:path";
34154
+ function tokenize(input, limit) {
34155
+ const tokens = [];
34156
+ let index = 0;
34157
+ while (index < input.length && tokens.length < limit) {
34158
+ while (input[index] === " ")
34159
+ index += 1;
34160
+ if (index >= input.length)
34161
+ break;
34162
+ const start = index;
34163
+ let quoted = false;
34164
+ let escaped = false;
34165
+ while (index < input.length) {
34166
+ const char = input[index];
34167
+ if (escaped) {
34168
+ escaped = false;
34169
+ } else if (quoted && char === "\\") {
34170
+ escaped = true;
34171
+ } else if (char === '"') {
34172
+ quoted = !quoted;
34173
+ } else if (!quoted && char === " ") {
34174
+ break;
34175
+ }
34176
+ index += 1;
34177
+ }
34178
+ if (quoted || escaped)
34179
+ return null;
34180
+ tokens.push({ raw: input.slice(start, index), start });
34181
+ }
34182
+ return tokens;
34183
+ }
34184
+ function decodeEscapes(value) {
34185
+ let decoded = "";
34186
+ for (let index = 0;index < value.length; index += 1) {
34187
+ const char = value[index];
34188
+ if (char !== "\\") {
34189
+ decoded += char;
34190
+ continue;
34191
+ }
34192
+ const next = value[index + 1];
34193
+ if (next === undefined)
34194
+ return null;
34195
+ if (next === "n")
34196
+ decoded += `
34197
+ `;
34198
+ else if (next === '"')
34199
+ decoded += '"';
34200
+ else if (next === "\\")
34201
+ decoded += "\\";
34202
+ else
34203
+ return null;
34204
+ index += 1;
34205
+ }
34206
+ return decoded;
34207
+ }
34208
+ function parseField2(token) {
34209
+ const equals = token.indexOf("=");
34210
+ if (equals <= 0)
34211
+ return null;
34212
+ const key = token.slice(0, equals);
34213
+ if (!FIELD_NAME.test(key))
34214
+ return null;
34215
+ const rawValue = token.slice(equals + 1);
34216
+ if (rawValue.startsWith('"')) {
34217
+ if (rawValue.length < 2 || !rawValue.endsWith('"'))
34218
+ return null;
34219
+ const value = decodeEscapes(rawValue.slice(1, -1));
34220
+ return value === null ? null : [key, value];
34221
+ }
34222
+ if (rawValue.length === 0 || rawValue.includes('"'))
34223
+ return null;
34224
+ return [key, rawValue];
34225
+ }
34226
+ function trailingToken(input, end) {
34227
+ let index = end;
34228
+ let quoted = false;
34229
+ while (index > 0) {
34230
+ const char = input[index - 1];
34231
+ if (char === '"') {
34232
+ let slashStart = index - 1;
34233
+ while (input[slashStart - 1] === "\\")
34234
+ slashStart -= 1;
34235
+ if ((index - 1 - slashStart) % 2 === 0)
34236
+ quoted = !quoted;
34237
+ index = slashStart;
34238
+ } else if (char === " " && !quoted) {
34239
+ break;
34240
+ } else {
34241
+ index -= 1;
34242
+ }
34243
+ }
34244
+ return quoted ? null : { raw: input.slice(index, end), start: index };
34245
+ }
34246
+ function splitMessageAndFields(input, decodeMessage = true) {
34247
+ let messageEnd = input.trimEnd().length;
34248
+ const fields = [];
34249
+ while (messageEnd > 0) {
34250
+ const token = trailingToken(input, messageEnd);
34251
+ const field = token && parseField2(token.raw);
34252
+ if (!token || !field || token.start === 0)
34253
+ break;
34254
+ fields.push(field);
34255
+ messageEnd = token.start;
34256
+ while (messageEnd > 0 && input[messageEnd - 1] === " ")
34257
+ messageEnd -= 1;
34258
+ }
34259
+ const rawMessage = fields.length > 0 ? input.slice(0, messageEnd) : input;
34260
+ const message = decodeMessage ? decodeEscapes(rawMessage) ?? rawMessage : rawMessage;
34261
+ const kv = {};
34262
+ for (const [key, value] of fields.reverse())
34263
+ kv[key] = value;
34264
+ return { message, kv };
34265
+ }
34266
+ function rawSessionId(value) {
34267
+ if (!value || value === "global")
34268
+ return null;
34269
+ const colon = value.indexOf(":");
34270
+ if (colon <= 0 || colon === value.length - 1)
34271
+ return null;
34272
+ return value.slice(colon + 1);
34273
+ }
34274
+ function parseLogLine(line) {
34275
+ const fleet = FLEET_PREFIX.exec(line);
34276
+ if (fleet) {
34277
+ const ts = fleet[1];
34278
+ if (Number.isNaN(Date.parse(ts)) || new Date(ts).toISOString() !== ts)
34279
+ return null;
34280
+ const level = fleet[2].trim();
34281
+ let remaining = fleet[3].trimStart();
34282
+ let session = null;
34283
+ const tags = [];
34284
+ if (remaining.startsWith("session=")) {
34285
+ const token = tokenize(remaining, 1)?.[0];
34286
+ if (!token || token.raw.includes("\x1B"))
34287
+ return null;
34288
+ const sessionField = parseField2(token.raw);
34289
+ if (!sessionField)
34290
+ return null;
34291
+ session = rawSessionId(sessionField[1]);
34292
+ if (!session)
34293
+ return null;
34294
+ remaining = remaining.slice(token.raw.length).trimStart();
34295
+ }
34296
+ while (remaining.startsWith("tag=")) {
34297
+ const token = tokenize(remaining, 1)?.[0];
34298
+ if (!token || token.raw.includes("\x1B"))
34299
+ return null;
34300
+ const tagField = parseField2(token.raw);
34301
+ if (!tagField?.[1])
34302
+ return null;
34303
+ tags.push(tagField[1]);
34304
+ remaining = remaining.slice(token.raw.length).trimStart();
34305
+ }
34306
+ const body = splitMessageAndFields(remaining);
34307
+ return { ts, level, session, tags, ...body, grammar: "fleet" };
34308
+ }
34309
+ const legacy = LEGACY_LINE.exec(line);
34310
+ if (!legacy || legacy[2].includes("\x1B") || Number.isNaN(Date.parse(legacy[1])))
34311
+ return null;
34312
+ const body = splitMessageAndFields(legacy[3], false);
34313
+ const legacySession = legacy[2].trim();
34314
+ return {
34315
+ ts: legacy[1],
34316
+ level: null,
34317
+ session: legacySession && legacySession !== "global" ? legacySession : null,
34318
+ tags: [],
34319
+ ...body,
34320
+ grammar: "legacy"
34321
+ };
34322
+ }
34323
+ function getMagicContextLogPaths(harness, options = {}) {
34324
+ const override = options.override === undefined ? process.env.MAGIC_CONTEXT_LOG_PATH?.trim() : options.override?.trim();
34325
+ const storageLogs = join21(options.storageDir ?? getMagicContextStorageDir(), "logs");
34326
+ return [
34327
+ ...override ? [override] : [],
34328
+ join21(options.tempDir ?? tmpdir2(), harness, "magic-context", "magic-context.log"),
34329
+ join21(storageLogs, `magic-context.${harness}.log`),
34330
+ join21(storageLogs, "magic-context.log")
34331
+ ].filter((path, index, paths) => paths.indexOf(path) === index);
34332
+ }
34333
+ function inspectLogFile(path) {
34334
+ if (!existsSync24(path)) {
34335
+ return { path, exists: false, sizeKb: 0, lineCount: 0, grammar: "unknown" };
34336
+ }
34337
+ try {
34338
+ const content = readFileSync14(path, "utf8");
34339
+ const lines = content.split(/\r?\n/).filter((line) => line.length > 0);
34340
+ const grammars = new Set(lines.flatMap((line) => {
34341
+ const parsed = parseLogLine(line);
34342
+ return parsed ? [parsed.grammar] : [];
34343
+ }));
34344
+ const grammar = grammars.size > 1 ? "mixed" : grammars.values().next().value ?? "unknown";
34345
+ return {
34346
+ path,
34347
+ exists: true,
34348
+ sizeKb: Math.round(statSync11(path).size / 1024),
34349
+ lineCount: lines.length,
34350
+ grammar
34351
+ };
34352
+ } catch {
34353
+ return { path, exists: true, sizeKb: 0, lineCount: 0, grammar: "unknown" };
34354
+ }
34355
+ }
34356
+ function inspectMagicContextLogs(harness, options = {}) {
34357
+ return getMagicContextLogPaths(harness, options).map(inspectLogFile);
34358
+ }
34359
+ function readLogLines(files) {
34360
+ const lines = files.flatMap((file, fileIndex) => {
34361
+ if (!file.exists)
34362
+ return [];
34363
+ try {
34364
+ let precedingTimestamp = "";
34365
+ return readFileSync14(file.path, "utf8").split(/\r?\n/).filter((line) => line.length > 0).map((line, lineIndex) => {
34366
+ precedingTimestamp = parseLogLine(line)?.ts ?? precedingTimestamp;
34367
+ return { line, timestamp: precedingTimestamp, fileIndex, lineIndex };
34368
+ });
34369
+ } catch {
34370
+ return [];
34371
+ }
34372
+ });
34373
+ lines.sort((left, right) => left.timestamp.localeCompare(right.timestamp) || left.fileIndex - right.fileIndex || left.lineIndex - right.lineIndex);
34374
+ return lines.map(({ line }) => line);
34375
+ }
34376
+ function formatLogFileInspection(file) {
34377
+ return `${file.path} (grammar=${file.grammar}, lines=${file.lineCount}, ${file.sizeKb} KB)`;
34378
+ }
34379
+ var FLEET_PREFIX, LEGACY_LINE, FIELD_NAME;
34380
+ var init_log_lines = __esm(() => {
34381
+ init_data_path();
34382
+ FLEET_PREFIX = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z) (TRACE|DEBUG|INFO |WARN |ERROR) magic-context (.*)$/;
34383
+ LEGACY_LINE = /^\[([^\]]+)\] \[magic-context\]\[([^\]]*)\]\s+(.*)$/;
34384
+ FIELD_NAME = /^[A-Za-z_][A-Za-z0-9_.-]*$/;
34385
+ });
34386
+
33802
34387
  // src/lib/redaction.ts
33803
34388
  function sanitizeDiagnosticEndpoint(value) {
33804
34389
  const trimmed = value.trim();
@@ -33823,9 +34408,9 @@ var init_redaction2 = __esm(() => {
33823
34408
 
33824
34409
  // src/commands/doctor-omp.ts
33825
34410
  import { execFileSync as execFileSync5, spawnSync as spawnSync5 } from "node:child_process";
33826
- import { existsSync as existsSync24, mkdirSync as mkdirSync8, readFileSync as readFileSync14 } from "node:fs";
34411
+ import { existsSync as existsSync25, mkdirSync as mkdirSync8, readFileSync as readFileSync15 } from "node:fs";
33827
34412
  import { createRequire as createRequire2 } from "node:module";
33828
- import { dirname as dirname14, join as join21, resolve as resolve7 } from "node:path";
34413
+ import { dirname as dirname14, join as join22, resolve as resolve7 } from "node:path";
33829
34414
  function parseSemver(value) {
33830
34415
  const match = value?.match(/(\d+)\.(\d+)\.(\d+)/);
33831
34416
  return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
@@ -33867,10 +34452,10 @@ function selfVersion() {
33867
34452
  return "unknown";
33868
34453
  }
33869
34454
  function readConfig2(path) {
33870
- if (!existsSync24(path))
34455
+ if (!existsSync25(path))
33871
34456
  return {};
33872
34457
  try {
33873
- const parsed = import_comment_json8.parse(readFileSync14(path, "utf-8"));
34458
+ const parsed = import_comment_json7.parse(readFileSync15(path, "utf-8"));
33874
34459
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? {} : { error: "top level is not an object" };
33875
34460
  } catch (error) {
33876
34461
  return { error: error instanceof Error ? error.message : String(error) };
@@ -33880,7 +34465,7 @@ function pluginDeclaresOmp(path) {
33880
34465
  if (!path)
33881
34466
  return null;
33882
34467
  try {
33883
- const pkg = JSON.parse(readFileSync14(join21(path, "package.json"), "utf-8"));
34468
+ const pkg = JSON.parse(readFileSync15(join22(path, "package.json"), "utf-8"));
33884
34469
  return Array.isArray(pkg.omp?.extensions) || Array.isArray(pkg.pi?.extensions);
33885
34470
  } catch {
33886
34471
  return null;
@@ -33961,7 +34546,7 @@ async function runHealthChecks(options) {
33961
34546
  }
33962
34547
  }
33963
34548
  const userConfigPath = getOmpUserConfigPath();
33964
- if (!existsSync24(userConfigPath)) {
34549
+ if (!existsSync25(userConfigPath)) {
33965
34550
  add(results, "warn", `No Magic Context user config at ${userConfigPath}`);
33966
34551
  repairPlan.writeUserConfig = true;
33967
34552
  } else {
@@ -33978,9 +34563,9 @@ async function runHealthChecks(options) {
33978
34563
  for (const warning of loaded.warnings.slice(0, 5))
33979
34564
  add(results, "warn", warning);
33980
34565
  const storage = getMagicContextStorageResolution();
33981
- const dbPath = join21(storage.path, "context.db");
34566
+ const dbPath = join22(storage.path, "context.db");
33982
34567
  add(results, "info", `Shared storage: ${storage.path} (source: ${storage.source})`);
33983
- if (!existsSync24(dbPath))
34568
+ if (!existsSync25(dbPath))
33984
34569
  add(results, "info", `Shared context DB will be created at ${dbPath}`);
33985
34570
  else {
33986
34571
  let db = null;
@@ -34008,8 +34593,15 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
34008
34593
  for (const source of getOmpNonGlobalConfigSources(options.cwd)) {
34009
34594
  add(results, "info", `OMP non-global config: ${source}`);
34010
34595
  }
34011
- const logPath = getMagicContextLogPath2("pi");
34012
- add(results, "info", `Pi-compatible runtime log: ${logPath}${existsSync24(logPath) ? "" : " (not created yet)"}`);
34596
+ const logFiles = options.deps.inspectMagicContextLogs("omp");
34597
+ const existingLogFiles = logFiles.filter((file) => file.exists);
34598
+ if (existingLogFiles.length === 0) {
34599
+ add(results, "info", `No OMP runtime log yet; checked: ${logFiles.map((file) => file.path).join(", ")}`);
34600
+ } else {
34601
+ for (const file of existingLogFiles) {
34602
+ add(results, "info", `OMP runtime log read: ${formatLogFileInspection(file)}`);
34603
+ }
34604
+ }
34013
34605
  if (!options.quiet)
34014
34606
  for (const result of results)
34015
34607
  printResult(options.prompts, result);
@@ -34027,12 +34619,12 @@ function writeDefaultConfig(path) {
34027
34619
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
34028
34620
  ...MagicContextConfigSchema.parse({})
34029
34621
  };
34030
- writeFileAtomic(path, `${import_comment_json8.stringify(config, null, 2)}
34622
+ writeFileAtomic(path, `${import_comment_json7.stringify(config, null, 2)}
34031
34623
  `);
34032
34624
  }
34033
34625
  async function repair(plan, deps, prompts, cwd) {
34034
34626
  let fixed = 0;
34035
- if (plan.writeUserConfig && !existsSync24(getOmpUserConfigPath())) {
34627
+ if (plan.writeUserConfig && !existsSync25(getOmpUserConfigPath())) {
34036
34628
  writeDefaultConfig(getOmpUserConfigPath());
34037
34629
  prompts.log.success(`Wrote default Magic Context config to ${getOmpUserConfigPath()}`);
34038
34630
  fixed += 1;
@@ -34117,7 +34709,7 @@ async function runIssueFlow(options) {
34117
34709
  ...report.results.map((result) => `- ${result.status.toUpperCase()}: ${sanitizeDiagnosticText(result.message)}`)
34118
34710
  ].join(`
34119
34711
  `);
34120
- const path = join21(options.cwd, `magic-context-omp-issue-${timestamp2(options.deps.now())}.md`);
34712
+ const path = join22(options.cwd, `magic-context-omp-issue-${timestamp2(options.deps.now())}.md`);
34121
34713
  writeFileAtomic(path, `${body}
34122
34714
  `);
34123
34715
  options.prompts.log.success(`Sanitized report written to ${path}`);
@@ -34161,7 +34753,7 @@ async function runDoctor(options = {}) {
34161
34753
  prompts.log.message(`Summary: PASS ${second.pass} / WARN ${second.warn} / FAIL ${second.fail}`);
34162
34754
  return second.fail === 0 ? 0 : 1;
34163
34755
  }
34164
- var import_comment_json8, MIN_OMP_VERSION = "17.1.7", DEFAULT_DEPS4;
34756
+ var import_comment_json7, MIN_OMP_VERSION = "17.1.7", DEFAULT_DEPS4;
34165
34757
  var init_doctor_omp = __esm(async () => {
34166
34758
  init_magic_context();
34167
34759
  init_data_path();
@@ -34170,12 +34762,13 @@ var init_doctor_omp = __esm(async () => {
34170
34762
  init_atomic_write();
34171
34763
  init_config_location_migration();
34172
34764
  init_github_issue();
34765
+ init_log_lines();
34173
34766
  init_omp_helpers();
34174
34767
  init_paths();
34175
34768
  init_prompts();
34176
34769
  init_redaction2();
34177
34770
  await init_database_access();
34178
- import_comment_json8 = __toESM(require_src3(), 1);
34771
+ import_comment_json7 = __toESM(require_src3(), 1);
34179
34772
  DEFAULT_DEPS4 = {
34180
34773
  prompts: promptIO,
34181
34774
  detectOmpBinary,
@@ -34185,6 +34778,7 @@ var init_doctor_omp = __esm(async () => {
34185
34778
  runOmpCommand,
34186
34779
  openExistingContextDatabase,
34187
34780
  now: () => new Date,
34781
+ inspectMagicContextLogs,
34188
34782
  execFileSync: execFileSync5,
34189
34783
  spawnSync: spawnSync5
34190
34784
  };
@@ -34304,14 +34898,14 @@ var DEFAULT_TIMEOUT_MS = 1e4, MAX_PREVIEW_CHARS = 240;
34304
34898
  // ../plugin/src/shared/tui-config.ts
34305
34899
  import {
34306
34900
  chmodSync as chmodSync5,
34307
- existsSync as existsSync25,
34901
+ existsSync as existsSync26,
34308
34902
  mkdirSync as mkdirSync9,
34309
- readFileSync as readFileSync15,
34903
+ readFileSync as readFileSync16,
34310
34904
  renameSync as renameSync6,
34311
- statSync as statSync11,
34905
+ statSync as statSync12,
34312
34906
  writeFileSync as writeFileSync6
34313
34907
  } from "node:fs";
34314
- import { dirname as dirname15, join as join22 } from "node:path";
34908
+ import { dirname as dirname15, join as join23 } from "node:path";
34315
34909
  function pluginEntryId(entry) {
34316
34910
  if (typeof entry === "string")
34317
34911
  return entry;
@@ -34339,24 +34933,24 @@ function isMagicContextPluginEntry(entry) {
34339
34933
  return isLocalMagicContextDevEntry(entry);
34340
34934
  }
34341
34935
  function writeTuiConfigAtomic(configPath, config) {
34342
- const body = `${import_comment_json9.stringify(config, null, 2)}
34936
+ const body = `${import_comment_json8.stringify(config, null, 2)}
34343
34937
  `;
34344
34938
  const tmpPath = `${configPath}.tmp`;
34345
34939
  writeFileSync6(tmpPath, body);
34346
34940
  try {
34347
- if (statSync11(configPath, { throwIfNoEntry: false })?.isFile()) {
34348
- chmodSync5(tmpPath, statSync11(configPath).mode & 511);
34941
+ if (statSync12(configPath, { throwIfNoEntry: false })?.isFile()) {
34942
+ chmodSync5(tmpPath, statSync12(configPath).mode & 511);
34349
34943
  }
34350
34944
  } catch {}
34351
34945
  renameSync6(tmpPath, configPath);
34352
34946
  }
34353
34947
  function resolveTuiConfigPath(configDirOverride) {
34354
34948
  const configDir = configDirOverride ?? getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
34355
- const jsoncPath = join22(configDir, "tui.jsonc");
34356
- const jsonPath = join22(configDir, "tui.json");
34357
- if (existsSync25(jsoncPath))
34949
+ const jsoncPath = join23(configDir, "tui.jsonc");
34950
+ const jsonPath = join23(configDir, "tui.json");
34951
+ if (existsSync26(jsoncPath))
34358
34952
  return jsoncPath;
34359
- if (existsSync25(jsonPath))
34953
+ if (existsSync26(jsonPath))
34360
34954
  return jsonPath;
34361
34955
  return jsoncPath;
34362
34956
  }
@@ -34364,9 +34958,9 @@ function ensureTuiPluginEntry(options = {}) {
34364
34958
  try {
34365
34959
  const configPath = resolveTuiConfigPath(options.configDir);
34366
34960
  let config = {};
34367
- if (existsSync25(configPath)) {
34368
- const raw = readFileSync15(configPath, "utf-8");
34369
- config = import_comment_json9.parse(raw) ?? {};
34961
+ if (existsSync26(configPath)) {
34962
+ const raw = readFileSync16(configPath, "utf-8");
34963
+ config = import_comment_json8.parse(raw) ?? {};
34370
34964
  }
34371
34965
  const plugins = Array.isArray(config.plugin) ? [...config.plugin] : [];
34372
34966
  const existingIdx = plugins.findIndex(isMagicContextPluginEntry);
@@ -34408,19 +35002,19 @@ function ensureTuiPluginEntry(options = {}) {
34408
35002
  return false;
34409
35003
  }
34410
35004
  }
34411
- var import_comment_json9, PLUGIN_NAME2 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY;
35005
+ var import_comment_json8, PLUGIN_NAME2 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY;
34412
35006
  var init_tui_config = __esm(() => {
34413
35007
  init_logger();
34414
35008
  init_opencode_config_dir();
34415
- import_comment_json9 = __toESM(require_src3(), 1);
35009
+ import_comment_json8 = __toESM(require_src3(), 1);
34416
35010
  PLUGIN_ENTRY = `${PLUGIN_NAME2}@latest`;
34417
35011
  });
34418
35012
 
34419
35013
  // src/lib/diagnostics-opencode.ts
34420
- import { existsSync as existsSync26, readdirSync as readdirSync3, readFileSync as readFileSync16, statSync as statSync12 } from "node:fs";
35014
+ import { existsSync as existsSync27, readdirSync as readdirSync3, readFileSync as readFileSync17, statSync as statSync13 } from "node:fs";
34421
35015
  import { createRequire as createRequire3 } from "node:module";
34422
35016
  import { homedir as homedir15 } from "node:os";
34423
- import { join as join23 } from "node:path";
35017
+ import { join as join24 } from "node:path";
34424
35018
  function getSelfVersion() {
34425
35019
  const require2 = createRequire3(import.meta.url);
34426
35020
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -34438,8 +35032,8 @@ function getPluginCacheInfo() {
34438
35032
  let cached;
34439
35033
  for (const installedPkgPath of getOpenCodePluginPackageJsonPaths()) {
34440
35034
  try {
34441
- if (existsSync26(installedPkgPath)) {
34442
- const pkg = JSON.parse(readFileSync16(installedPkgPath, "utf-8"));
35035
+ if (existsSync27(installedPkgPath)) {
35036
+ const pkg = JSON.parse(readFileSync17(installedPkgPath, "utf-8"));
34443
35037
  cached = typeof pkg.version === "string" ? pkg.version : undefined;
34444
35038
  if (cached)
34445
35039
  break;
@@ -34455,7 +35049,7 @@ function getStorageResolution() {
34455
35049
  }
34456
35050
  function fileSize(path) {
34457
35051
  try {
34458
- return existsSync26(path) ? statSync12(path).size : 0;
35052
+ return existsSync27(path) ? statSync13(path).size : 0;
34459
35053
  } catch {
34460
35054
  return 0;
34461
35055
  }
@@ -34467,11 +35061,11 @@ function sanitizeValue(value) {
34467
35061
  return sanitizeConfigValue(value);
34468
35062
  }
34469
35063
  function readConfig3(path) {
34470
- if (!existsSync26(path))
35064
+ if (!existsSync27(path))
34471
35065
  return { value: null };
34472
35066
  try {
34473
- const raw = readFileSync16(path, "utf-8");
34474
- const value = import_comment_json10.parse(raw);
35067
+ const raw = readFileSync17(path, "utf-8");
35068
+ const value = import_comment_json9.parse(raw);
34475
35069
  return { value };
34476
35070
  } catch (error) {
34477
35071
  return { value: null, error: error instanceof Error ? error.message : String(error) };
@@ -34495,7 +35089,7 @@ function configHasPluginEntry(config) {
34495
35089
  }
34496
35090
  function parseHistorianDumpMeta(path) {
34497
35091
  try {
34498
- const xml = readFileSync16(path, "utf-8");
35092
+ const xml = readFileSync17(path, "utf-8");
34499
35093
  const parsed = parseCompartmentOutput(xml);
34500
35094
  const factCountByCategory = {};
34501
35095
  for (const fact of parsed.facts) {
@@ -34528,11 +35122,11 @@ function parseHistorianDumpMeta(path) {
34528
35122
  }
34529
35123
  }
34530
35124
  function listDumpsInDir(dir, limit) {
34531
- if (!existsSync26(dir))
35125
+ if (!existsSync27(dir))
34532
35126
  return { count: 0, recent: [] };
34533
35127
  try {
34534
35128
  const entries = readdirSync3(dir).filter((name) => name.endsWith(".xml")).map((name) => {
34535
- const stat = statSync12(join23(dir, name));
35129
+ const stat = statSync13(join24(dir, name));
34536
35130
  return {
34537
35131
  name,
34538
35132
  mtime: stat.mtimeMs,
@@ -34541,7 +35135,7 @@ function listDumpsInDir(dir, limit) {
34541
35135
  }).sort((a, b) => b.mtime - a.mtime);
34542
35136
  const now = Date.now();
34543
35137
  const recent = entries.slice(0, limit).map((entry) => {
34544
- const meta = parseHistorianDumpMeta(join23(dir, entry.name));
35138
+ const meta = parseHistorianDumpMeta(join24(dir, entry.name));
34545
35139
  const summary = {
34546
35140
  name: entry.name,
34547
35141
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -34652,9 +35246,9 @@ function collectRecentSessionsFromDatabase(database) {
34652
35246
  });
34653
35247
  }
34654
35248
  async function collectRecentSessions() {
34655
- const dataHome = process.env.XDG_DATA_HOME || join23(process.env.HOME || homedir15(), ".local", "share");
34656
- const opencodeDbPath = join23(dataHome, "opencode", "opencode.db");
34657
- if (!existsSync26(opencodeDbPath))
35249
+ const dataHome = process.env.XDG_DATA_HOME || join24(process.env.HOME || homedir15(), ".local", "share");
35250
+ const opencodeDbPath = join24(dataHome, "opencode", "opencode.db");
35251
+ if (!existsSync27(opencodeDbPath))
34658
35252
  return [];
34659
35253
  if (typeof globalThis.Bun === "undefined") {
34660
35254
  return [];
@@ -34679,8 +35273,8 @@ async function collectRecentSessions() {
34679
35273
  }
34680
35274
  }
34681
35275
  async function collectHistorianFailures(storageDirPath) {
34682
- const contextDbPath = join23(storageDirPath, "context.db");
34683
- if (!existsSync26(contextDbPath))
35276
+ const contextDbPath = join24(storageDirPath, "context.db");
35277
+ if (!existsSync27(contextDbPath))
34684
35278
  return [];
34685
35279
  if (typeof globalThis.Bun === "undefined") {
34686
35280
  return [];
@@ -34713,8 +35307,8 @@ async function collectHistorianFailures(storageDirPath) {
34713
35307
  }
34714
35308
  }
34715
35309
  async function collectHistorianRuns(storageDirPath) {
34716
- const contextDbPath = join23(storageDirPath, "context.db");
34717
- if (!existsSync26(contextDbPath))
35310
+ const contextDbPath = join24(storageDirPath, "context.db");
35311
+ if (!existsSync27(contextDbPath))
34718
35312
  return [];
34719
35313
  if (typeof globalThis.Bun === "undefined")
34720
35314
  return [];
@@ -34784,9 +35378,9 @@ async function collectDiagnostics() {
34784
35378
  const magicContextConfig = readConfig3(configPaths.magicContextConfig);
34785
35379
  const storageResolution = getStorageResolution();
34786
35380
  const storageDirPath = storageResolution.path;
34787
- const contextDbPath = join23(storageDirPath, "context.db");
34788
- const logPath = getMagicContextLogPath2("opencode");
34789
- const logFileSize = existsSync26(logPath) ? statSync12(logPath).size : 0;
35381
+ const contextDbPath = join24(storageDirPath, "context.db");
35382
+ const logFiles = inspectMagicContextLogs("opencode");
35383
+ const primaryLog = logFiles.find((file) => file.exists) ?? logFiles[0];
34790
35384
  let compactionEnabled = false;
34791
35385
  try {
34792
35386
  compactionEnabled = isCompactionEnabled(loadPluginConfig(process.cwd()));
@@ -34814,7 +35408,7 @@ async function collectDiagnostics() {
34814
35408
  opencodeConfigHasPlugin: configHasPluginEntry(opencodeConfig.value),
34815
35409
  tuiConfigHasPlugin: configHasPluginEntry(tuiConfig.value),
34816
35410
  magicContextConfig: {
34817
- exists: existsSync26(configPaths.magicContextConfig),
35411
+ exists: existsSync27(configPaths.magicContextConfig),
34818
35412
  ...magicContextConfig.error ? { parseError: magicContextConfig.error } : {},
34819
35413
  flags: sanitizeValue(magicContextConfig.value ?? {}) ?? {}
34820
35414
  },
@@ -34822,7 +35416,7 @@ async function collectDiagnostics() {
34822
35416
  storageDir: {
34823
35417
  path: storageDirPath,
34824
35418
  source: storageResolution.source,
34825
- exists: existsSync26(storageDirPath),
35419
+ exists: existsSync27(storageDirPath),
34826
35420
  contextDbSizeBytes: fileSize(contextDbPath)
34827
35421
  },
34828
35422
  conflicts: {
@@ -34832,10 +35426,11 @@ async function collectDiagnostics() {
34832
35426
  nativeCompaction: conflictResult.nativeCompaction
34833
35427
  },
34834
35428
  logFile: {
34835
- path: logPath,
34836
- exists: existsSync26(logPath),
34837
- sizeKb: Math.round(logFileSize / 1024)
35429
+ path: primaryLog.path,
35430
+ exists: primaryLog.exists,
35431
+ sizeKb: primaryLog.sizeKb
34838
35432
  },
35433
+ logFiles,
34839
35434
  recentSessions,
34840
35435
  historianDumps: collectHistorianDumps(recentSessions),
34841
35436
  historianFailures: await collectHistorianFailures(storageDirPath),
@@ -34964,26 +35559,25 @@ function renderDiagnosticsMarkdown(report) {
34964
35559
  ].join(`
34965
35560
  `),
34966
35561
  "",
34967
- "### Log file",
34968
- `- Path: ${sanitizeString(report.logFile.path)}`,
34969
- `- Exists: ${report.logFile.exists}`,
34970
- `- Size: ${report.logFile.sizeKb} KB`
35562
+ "### Log files",
35563
+ ...(report.logFiles ?? [report.logFile]).map((file) => `- ${sanitizeString(file.path)}: exists=${file.exists}, grammar=${"grammar" in file ? file.grammar : "unknown"}, lines=${"lineCount" in file ? file.lineCount : 0}, size=${file.sizeKb} KB`)
34971
35564
  ].join(`
34972
35565
  `);
34973
35566
  }
34974
- var import_comment_json10, RECENT_SESSION_GROUP_LIMIT = 5, CHILD_SESSIONS_PER_PARENT_LIMIT = 3;
35567
+ var import_comment_json9, RECENT_SESSION_GROUP_LIMIT = 5, CHILD_SESSIONS_PER_PARENT_LIMIT = 3;
34975
35568
  var init_diagnostics_opencode = __esm(() => {
34976
35569
  init_config();
34977
35570
  init_agent_disable();
34978
35571
  init_compartment_parser();
34979
35572
  init_conflict_detector();
34980
35573
  init_data_path();
35574
+ init_log_lines();
34981
35575
  init_opencode_detect();
34982
35576
  init_opencode_helpers();
34983
35577
  init_opencode_plugin_cache();
34984
35578
  init_paths();
34985
35579
  init_redaction2();
34986
- import_comment_json10 = __toESM(require_src3(), 1);
35580
+ import_comment_json9 = __toESM(require_src3(), 1);
34987
35581
  });
34988
35582
  // ../plugin/src/features/magic-context/memory/embedding-synapse.ts
34989
35583
  var SYNAPSE_CERTIFICATION_REFUSAL_REASONS, factoryClients;
@@ -35049,9 +35643,9 @@ var init_embedding_local = __esm(() => {
35049
35643
 
35050
35644
  // src/lib/embedding-runtime.ts
35051
35645
  import { spawnSync as spawnSync6 } from "node:child_process";
35052
- import { existsSync as existsSync27, readFileSync as readFileSync17 } from "node:fs";
35646
+ import { existsSync as existsSync28, readFileSync as readFileSync18 } from "node:fs";
35053
35647
  import { createRequire as createRequire4 } from "node:module";
35054
- import { dirname as dirname16, join as join24, sep } from "node:path";
35648
+ import { dirname as dirname16, join as join25, sep } from "node:path";
35055
35649
  function describeError(error) {
35056
35650
  const message = error instanceof Error ? error.message : String(error ?? "unknown error");
35057
35651
  const code = error?.code;
@@ -35192,11 +35786,11 @@ function expectedBinaryRelPath(platform, arch) {
35192
35786
  const supportedArch = arch === "x64" || arch === "arm64";
35193
35787
  if (!supportedPlatform || !supportedArch)
35194
35788
  return null;
35195
- return join24("bin", "napi-v6", platform, arch, "onnxruntime_binding.node");
35789
+ return join25("bin", "napi-v6", platform, arch, "onnxruntime_binding.node");
35196
35790
  }
35197
35791
  function onnxRuntimeNodeVersion(packageDir) {
35198
35792
  try {
35199
- const parsed = JSON.parse(readFileSync17(join24(packageDir, "package.json"), "utf8"));
35793
+ const parsed = JSON.parse(readFileSync18(join25(packageDir, "package.json"), "utf8"));
35200
35794
  return typeof parsed.version === "string" ? parsed.version : undefined;
35201
35795
  } catch {
35202
35796
  return;
@@ -35245,7 +35839,7 @@ function formatLocalEmbeddingRuntimeWasmSelected(status) {
35245
35839
  function requireNodeWasmBundle(probe, candidates) {
35246
35840
  if (probe.state === "failed")
35247
35841
  return probe;
35248
- const bundlePath = candidates.find((candidate) => existsSync27(candidate));
35842
+ const bundlePath = candidates.find((candidate) => existsSync28(candidate));
35249
35843
  return bundlePath ? probe : {
35250
35844
  state: "failed",
35251
35845
  reason: `functional Node WASM Transformers bundle is missing (checked ${candidates.join(", ")})`
@@ -35253,13 +35847,13 @@ function requireNodeWasmBundle(probe, candidates) {
35253
35847
  }
35254
35848
  function nodeWasmBundleCandidates(installRoot) {
35255
35849
  return [
35256
- join24(installRoot, "dist", "transformers-node-wasm.js"),
35257
- join24(installRoot, "node_modules", "@cortexkit", "opencode-magic-context", "dist", "transformers-node-wasm.js"),
35258
- join24(installRoot, "node_modules", "@cortexkit", "pi-magic-context", "dist", "transformers-node-wasm.js")
35850
+ join25(installRoot, "dist", "transformers-node-wasm.js"),
35851
+ join25(installRoot, "node_modules", "@cortexkit", "opencode-magic-context", "dist", "transformers-node-wasm.js"),
35852
+ join25(installRoot, "node_modules", "@cortexkit", "pi-magic-context", "dist", "transformers-node-wasm.js")
35259
35853
  ];
35260
35854
  }
35261
35855
  function probeWasmRuntimeAt(installRoot) {
35262
- const requireFn = createRequire4(join24(installRoot, "package.json"));
35856
+ const requireFn = createRequire4(join25(installRoot, "package.json"));
35263
35857
  return requireNodeWasmBundle(probeWasmRuntimeFromRequire(requireFn), nodeWasmBundleCandidates(installRoot));
35264
35858
  }
35265
35859
  function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
@@ -35268,9 +35862,9 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
35268
35862
  const wasm = probeWasmRuntimeAt(installRoot);
35269
35863
  return wasm.state === "ok" ? { state: "wasm-selected", wasmPath: wasm.wasmPath } : { state: "wasm-broken", wasmReason: wasm.reason };
35270
35864
  }
35271
- const packageDir = join24(installRoot, "node_modules", "onnxruntime-node");
35865
+ const packageDir = join25(installRoot, "node_modules", "onnxruntime-node");
35272
35866
  let native;
35273
- if (!existsSync27(join24(packageDir, "package.json"))) {
35867
+ if (!existsSync28(join25(packageDir, "package.json"))) {
35274
35868
  native = { state: "package-missing", packageDir };
35275
35869
  } else {
35276
35870
  const rel = expectedBinaryRelPath(platform, arch);
@@ -35280,8 +35874,8 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
35280
35874
  binaryPath: packageDir
35281
35875
  };
35282
35876
  } else {
35283
- const binaryPath = join24(packageDir, rel);
35284
- native = existsSync27(binaryPath) ? probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath } : {
35877
+ const binaryPath = join25(packageDir, rel);
35878
+ native = existsSync28(binaryPath) ? probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath } : {
35285
35879
  state: "binary-missing",
35286
35880
  packageDir,
35287
35881
  expectedBinary: binaryPath,
@@ -35292,7 +35886,7 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
35292
35886
  return withWasmFallback(native, () => probeWasmRuntimeAt(installRoot));
35293
35887
  }
35294
35888
  function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
35295
- const existing = installRoots.filter((root) => existsSync27(root));
35889
+ const existing = installRoots.filter((root) => existsSync28(root));
35296
35890
  if (existing.length === 0) {
35297
35891
  return {
35298
35892
  state: "unknown",
@@ -35322,15 +35916,15 @@ function packageDirFromResolved(resolvedPath, packageName) {
35322
35916
  }
35323
35917
  function probeWasmRuntimeByResolution(pluginDir) {
35324
35918
  try {
35325
- const reqPlugin = createRequire4(join24(pluginDir, "package.json"));
35919
+ const reqPlugin = createRequire4(join25(pluginDir, "package.json"));
35326
35920
  const direct = probeWasmRuntimeFromRequire(reqPlugin);
35327
35921
  let probe = direct;
35328
35922
  if (direct.state === "failed" && direct.reason.startsWith("onnxruntime-web is not resolvable")) {
35329
35923
  const tfResolved = reqPlugin.resolve("@huggingface/transformers");
35330
35924
  const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
35331
- probe = probeWasmRuntimeFromRequire(createRequire4(join24(tfDir, "package.json")));
35925
+ probe = probeWasmRuntimeFromRequire(createRequire4(join25(tfDir, "package.json")));
35332
35926
  }
35333
- return requireNodeWasmBundle(probe, [join24(pluginDir, "dist", "transformers-node-wasm.js")]);
35927
+ return requireNodeWasmBundle(probe, [join25(pluginDir, "dist", "transformers-node-wasm.js")]);
35334
35928
  } catch (error) {
35335
35929
  return {
35336
35930
  state: "failed",
@@ -35339,7 +35933,7 @@ function probeWasmRuntimeByResolution(pluginDir) {
35339
35933
  }
35340
35934
  }
35341
35935
  function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
35342
- if (!existsSync27(join24(pluginDir, "package.json"))) {
35936
+ if (!existsSync28(join25(pluginDir, "package.json"))) {
35343
35937
  return { state: "unknown", reason: "plugin package dir not found" };
35344
35938
  }
35345
35939
  const selectedRuntime = resolveLocalEmbeddingRuntime(runtimePreference, host);
@@ -35350,13 +35944,13 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
35350
35944
  let onnxDir = null;
35351
35945
  let resolveError;
35352
35946
  try {
35353
- const reqPlugin = createRequire4(join24(pluginDir, "package.json"));
35947
+ const reqPlugin = createRequire4(join25(pluginDir, "package.json"));
35354
35948
  try {
35355
35949
  onnxDir = packageDirFromResolved(reqPlugin.resolve("onnxruntime-node"), "onnxruntime-node");
35356
35950
  } catch {
35357
35951
  const tfResolved = reqPlugin.resolve("@huggingface/transformers");
35358
35952
  const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
35359
- const reqTf = createRequire4(join24(tfDir, "package.json"));
35953
+ const reqTf = createRequire4(join25(tfDir, "package.json"));
35360
35954
  onnxDir = packageDirFromResolved(reqTf.resolve("onnxruntime-node"), "onnxruntime-node");
35361
35955
  }
35362
35956
  } catch (error) {
@@ -35364,7 +35958,7 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
35364
35958
  if (resolveError === "ERR_MODULE_NOT_FOUND" || resolveError === "MODULE_NOT_FOUND") {
35365
35959
  return withWasmFallback({
35366
35960
  state: "package-missing",
35367
- packageDir: join24(pluginDir, "node_modules", "onnxruntime-node")
35961
+ packageDir: join25(pluginDir, "node_modules", "onnxruntime-node")
35368
35962
  }, () => probeWasmRuntimeByResolution(pluginDir));
35369
35963
  }
35370
35964
  return {
@@ -35380,8 +35974,8 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
35380
35974
  if (rel === null) {
35381
35975
  native = probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath: onnxDir };
35382
35976
  } else {
35383
- const binaryPath = join24(onnxDir, rel);
35384
- native = existsSync27(binaryPath) ? probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath } : {
35977
+ const binaryPath = join25(onnxDir, rel);
35978
+ native = existsSync28(binaryPath) ? probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath } : {
35385
35979
  state: "binary-missing",
35386
35980
  packageDir: onnxDir,
35387
35981
  expectedBinary: binaryPath,
@@ -35417,7 +36011,14 @@ var init_embedding_runtime = __esm(() => {
35417
36011
 
35418
36012
  // src/lib/issue-body.ts
35419
36013
  function isErrorLogLine(line) {
35420
- return ERROR_LOG_PATTERNS.some((rx) => rx.test(line));
36014
+ const parsed = parseLogLine(line);
36015
+ if (parsed?.level !== null && parsed?.level !== undefined) {
36016
+ return parsed.level === "ERROR" || parsed.level === "WARN";
36017
+ }
36018
+ if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(line))
36019
+ return false;
36020
+ const message = parsed?.message ?? line;
36021
+ return ERROR_LOG_PATTERNS.some((rx) => rx.test(message));
35421
36022
  }
35422
36023
  function extractRecentErrors(sanitized, limit = 20) {
35423
36024
  const matches = [];
@@ -35504,6 +36105,7 @@ var MAX_GITHUB_BODY_BYTES = 60000, LOG_TRUNCATION_MARKER = `[truncated for GitHu
35504
36105
  [truncated for GitHub 64KB limit]
35505
36106
  `, ERROR_LOG_PATTERNS;
35506
36107
  var init_issue_body = __esm(() => {
36108
+ init_log_lines();
35507
36109
  ERROR_LOG_PATTERNS = [
35508
36110
  /\bfailed:/i,
35509
36111
  /\b(?:[A-Z][a-zA-Z]*)?Error:\s/,
@@ -35515,8 +36117,8 @@ var init_issue_body = __esm(() => {
35515
36117
  });
35516
36118
 
35517
36119
  // src/lib/logs-opencode.ts
35518
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync7 } from "node:fs";
35519
- import { join as join25 } from "node:path";
36120
+ import { writeFileSync as writeFileSync7 } from "node:fs";
36121
+ import { join as join26 } from "node:path";
35520
36122
  function sanitizeLogContent(content) {
35521
36123
  return sanitizeDiagnosticText(content);
35522
36124
  }
@@ -35539,7 +36141,8 @@ function extractHistorianFailureLines(sanitized, limit = 30) {
35539
36141
  const matches = [];
35540
36142
  const lines = sanitized.split(/\r?\n/);
35541
36143
  for (let i = lines.length - 1;i >= 0 && matches.length < limit; i -= 1) {
35542
- if (isHistorianLogLine(lines[i])) {
36144
+ const parsed = parseLogLine(lines[i]);
36145
+ if (parsed && isHistorianLogLine(parsed.message)) {
35543
36146
  matches.push(lines[i]);
35544
36147
  }
35545
36148
  }
@@ -35548,9 +36151,12 @@ function extractHistorianFailureLines(sanitized, limit = 30) {
35548
36151
  function filterLogLinesBySession(lines, sessionId) {
35549
36152
  if (!sessionId)
35550
36153
  return lines;
35551
- const otherSessionPattern = /\bses_[A-Za-z0-9]{8,32}\b/g;
36154
+ const otherSessionPattern = /\bses_[A-Za-z0-9]{3,64}\b/g;
35552
36155
  return lines.filter((line) => {
35553
- const matches = line.match(otherSessionPattern);
36156
+ const parsed = parseLogLine(line);
36157
+ if (parsed?.session && parsed.session !== sessionId)
36158
+ return false;
36159
+ const matches = parsed?.message.match(otherSessionPattern) ?? line.match(otherSessionPattern);
35554
36160
  if (!matches)
35555
36161
  return true;
35556
36162
  return matches.every((id) => id === sessionId);
@@ -35558,7 +36164,7 @@ function filterLogLinesBySession(lines, sessionId) {
35558
36164
  }
35559
36165
  async function bundleIssueReport(report, description, title, sessionFilter = null) {
35560
36166
  const LOG_TAIL_LINES = 400;
35561
- const allLogLines = report.logFile.exists ? readFileSync18(report.logFile.path, "utf-8").split(/\r?\n/) : [];
36167
+ const allLogLines = readLogLines(report.logFiles ?? [report.logFile]);
35562
36168
  const logLines = filterLogLinesBySession(allLogLines, sessionFilter);
35563
36169
  const recentLog = sanitizeLogContent(logLines.slice(-LOG_TAIL_LINES).join(`
35564
36170
  `)).trim();
@@ -35619,10 +36225,10 @@ async function bundleIssueReport(report, description, title, sessionFilter = nul
35619
36225
  const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
35620
36226
  const truncated = bodyMarkdown !== rawBodyMarkdown;
35621
36227
  const timestamp = formatTimestamp(new Date);
35622
- const path = join25(process.cwd(), `magic-context-issue-${timestamp}.md`);
36228
+ const path = join26(process.cwd(), `magic-context-issue-${timestamp}.md`);
35623
36229
  writeFileSync7(path, `${bodyMarkdown}
35624
36230
  `);
35625
- const fullPath = truncated ? join25(process.cwd(), `magic-context-issue-${timestamp}-full.md`) : undefined;
36231
+ const fullPath = truncated ? join26(process.cwd(), `magic-context-issue-${timestamp}-full.md`) : undefined;
35626
36232
  if (fullPath)
35627
36233
  writeFileSync7(fullPath, `${rawBodyMarkdown}
35628
36234
  `);
@@ -35632,6 +36238,7 @@ var HISTORIAN_LOG_PATTERNS;
35632
36238
  var init_logs_opencode = __esm(() => {
35633
36239
  init_diagnostics_opencode();
35634
36240
  init_issue_body();
36241
+ init_log_lines();
35635
36242
  init_redaction2();
35636
36243
  HISTORIAN_LOG_PATTERNS = [
35637
36244
  /historian failure:/,
@@ -35888,24 +36495,24 @@ function migrateExperimentalPinKeyFilesForDoctor(mcConfig) {
35888
36495
 
35889
36496
  // ../plugin/src/hooks/auto-update-checker/constants.ts
35890
36497
  import { homedir as homedir16, platform } from "node:os";
35891
- import { join as join26 } from "node:path";
36498
+ import { join as join27 } from "node:path";
35892
36499
  function getOpenCodeCacheRoot() {
35893
36500
  if (platform() === "win32") {
35894
- return join26(process.env.LOCALAPPDATA ?? homedir16(), "opencode");
36501
+ return join27(process.env.LOCALAPPDATA ?? homedir16(), "opencode");
35895
36502
  }
35896
- return join26(homedir16(), ".cache", "opencode");
36503
+ return join27(homedir16(), ".cache", "opencode");
35897
36504
  }
35898
36505
  function getOpenCodeConfigRoot() {
35899
36506
  if (platform() === "win32") {
35900
- return join26(process.env.APPDATA ?? join26(homedir16(), "AppData", "Roaming"), "opencode");
36507
+ return join27(process.env.APPDATA ?? join27(homedir16(), "AppData", "Roaming"), "opencode");
35901
36508
  }
35902
- return join26(process.env.XDG_CONFIG_HOME ?? join26(homedir16(), ".config"), "opencode");
36509
+ return join27(process.env.XDG_CONFIG_HOME ?? join27(homedir16(), ".config"), "opencode");
35903
36510
  }
35904
36511
  var PACKAGE_NAME = "@cortexkit/opencode-magic-context", CACHE_DIR, USER_OPENCODE_CONFIG, USER_OPENCODE_CONFIG_JSONC;
35905
36512
  var init_constants2 = __esm(() => {
35906
- CACHE_DIR = join26(getOpenCodeCacheRoot(), "packages");
35907
- USER_OPENCODE_CONFIG = join26(getOpenCodeConfigRoot(), "opencode.json");
35908
- USER_OPENCODE_CONFIG_JSONC = join26(getOpenCodeConfigRoot(), "opencode.jsonc");
36513
+ CACHE_DIR = join27(getOpenCodeCacheRoot(), "packages");
36514
+ USER_OPENCODE_CONFIG = join27(getOpenCodeConfigRoot(), "opencode.json");
36515
+ USER_OPENCODE_CONFIG_JSONC = join27(getOpenCodeConfigRoot(), "opencode.jsonc");
35909
36516
  });
35910
36517
  // ../plugin/src/hooks/auto-update-checker/types.ts
35911
36518
  var NpmPackageEnvelopeSchema, OpencodePluginTupleSchema, OpencodeConfigSchema, PackageJsonSchema;
@@ -35928,14 +36535,14 @@ var init_types = __esm(() => {
35928
36535
  // ../plugin/src/hooks/auto-update-checker/checker.ts
35929
36536
  import {
35930
36537
  accessSync as accessSync2,
35931
- existsSync as existsSync28,
36538
+ existsSync as existsSync29,
35932
36539
  constants as fsConstants,
35933
36540
  readFileSync as readFileSync19,
35934
36541
  renameSync as renameSync7,
35935
- statSync as statSync13,
36542
+ statSync as statSync14,
35936
36543
  writeFileSync as writeFileSync8
35937
36544
  } from "node:fs";
35938
- import { dirname as dirname17, isAbsolute as isAbsolute5, join as join27, resolve as resolve8 } from "node:path";
36545
+ import { dirname as dirname17, isAbsolute as isAbsolute5, join as join28, resolve as resolve8 } from "node:path";
35939
36546
  function warn(message) {
35940
36547
  log3(`WARN: ${message}`);
35941
36548
  }
@@ -35953,7 +36560,7 @@ function getPluginEntries(config) {
35953
36560
  }
35954
36561
  function parseJsonConfig(content) {
35955
36562
  try {
35956
- return import_comment_json11.parse(content);
36563
+ return import_comment_json10.parse(content);
35957
36564
  } catch (err) {
35958
36565
  warn(`[auto-update-checker] Failed to parse OpenCode config: ${String(err)}`);
35959
36566
  return null;
@@ -35965,13 +36572,13 @@ function getSurfaceConfigPaths(directory, surface) {
35965
36572
  const dirs = [
35966
36573
  globalDir,
35967
36574
  directory,
35968
- join27(directory, ".opencode"),
36575
+ join28(directory, ".opencode"),
35969
36576
  process.env.OPENCODE_CONFIG_DIR
35970
36577
  ].filter((value) => Boolean(value));
35971
36578
  const paths = [];
35972
36579
  for (const dir of dirs) {
35973
36580
  for (const extension of ["json", "jsonc"]) {
35974
- const path = join27(dir, `${name}.${extension}`);
36581
+ const path = join28(dir, `${name}.${extension}`);
35975
36582
  if (!paths.includes(path))
35976
36583
  paths.push(path);
35977
36584
  }
@@ -35982,7 +36589,7 @@ function getWinningConfig(directory, surface) {
35982
36589
  let winner = null;
35983
36590
  for (const path of getSurfaceConfigPaths(directory, surface)) {
35984
36591
  try {
35985
- if (!existsSync28(path))
36592
+ if (!existsSync29(path))
35986
36593
  continue;
35987
36594
  const parsed = parseJsonConfig(readFileSync19(path, "utf-8"));
35988
36595
  const entries = getPluginEntries(parsed);
@@ -36011,21 +36618,21 @@ function findPluginEntry(directory, surface = "server") {
36011
36618
  configPath: winner.path
36012
36619
  };
36013
36620
  }
36014
- var import_comment_json11;
36621
+ var import_comment_json10;
36015
36622
  var init_checker = __esm(() => {
36016
36623
  init_logger();
36017
36624
  init_constants2();
36018
36625
  init_types();
36019
- import_comment_json11 = __toESM(require_src3(), 1);
36626
+ import_comment_json10 = __toESM(require_src3(), 1);
36020
36627
  });
36021
36628
 
36022
36629
  // src/lib/opencode-plugin-schema-fence.ts
36023
- import { existsSync as existsSync29, readdirSync as readdirSync4, readFileSync as readFileSync20 } from "node:fs";
36024
- import { join as join28 } from "node:path";
36630
+ import { existsSync as existsSync30, readdirSync as readdirSync4, readFileSync as readFileSync20 } from "node:fs";
36631
+ import { join as join29 } from "node:path";
36025
36632
  import { gunzipSync } from "node:zlib";
36026
36633
  function readPackageVersion(packageJsonPath) {
36027
36634
  try {
36028
- if (!existsSync29(packageJsonPath))
36635
+ if (!existsSync30(packageJsonPath))
36029
36636
  return null;
36030
36637
  const packageJson = JSON.parse(readFileSync20(packageJsonPath, "utf-8"));
36031
36638
  if (packageJson.name !== OPENCODE_PLUGIN_NAME || typeof packageJson.version !== "string") {
@@ -36046,8 +36653,8 @@ function readFenceValue(text) {
36046
36653
  return values.size === 1 ? [...values][0] ?? null : null;
36047
36654
  }
36048
36655
  function readFenceFromDist(packageDirectory) {
36049
- const distDirectory = join28(packageDirectory, "dist");
36050
- if (!existsSync29(distDirectory))
36656
+ const distDirectory = join29(packageDirectory, "dist");
36657
+ if (!existsSync30(distDirectory))
36051
36658
  return null;
36052
36659
  const pending = [distDirectory];
36053
36660
  const fenceValues = new Set;
@@ -36057,7 +36664,7 @@ function readFenceFromDist(packageDirectory) {
36057
36664
  continue;
36058
36665
  try {
36059
36666
  for (const entry of readdirSync4(directory, { withFileTypes: true })) {
36060
- const path = join28(directory, entry.name);
36667
+ const path = join29(directory, entry.name);
36061
36668
  if (entry.isDirectory()) {
36062
36669
  pending.push(path);
36063
36670
  continue;
@@ -36075,20 +36682,20 @@ function readFenceFromDist(packageDirectory) {
36075
36682
  return fenceValues.size === 1 ? [...fenceValues][0] ?? null : null;
36076
36683
  }
36077
36684
  function findInstalledPluginPackage(cacheDirectory, specifier, requestedVersion) {
36078
- const directCacheRoot = join28(cacheDirectory, specifier);
36685
+ const directCacheRoot = join29(cacheDirectory, specifier);
36079
36686
  const candidates = [directCacheRoot];
36080
36687
  try {
36081
36688
  for (const entry of readdirSync4(cacheDirectory, { withFileTypes: true })) {
36082
36689
  if (!entry.isDirectory())
36083
36690
  continue;
36084
- const candidate = join28(cacheDirectory, entry.name);
36691
+ const candidate = join29(cacheDirectory, entry.name);
36085
36692
  if (!candidates.includes(candidate))
36086
36693
  candidates.push(candidate);
36087
36694
  }
36088
36695
  } catch {}
36089
36696
  for (const cacheRoot of candidates) {
36090
- const directory = join28(cacheRoot, "node_modules", ...PACKAGE_PATH_SEGMENTS);
36091
- const version = readPackageVersion(join28(directory, "package.json"));
36697
+ const directory = join29(cacheRoot, "node_modules", ...PACKAGE_PATH_SEGMENTS);
36698
+ const version = readPackageVersion(join29(directory, "package.json"));
36092
36699
  if (!version)
36093
36700
  continue;
36094
36701
  if (cacheRoot === directCacheRoot || EXACT_VERSION_PATTERN.test(requestedVersion) && version === requestedVersion) {
@@ -36282,11 +36889,11 @@ var init_storage_versions = __esm(async () => {
36282
36889
  });
36283
36890
 
36284
36891
  // src/commands/doctor-opencode-cache.ts
36285
- import { existsSync as existsSync30, readFileSync as readFileSync21, rmSync as rmSync3 } from "node:fs";
36892
+ import { existsSync as existsSync31, readFileSync as readFileSync21, rmSync as rmSync3 } from "node:fs";
36286
36893
  function readCachedPluginVersion(pluginCacheDir) {
36287
36894
  try {
36288
36895
  const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
36289
- if (!existsSync30(installedPkgPath))
36896
+ if (!existsSync31(installedPkgPath))
36290
36897
  return;
36291
36898
  const pkg = JSON.parse(readFileSync21(installedPkgPath, "utf-8"));
36292
36899
  return typeof pkg.version === "string" ? pkg.version : undefined;
@@ -36297,7 +36904,7 @@ function readCachedPluginVersion(pluginCacheDir) {
36297
36904
  async function clearPluginCache(options = {}, deps = {}) {
36298
36905
  const remove = deps.remove ?? ((path) => rmSync3(path, { recursive: true, force: true }));
36299
36906
  const pluginCacheRoots = getOpenCodePluginCacheRoots();
36300
- const existingRoots = pluginCacheRoots.filter((root) => existsSync30(root));
36907
+ const existingRoots = pluginCacheRoots.filter((root) => existsSync31(root));
36301
36908
  if (existingRoots.length === 0) {
36302
36909
  return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
36303
36910
  }
@@ -36365,10 +36972,10 @@ var init_doctor_opencode_cache = __esm(() => {
36365
36972
 
36366
36973
  // src/commands/doctor-opencode.ts
36367
36974
  import { spawnSync as spawnSync7 } from "node:child_process";
36368
- import { existsSync as existsSync31, readFileSync as readFileSync22, statSync as statSync14 } from "node:fs";
36975
+ import { existsSync as existsSync32, readFileSync as readFileSync22 } from "node:fs";
36369
36976
  import { createRequire as createRequire5 } from "node:module";
36370
36977
  import { homedir as homedir17 } from "node:os";
36371
- import { join as join29 } from "node:path";
36978
+ import { join as join30 } from "node:path";
36372
36979
  function resolveCompactionEnabledForDoctor() {
36373
36980
  try {
36374
36981
  const config = loadPluginConfig(process.cwd());
@@ -36467,12 +37074,12 @@ function getUserNpmrcPath() {
36467
37074
  if (custom)
36468
37075
  return custom;
36469
37076
  const home = process.env.HOME?.trim();
36470
- return join29(home || homedir17(), ".npmrc");
37077
+ return join30(home || homedir17(), ".npmrc");
36471
37078
  }
36472
37079
  function collectNpmReleaseAgeWarnings() {
36473
37080
  const ageWarnings = [];
36474
37081
  const npmrcPath = getUserNpmrcPath();
36475
- if (!existsSync31(npmrcPath))
37082
+ if (!existsSync32(npmrcPath))
36476
37083
  return ageWarnings;
36477
37084
  try {
36478
37085
  const npmrc = readFileSync22(npmrcPath, "utf-8");
@@ -36609,7 +37216,7 @@ function checkLocalEmbeddingRuntimeForDoctor(runtimePreference = "auto") {
36609
37216
  return { issues: 0 };
36610
37217
  }
36611
37218
  async function checkEmbeddingConfig(magicContextConfigPath) {
36612
- if (!existsSync31(magicContextConfigPath)) {
37219
+ if (!existsSync32(magicContextConfigPath)) {
36613
37220
  return checkLocalEmbeddingRuntimeForDoctor();
36614
37221
  }
36615
37222
  let rawText;
@@ -36628,7 +37235,7 @@ async function checkEmbeddingConfig(magicContextConfigPath) {
36628
37235
  });
36629
37236
  let parsedConfig;
36630
37237
  try {
36631
- parsedConfig = import_comment_json12.parse(substituted.text);
37238
+ parsedConfig = import_comment_json11.parse(substituted.text);
36632
37239
  } catch (error) {
36633
37240
  log2.warn(`Embedding check skipped — could not parse magic-context.jsonc: ${error instanceof Error ? error.message : String(error)}`);
36634
37241
  return { issues: 1 };
@@ -36741,7 +37348,7 @@ async function runDoctor2(options = {}) {
36741
37348
  const v22Result = await runV22BackfillCommands({
36742
37349
  name: "OpenCode",
36743
37350
  openDatabase: (readonly = true) => {
36744
- const dbPath = join29(getMagicContextStorageDir(), "context.db");
37351
+ const dbPath = join30(getMagicContextStorageDir(), "context.db");
36745
37352
  v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
36746
37353
  return v22Db;
36747
37354
  },
@@ -36773,7 +37380,7 @@ async function runDoctor2(options = {}) {
36773
37380
  failCount++;
36774
37381
  issues++;
36775
37382
  };
36776
- const authorityDbPath = join29(getMagicContextStorageDir(), "context.db");
37383
+ const authorityDbPath = join30(getMagicContextStorageDir(), "context.db");
36777
37384
  let authorityDb = null;
36778
37385
  try {
36779
37386
  authorityDb = openExistingContextDatabase(authorityDbPath, { readonly: true });
@@ -36824,7 +37431,7 @@ async function runDoctor2(options = {}) {
36824
37431
  } else {
36825
37432
  pass(`OpenCode config: ${paths.opencodeConfig}`);
36826
37433
  }
36827
- if (existsSync31(paths.magicContextConfig)) {
37434
+ if (existsSync32(paths.magicContextConfig)) {
36828
37435
  pass(`Magic Context config: ${paths.magicContextConfig}`);
36829
37436
  try {
36830
37437
  const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
@@ -36834,7 +37441,11 @@ async function runDoctor2(options = {}) {
36834
37441
  text: raw.text,
36835
37442
  configPath: paths.magicContextConfig
36836
37443
  }).text;
36837
- import_comment_json12.parse(substituted);
37444
+ const parsed = parseJsoncRecovering(substituted);
37445
+ const issue = parsed.issues[0];
37446
+ if (issue) {
37447
+ throw new Error(`${paths.magicContextConfig}:${issue.line}:${issue.column}: ${issue.message} (runtime recovery does not make the file valid)`);
37448
+ }
36838
37449
  pass("magic-context.jsonc parses as valid JSONC");
36839
37450
  } catch (err) {
36840
37451
  fail(`magic-context.jsonc parse failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -36854,12 +37465,12 @@ async function runDoctor2(options = {}) {
36854
37465
  warn(`No magic-context.jsonc found — using defaults`);
36855
37466
  log2.info(" Run 'setup' to create one with model recommendations");
36856
37467
  }
36857
- if (existsSync31(paths.magicContextConfig)) {
37468
+ if (existsSync32(paths.magicContextConfig)) {
36858
37469
  try {
36859
37470
  const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
36860
37471
  if (!raw)
36861
37472
  throw new Error("Magic Context config disappeared while doctor was reading it");
36862
- const mcConfig = import_comment_json12.parse(raw.text);
37473
+ const mcConfig = import_comment_json11.parse(raw.text);
36863
37474
  let mcChanged = false;
36864
37475
  const experimental = mcConfig.experimental;
36865
37476
  if (experimental && "compaction_markers" in experimental) {
@@ -36967,7 +37578,7 @@ async function runDoctor2(options = {}) {
36967
37578
  fixed++;
36968
37579
  }
36969
37580
  if (mcChanged) {
36970
- writeFileAtomic(paths.magicContextConfig, `${import_comment_json12.stringify(mcConfig, null, 2)}
37581
+ writeFileAtomic(paths.magicContextConfig, `${import_comment_json11.stringify(mcConfig, null, 2)}
36971
37582
  `);
36972
37583
  }
36973
37584
  } catch {
@@ -36977,7 +37588,7 @@ async function runDoctor2(options = {}) {
36977
37588
  if (paths.opencodeConfigFormat !== "none") {
36978
37589
  try {
36979
37590
  const raw = readFileSync22(paths.opencodeConfig, "utf-8");
36980
- const config = import_comment_json12.parse(raw);
37591
+ const config = import_comment_json11.parse(raw);
36981
37592
  const rawPlugins = Array.isArray(config?.plugin) ? config.plugin : [];
36982
37593
  const existingIdx = rawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
36983
37594
  if (rawPlugins.some((entry) => isLocalPathPluginEntry(entry) && String(entry).includes("magic-context") && !isDevPathPluginEntry(entry))) {
@@ -37011,7 +37622,7 @@ async function runDoctor2(options = {}) {
37011
37622
  rawPlugins[existingIdx] = OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
37012
37623
  }
37013
37624
  config.plugin = rawPlugins;
37014
- writeFileAtomic(paths.opencodeConfig, `${import_comment_json12.stringify(config, null, 2)}
37625
+ writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config, null, 2)}
37015
37626
  `);
37016
37627
  pass(`Upgraded plugin entry in ${configName}: ${oldEntryStr} → ${OPENCODE_PLUGIN_ENTRY_WITH_VERSION}`);
37017
37628
  fixed++;
@@ -37020,7 +37631,7 @@ async function runDoctor2(options = {}) {
37020
37631
  } else {
37021
37632
  rawPlugins.push(OPENCODE_PLUGIN_ENTRY_WITH_VERSION);
37022
37633
  config.plugin = rawPlugins;
37023
- writeFileAtomic(paths.opencodeConfig, `${import_comment_json12.stringify(config, null, 2)}
37634
+ writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config, null, 2)}
37024
37635
  `);
37025
37636
  pass(`Added plugin to ${configName}`);
37026
37637
  fixed++;
@@ -37061,10 +37672,10 @@ async function runDoctor2(options = {}) {
37061
37672
  pass("Added TUI sidebar plugin to tui.json");
37062
37673
  warn("Restart OpenCode to see the sidebar");
37063
37674
  fixed++;
37064
- } else if (existsSync31(paths.tuiConfig)) {
37675
+ } else if (existsSync32(paths.tuiConfig)) {
37065
37676
  try {
37066
37677
  const tuiRaw = readFileSync22(paths.tuiConfig, "utf-8");
37067
- const tuiConfig = import_comment_json12.parse(tuiRaw);
37678
+ const tuiConfig = import_comment_json11.parse(tuiRaw);
37068
37679
  const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
37069
37680
  const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
37070
37681
  if (tuiRawPlugins.some((entry) => isLocalPathPluginEntry(entry) && String(entry).includes("magic-context") && !isDevPathPluginEntry(entry))) {
@@ -37095,7 +37706,7 @@ async function runDoctor2(options = {}) {
37095
37706
  tuiRawPlugins[tuiIdx] = OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
37096
37707
  }
37097
37708
  tuiConfig.plugin = tuiRawPlugins;
37098
- writeFileAtomic(paths.tuiConfig, `${import_comment_json12.stringify(tuiConfig, null, 2)}
37709
+ writeFileAtomic(paths.tuiConfig, `${import_comment_json11.stringify(tuiConfig, null, 2)}
37099
37710
  `);
37100
37711
  pass(`Upgraded TUI plugin: ${tuiEntryStr} → ${OPENCODE_PLUGIN_ENTRY_WITH_VERSION}`);
37101
37712
  fixed++;
@@ -37112,12 +37723,12 @@ async function runDoctor2(options = {}) {
37112
37723
  } else {
37113
37724
  fail("Could not create or verify the TUI sidebar config");
37114
37725
  }
37115
- if (existsSync31(paths.magicContextConfig)) {
37726
+ if (existsSync32(paths.magicContextConfig)) {
37116
37727
  try {
37117
37728
  const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
37118
37729
  if (!raw)
37119
37730
  throw new Error("Magic Context config disappeared while doctor was reading it");
37120
- const mcConfig = import_comment_json12.parse(raw.text);
37731
+ const mcConfig = import_comment_json11.parse(raw.text);
37121
37732
  const warning = checkUserMemoriesDreamerCompatibility(mcConfig);
37122
37733
  if (warning) {
37123
37734
  log2.warn(warning);
@@ -37134,9 +37745,9 @@ async function runDoctor2(options = {}) {
37134
37745
  else
37135
37746
  passCount++;
37136
37747
  const storage = getMagicContextStorageResolution();
37137
- const dbPath = join29(storage.path, "context.db");
37748
+ const dbPath = join30(storage.path, "context.db");
37138
37749
  log2.info(`Shared storage: ${storage.path} (source: ${storage.source})`);
37139
- if (!existsSync31(dbPath)) {
37750
+ if (!existsSync32(dbPath)) {
37140
37751
  log2.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
37141
37752
  } else {
37142
37753
  log2.info(`Shared context DB exists at ${dbPath}`);
@@ -37257,13 +37868,14 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
37257
37868
  issues++;
37258
37869
  }
37259
37870
  }
37260
- const logPath = getMagicContextLogPath2("opencode");
37261
- if (existsSync31(logPath)) {
37262
- const logStat = statSync14(logPath);
37263
- const sizeKb = (logStat.size / 1024).toFixed(0);
37264
- log2.info(`Log file: ${logPath} (${sizeKb} KB)`);
37871
+ const logFiles = inspectMagicContextLogs("opencode");
37872
+ const existingLogFiles = logFiles.filter((file) => file.exists);
37873
+ if (existingLogFiles.length === 0) {
37874
+ log2.info(`No plugin log file yet; checked: ${logFiles.map((file) => file.path).join(", ")}`);
37265
37875
  } else {
37266
- log2.info(`Log file: ${logPath} (not yet created)`);
37876
+ for (const file of existingLogFiles) {
37877
+ log2.info(`Log file read: ${formatLogFileInspection(file)}`);
37878
+ }
37267
37879
  }
37268
37880
  const diagnostics = await collectDiagnostics();
37269
37881
  const dumpBuckets = diagnostics.historianDumps.byProject;
@@ -37304,7 +37916,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
37304
37916
  }
37305
37917
  return 0;
37306
37918
  }
37307
- var import_comment_json12, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
37919
+ var import_comment_json11, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
37308
37920
  var init_doctor_opencode = __esm(async () => {
37309
37921
  init_config();
37310
37922
  init_agent_disable();
@@ -37313,6 +37925,7 @@ var init_doctor_opencode = __esm(async () => {
37313
37925
  init_conflict_detector();
37314
37926
  init_conflict_fixer();
37315
37927
  init_data_path();
37928
+ init_jsonc_parser();
37316
37929
  init_tui_config();
37317
37930
  init_opencode();
37318
37931
  init_atomic_write();
@@ -37320,6 +37933,7 @@ var init_doctor_opencode = __esm(async () => {
37320
37933
  init_diagnostics_opencode();
37321
37934
  init_embedding_runtime();
37322
37935
  init_github_issue();
37936
+ init_log_lines();
37323
37937
  init_logs_opencode();
37324
37938
  init_migrate_dreamer_v2_doctor();
37325
37939
  init_opencode_detect();
@@ -37337,13 +37951,13 @@ var init_doctor_opencode = __esm(async () => {
37337
37951
  init_v22_backfill_commands(),
37338
37952
  init_doctor_authority()
37339
37953
  ]);
37340
- import_comment_json12 = __toESM(require_src3(), 1);
37954
+ import_comment_json11 = __toESM(require_src3(), 1);
37341
37955
  });
37342
37956
 
37343
37957
  // src/lib/diagnostics-pi.ts
37344
- import { existsSync as existsSync32, readdirSync as readdirSync5, readFileSync as readFileSync23, statSync as statSync15 } from "node:fs";
37958
+ import { existsSync as existsSync33, readdirSync as readdirSync5, readFileSync as readFileSync23, statSync as statSync15 } from "node:fs";
37345
37959
  import { createRequire as createRequire6 } from "node:module";
37346
- import { join as join30 } from "node:path";
37960
+ import { join as join31 } from "node:path";
37347
37961
  function getSelfVersion3() {
37348
37962
  const req = createRequire6(import.meta.url);
37349
37963
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -37358,7 +37972,7 @@ function getSelfVersion3() {
37358
37972
  }
37359
37973
  function fileSize2(path) {
37360
37974
  try {
37361
- return existsSync32(path) ? statSync15(path).size : 0;
37975
+ return existsSync33(path) ? statSync15(path).size : 0;
37362
37976
  } catch {
37363
37977
  return 0;
37364
37978
  }
@@ -37370,11 +37984,11 @@ function sanitizeValue2(value) {
37370
37984
  return sanitizeConfigValue(value);
37371
37985
  }
37372
37986
  function readJsonc(path) {
37373
- if (!existsSync32(path))
37987
+ if (!existsSync33(path))
37374
37988
  return { value: {} };
37375
37989
  try {
37376
37990
  return {
37377
- value: import_comment_json13.parse(readFileSync23(path, "utf-8"))
37991
+ value: import_comment_json12.parse(readFileSync23(path, "utf-8"))
37378
37992
  };
37379
37993
  } catch (error) {
37380
37994
  return {
@@ -37390,7 +38004,7 @@ function readConfigDiagnostic(path) {
37390
38004
  const parsed = readJsonc(path);
37391
38005
  return {
37392
38006
  path,
37393
- exists: existsSync32(path),
38007
+ exists: existsSync33(path),
37394
38008
  ...parsed.parseError ? { parseError: parsed.parseError } : {},
37395
38009
  flags: sanitizeValue2(parsed.value)
37396
38010
  };
@@ -37408,7 +38022,7 @@ function reverseSlugToDirectory(slug) {
37408
38022
  }
37409
38023
  function collectPiRecentSessions() {
37410
38024
  const sessionsRoot = getPiSessionsRoot();
37411
- if (!existsSync32(sessionsRoot))
38025
+ if (!existsSync33(sessionsRoot))
37412
38026
  return [];
37413
38027
  try {
37414
38028
  const slugs = readdirSync5(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
@@ -37417,7 +38031,7 @@ function collectPiRecentSessions() {
37417
38031
  const directory = reverseSlugToDirectory(slug);
37418
38032
  if (!directory)
37419
38033
  continue;
37420
- const slugDir = join30(sessionsRoot, slug);
38034
+ const slugDir = join31(sessionsRoot, slug);
37421
38035
  let files;
37422
38036
  try {
37423
38037
  files = readdirSync5(slugDir).filter((name) => name.endsWith(".jsonl"));
@@ -37426,7 +38040,7 @@ function collectPiRecentSessions() {
37426
38040
  }
37427
38041
  for (const file of files) {
37428
38042
  try {
37429
- const mtime = statSync15(join30(slugDir, file)).mtimeMs;
38043
+ const mtime = statSync15(join31(slugDir, file)).mtimeMs;
37430
38044
  const sessionId = file.replace(/\.jsonl$/, "");
37431
38045
  candidates.push({ sessionId, directory, mtime });
37432
38046
  } catch {}
@@ -37477,11 +38091,11 @@ function parseHistorianDumpMeta2(path) {
37477
38091
  }
37478
38092
  }
37479
38093
  function listDumpsInDir2(dir, limit) {
37480
- if (!existsSync32(dir))
38094
+ if (!existsSync33(dir))
37481
38095
  return { count: 0, recent: [] };
37482
38096
  try {
37483
38097
  const entries = readdirSync5(dir).filter((name) => name.endsWith(".xml")).map((name) => {
37484
- const stat = statSync15(join30(dir, name));
38098
+ const stat = statSync15(join31(dir, name));
37485
38099
  return {
37486
38100
  name,
37487
38101
  mtime: stat.mtimeMs,
@@ -37490,7 +38104,7 @@ function listDumpsInDir2(dir, limit) {
37490
38104
  }).sort((a, b) => b.mtime - a.mtime);
37491
38105
  const now = Date.now();
37492
38106
  const recent = entries.slice(0, limit).map((entry) => {
37493
- const meta = parseHistorianDumpMeta2(join30(dir, entry.name));
38107
+ const meta = parseHistorianDumpMeta2(join31(dir, entry.name));
37494
38108
  const summary = {
37495
38109
  name: entry.name,
37496
38110
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -37554,9 +38168,9 @@ async function collectDiagnostics2(cwd = process.cwd()) {
37554
38168
  const loaded = loadPiConfig({ cwd });
37555
38169
  const storageResolution = getMagicContextStorageResolution();
37556
38170
  const storageDirPath = storageResolution.path;
37557
- const dbPath = join30(storageDirPath, "context.db");
37558
- const logPath = getMagicContextLogPath2("pi");
37559
- const logFileSize = existsSync32(logPath) ? statSync15(logPath).size : 0;
38171
+ const dbPath = join31(storageDirPath, "context.db");
38172
+ const logFiles = inspectMagicContextLogs("pi");
38173
+ const primaryLog = logFiles.find((file) => file.exists) ?? logFiles[0];
37560
38174
  const otherPiExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
37561
38175
  const recentSessions = collectPiRecentSessions();
37562
38176
  const historianDumps = collectPiHistorianDumps(recentSessions);
@@ -37571,7 +38185,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
37571
38185
  piVersion: pi ? getPiVersion(pi.path) : null,
37572
38186
  settings: {
37573
38187
  path: settingsPath,
37574
- exists: existsSync32(settingsPath),
38188
+ exists: existsSync33(settingsPath),
37575
38189
  ...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
37576
38190
  hasMagicContextPackage: hasPiMagicContextPackage(packages),
37577
38191
  packages: sanitizeValue2(packages)
@@ -37588,7 +38202,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
37588
38202
  storageDir: {
37589
38203
  path: storageDirPath,
37590
38204
  source: storageResolution.source,
37591
- exists: existsSync32(storageDirPath),
38205
+ exists: existsSync33(storageDirPath),
37592
38206
  contextDbSizeBytes: fileSize2(dbPath)
37593
38207
  },
37594
38208
  conflicts: {
@@ -37596,10 +38210,11 @@ async function collectDiagnostics2(cwd = process.cwd()) {
37596
38210
  otherPiExtensions: otherPiExtensions.map(sanitizeString2)
37597
38211
  },
37598
38212
  logFile: {
37599
- path: logPath,
37600
- exists: existsSync32(logPath),
37601
- sizeKb: Math.round(logFileSize / 1024)
38213
+ path: primaryLog.path,
38214
+ exists: primaryLog.exists,
38215
+ sizeKb: primaryLog.sizeKb
37602
38216
  },
38217
+ logFiles,
37603
38218
  recentSessions,
37604
38219
  historianDumps
37605
38220
  };
@@ -37672,28 +38287,27 @@ function renderDiagnosticsMarkdown2(report) {
37672
38287
  JSON.stringify(report.conflicts, null, 2),
37673
38288
  "```",
37674
38289
  "",
37675
- "### Log file",
37676
- `- Path: ${sanitizeString2(report.logFile.path)}`,
37677
- `- Exists: ${report.logFile.exists}`,
37678
- `- Size: ${report.logFile.sizeKb} KB`
38290
+ "### Log files",
38291
+ ...(report.logFiles ?? [report.logFile]).map((file) => `- ${sanitizeString2(file.path)}: exists=${file.exists}, grammar=${"grammar" in file ? file.grammar : "unknown"}, lines=${"lineCount" in file ? file.lineCount : 0}, size=${file.sizeKb} KB`)
37679
38292
  ].join(`
37680
38293
  `);
37681
38294
  }
37682
- var import_comment_json13;
38295
+ var import_comment_json12;
37683
38296
  var init_diagnostics_pi = __esm(() => {
37684
38297
  init_migrate_config_location();
37685
38298
  init_compartment_parser();
37686
38299
  init_data_path();
37687
38300
  init_config2();
38301
+ init_log_lines();
37688
38302
  init_paths();
37689
38303
  init_pi_helpers();
37690
38304
  init_redaction2();
37691
- import_comment_json13 = __toESM(require_src3(), 1);
38305
+ import_comment_json12 = __toESM(require_src3(), 1);
37692
38306
  });
37693
38307
 
37694
38308
  // src/lib/logs-pi.ts
37695
- import { readFileSync as readFileSync24, writeFileSync as writeFileSync9 } from "node:fs";
37696
- import { join as join31 } from "node:path";
38309
+ import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "node:fs";
38310
+ import { dirname as dirname18, join as join32 } from "node:path";
37697
38311
  function sanitizeLogContent2(content) {
37698
38312
  return sanitizeString2(content);
37699
38313
  }
@@ -37712,9 +38326,12 @@ function formatTimestamp2(date) {
37712
38326
  function filterLogLinesBySession2(lines, sessionId) {
37713
38327
  if (!sessionId)
37714
38328
  return lines;
37715
- const otherSessionPattern = /\bses_[A-Za-z0-9]{8,32}\b/g;
38329
+ const otherSessionPattern = /\bses_[A-Za-z0-9]{3,64}\b/g;
37716
38330
  return lines.filter((line) => {
37717
- const matches = line.match(otherSessionPattern);
38331
+ const parsed = parseLogLine(line);
38332
+ if (parsed?.session && parsed.session !== sessionId)
38333
+ return false;
38334
+ const matches = parsed?.message.match(otherSessionPattern) ?? line.match(otherSessionPattern);
37718
38335
  if (!matches)
37719
38336
  return true;
37720
38337
  return matches.every((id) => id === sessionId);
@@ -37722,7 +38339,7 @@ function filterLogLinesBySession2(lines, sessionId) {
37722
38339
  }
37723
38340
  async function bundleIssueReport2(report, description, title, options = {}) {
37724
38341
  const LOG_TAIL_LINES = 400;
37725
- const allLogLines = report.logFile.exists ? readFileSync24(report.logFile.path, "utf-8").split(/\r?\n/) : [];
38342
+ const allLogLines = readLogLines(report.logFiles ?? [report.logFile]);
37726
38343
  const logLines = filterLogLinesBySession2(allLogLines, options.sessionFilter ?? null);
37727
38344
  const recentLog = sanitizeLogContent2(logLines.slice(-LOG_TAIL_LINES).join(`
37728
38345
  `)).trim();
@@ -37760,10 +38377,11 @@ async function bundleIssueReport2(report, description, title, options = {}) {
37760
38377
  const truncated = bodyMarkdown !== rawBodyMarkdown;
37761
38378
  const cwd = options.cwd ?? process.cwd();
37762
38379
  const timestamp = formatTimestamp2(options.now ?? new Date);
37763
- const path = join31(cwd, `magic-context-pi-issue-${timestamp}.md`);
38380
+ const path = options.outputPath ?? join32(cwd, `magic-context-pi-issue-${timestamp}.md`);
38381
+ mkdirSync10(dirname18(path), { recursive: true });
37764
38382
  writeFileSync9(path, `${bodyMarkdown}
37765
38383
  `);
37766
- const fullPath = truncated ? join31(cwd, `magic-context-pi-issue-${timestamp}-full.md`) : undefined;
38384
+ const fullPath = truncated ? options.outputPath ? `${options.outputPath}.full.md` : join32(cwd, `magic-context-pi-issue-${timestamp}-full.md`) : undefined;
37767
38385
  if (fullPath)
37768
38386
  writeFileSync9(fullPath, `${rawBodyMarkdown}
37769
38387
  `);
@@ -37772,14 +38390,15 @@ async function bundleIssueReport2(report, description, title, options = {}) {
37772
38390
  var init_logs_pi = __esm(() => {
37773
38391
  init_diagnostics_pi();
37774
38392
  init_issue_body();
38393
+ init_log_lines();
37775
38394
  });
37776
38395
 
37777
38396
  // src/commands/doctor-pi.ts
37778
38397
  import { execFileSync as execFileSync6, spawnSync as spawnSync8 } from "node:child_process";
37779
- import { existsSync as existsSync33, mkdirSync as mkdirSync10, readdirSync as readdirSync6, readFileSync as readFileSync25, rmSync as rmSync4, statSync as statSync16 } from "node:fs";
38398
+ import { existsSync as existsSync34, mkdirSync as mkdirSync11, readdirSync as readdirSync6, readFileSync as readFileSync24, rmSync as rmSync4, statSync as statSync16 } from "node:fs";
37780
38399
  import { createRequire as createRequire7 } from "node:module";
37781
38400
  import { homedir as homedir18 } from "node:os";
37782
- import { dirname as dirname18, isAbsolute as isAbsolute6, join as join32 } from "node:path";
38401
+ import { dirname as dirname19, isAbsolute as isAbsolute6, join as join33 } from "node:path";
37783
38402
  function depsFrom(options) {
37784
38403
  return {
37785
38404
  ...DEFAULT_DEPS5,
@@ -37796,6 +38415,7 @@ function printDoctorHelp() {
37796
38415
  console.log(" magic-context-pi doctor Run health checks");
37797
38416
  console.log(" magic-context-pi doctor --force Repair safe issues, then re-check");
37798
38417
  console.log(" magic-context-pi doctor --issue Create a sanitized bug report");
38418
+ console.log(" magic-context-pi doctor --issue --report <path> Write a report without prompting");
37799
38419
  console.log(" magic-context-pi doctor --check-v22-backfill Show v22 memory backfill status");
37800
38420
  console.log(" magic-context-pi doctor --retry-v22-backfill Retry failed v22 memory backfill rows");
37801
38421
  console.log(" magic-context-pi doctor --rekey-v22-dir-identity <path> Re-key legacy dir identity rows");
@@ -37869,7 +38489,7 @@ function summarize(results) {
37869
38489
  function readJsonc2(path) {
37870
38490
  try {
37871
38491
  return {
37872
- value: import_comment_json14.parse(readFileSync25(path, "utf-8"))
38492
+ value: import_comment_json13.parse(readFileSync24(path, "utf-8"))
37873
38493
  };
37874
38494
  } catch (error) {
37875
38495
  return {
@@ -37883,7 +38503,18 @@ function readMagicContextJsonc(path, tier) {
37883
38503
  const raw = loadRawConfigFile({ configPath: path, tier });
37884
38504
  if (!raw)
37885
38505
  return { value: {}, error: "config file disappeared while doctor was reading it" };
37886
- return { value: import_comment_json14.parse(raw.text) };
38506
+ const substituted = substituteConfigVariables({
38507
+ text: raw.text,
38508
+ configPath: path,
38509
+ isProjectConfig: tier === "project"
38510
+ });
38511
+ const parsed = parseJsoncRecovering(substituted.text);
38512
+ const value = parsed.value && typeof parsed.value === "object" && !Array.isArray(parsed.value) ? parsed.value : {};
38513
+ const issue = parsed.issues[0];
38514
+ return issue ? {
38515
+ value,
38516
+ error: `${path}:${issue.line}:${issue.column}: ${issue.message} (runtime recovery does not make the file valid)`
38517
+ } : { value };
37887
38518
  } catch (error) {
37888
38519
  return {
37889
38520
  value: {},
@@ -37901,18 +38532,18 @@ function piPluginDirCandidates(packages, cwd) {
37901
38532
  const spec = typeof entry === "string" ? entry.trim() : "";
37902
38533
  if (!spec || spec.startsWith("npm:"))
37903
38534
  continue;
37904
- const resolved = isAbsolute6(spec) ? spec : join32(agentDir, spec);
38535
+ const resolved = isAbsolute6(spec) ? spec : join33(agentDir, spec);
37905
38536
  dirs.push(resolved);
37906
38537
  }
37907
- dirs.push(join32(agentDir, "npm", "node_modules", PACKAGE_NAME2));
37908
- dirs.push(join32(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2));
37909
- return dirs.filter((dir) => existsSync33(join32(dir, "package.json")));
38538
+ dirs.push(join33(agentDir, "npm", "node_modules", PACKAGE_NAME2));
38539
+ dirs.push(join33(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2));
38540
+ return dirs.filter((dir) => existsSync34(join33(dir, "package.json")));
37910
38541
  }
37911
38542
  function projectConfigPath(cwd) {
37912
38543
  return resolveCortexKitProjectConfigPath(cwd);
37913
38544
  }
37914
38545
  function readConfigForEmbedding(path, isProjectConfig) {
37915
- if (!existsSync33(path))
38546
+ if (!existsSync34(path))
37916
38547
  return null;
37917
38548
  try {
37918
38549
  const raw = loadRawConfigFile({
@@ -37927,7 +38558,7 @@ function readConfigForEmbedding(path, isProjectConfig) {
37927
38558
  isProjectConfig
37928
38559
  });
37929
38560
  const rejectedKeyPaths = [];
37930
- const parsed = sanitizeParsedJson(import_comment_json14.parse(substituted.text), {
38561
+ const parsed = sanitizeParsedJson(import_comment_json13.parse(substituted.text), {
37931
38562
  onRejectedKey: (keyPath) => rejectedKeyPaths.push(keyPath.join("."))
37932
38563
  });
37933
38564
  if (rejectedKeyPaths.length > 0) {
@@ -37998,22 +38629,22 @@ function pinnedVersionFromPackageSpecifier(specifier) {
37998
38629
  }
37999
38630
  function cacheRoots(cwd) {
38000
38631
  const home = process.env.HOME?.trim();
38001
- const cacheHome = process.env.XDG_CACHE_HOME || join32(home || homedir18(), ".cache");
38632
+ const cacheHome = process.env.XDG_CACHE_HOME || join33(home || homedir18(), ".cache");
38002
38633
  const piCacheRoot = getPiCacheRoot();
38003
38634
  return [
38004
- join32(piCacheRoot, "extensions"),
38005
- join32(piCacheRoot, "packages"),
38006
- join32(cacheHome, "pi", "extensions"),
38007
- join32(cacheHome, "pi", "packages"),
38008
- join32(getPiAgentConfigDir(), "cache", "extensions"),
38009
- join32(getPiAgentConfigDir(), "npm", "node_modules", PACKAGE_NAME2),
38010
- join32(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2)
38635
+ join33(piCacheRoot, "extensions"),
38636
+ join33(piCacheRoot, "packages"),
38637
+ join33(cacheHome, "pi", "extensions"),
38638
+ join33(cacheHome, "pi", "packages"),
38639
+ join33(getPiAgentConfigDir(), "cache", "extensions"),
38640
+ join33(getPiAgentConfigDir(), "npm", "node_modules", PACKAGE_NAME2),
38641
+ join33(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2)
38011
38642
  ];
38012
38643
  }
38013
38644
  function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
38014
38645
  const found = new Map;
38015
38646
  const visit = (path, depth) => {
38016
- if (depth < 0 || !existsSync33(path))
38647
+ if (depth < 0 || !existsSync34(path))
38017
38648
  return;
38018
38649
  let stat;
38019
38650
  try {
@@ -38023,10 +38654,10 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
38023
38654
  }
38024
38655
  if (!stat.isDirectory())
38025
38656
  return;
38026
- const packageJson = join32(path, "package.json");
38027
- if (existsSync33(packageJson)) {
38657
+ const packageJson = join33(path, "package.json");
38658
+ if (existsSync34(packageJson)) {
38028
38659
  try {
38029
- const pkg = JSON.parse(readFileSync25(packageJson, "utf-8"));
38660
+ const pkg = JSON.parse(readFileSync24(packageJson, "utf-8"));
38030
38661
  const name = typeof pkg.name === "string" ? pkg.name : "";
38031
38662
  const version = typeof pkg.version === "string" ? pkg.version : undefined;
38032
38663
  if (name === PACKAGE_NAME2) {
@@ -38046,7 +38677,7 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
38046
38677
  return;
38047
38678
  }
38048
38679
  for (const entry of entries)
38049
- visit(join32(path, entry), depth - 1);
38680
+ visit(join33(path, entry), depth - 1);
38050
38681
  };
38051
38682
  for (const root of cacheRoots(cwd))
38052
38683
  visit(root, 5);
@@ -38091,7 +38722,7 @@ async function runHealthChecks2(options) {
38091
38722
  }
38092
38723
  const settingsPath = getPiUserExtensionsPath();
38093
38724
  let packages = [];
38094
- if (!existsSync33(settingsPath)) {
38725
+ if (!existsSync34(settingsPath)) {
38095
38726
  add2(results, "fail", `Pi settings not found at ${settingsPath}`);
38096
38727
  repairPlan.addPackageEntry = true;
38097
38728
  } else {
@@ -38115,7 +38746,7 @@ async function runHealthChecks2(options) {
38115
38746
  ["user", userConfigPath, true],
38116
38747
  ["project", projectPath, false]
38117
38748
  ]) {
38118
- if (!existsSync33(path)) {
38749
+ if (!existsSync34(path)) {
38119
38750
  if (required) {
38120
38751
  add2(results, "warn", `No ${label} magic-context.jsonc found at ${path}`);
38121
38752
  if (userConfigMigrationRefused) {
@@ -38155,9 +38786,9 @@ async function runHealthChecks2(options) {
38155
38786
  }
38156
38787
  const storage = getMagicContextStorageResolution();
38157
38788
  const storageDir = storage.path;
38158
- const dbPath = join32(storageDir, "context.db");
38789
+ const dbPath = join33(storageDir, "context.db");
38159
38790
  add2(results, "info", `Shared storage: ${storageDir} (source: ${storage.source})`);
38160
- const existedBeforeOpen = existsSync33(dbPath);
38791
+ const existedBeforeOpen = existsSync34(dbPath);
38161
38792
  if (existedBeforeOpen)
38162
38793
  add2(results, "pass", `Shared context DB exists at ${dbPath}`);
38163
38794
  else
@@ -38303,16 +38934,16 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
38303
38934
  } else {
38304
38935
  add2(results, "pass", "Pi extension cache clean (no stale cached package found)");
38305
38936
  }
38306
- const logPath = getMagicContextLogPath2("pi");
38307
- if (existsSync33(logPath)) {
38308
- const stat = statSync16(logPath);
38309
- const sizeKb = (stat.size / 1024).toFixed(0);
38310
- const lines = readFileSync25(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
38311
- add2(results, "info", `Log file: ${logPath} (${sizeKb} KB)`);
38312
- const lastLine = lines.at(-1);
38313
- add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
38937
+ const logFiles = inspectMagicContextLogs("pi");
38938
+ const existingLogFiles = logFiles.filter((file) => file.exists);
38939
+ if (existingLogFiles.length === 0) {
38940
+ add2(results, "info", `No plugin log file yet; checked: ${logFiles.map((file) => file.path).join(", ")}`);
38314
38941
  } else {
38315
- add2(results, "info", `No plugin log file yet at ${logPath}`);
38942
+ for (const file of existingLogFiles) {
38943
+ add2(results, "info", `Log file read: ${formatLogFileInspection(file)}`);
38944
+ }
38945
+ const lastLine = readLogLines(existingLogFiles).at(-1);
38946
+ add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
38316
38947
  }
38317
38948
  const diagnosticsForDumps = await collectDiagnostics2(options.cwd);
38318
38949
  const dumpBuckets = diagnosticsForDumps.historianDumps.byProject;
@@ -38342,12 +38973,12 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
38342
38973
  return { results, repairPlan, ...summarize(results) };
38343
38974
  }
38344
38975
  function writeDefaultMagicContextConfig(path) {
38345
- mkdirSync10(dirname18(path), { recursive: true });
38976
+ mkdirSync11(dirname19(path), { recursive: true });
38346
38977
  const config = {
38347
38978
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
38348
38979
  ...MagicContextConfigSchema.parse({})
38349
38980
  };
38350
- writeFileAtomic(path, `${import_comment_json14.stringify(config, null, 2)}
38981
+ writeFileAtomic(path, `${import_comment_json13.stringify(config, null, 2)}
38351
38982
  `);
38352
38983
  }
38353
38984
  function repair2(plan, prompts) {
@@ -38364,7 +38995,7 @@ function repair2(plan, prompts) {
38364
38995
  }
38365
38996
  if (plan.writeUserConfig) {
38366
38997
  const configPath = getPiUserConfigPath();
38367
- if (!existsSync33(configPath)) {
38998
+ if (!existsSync34(configPath)) {
38368
38999
  try {
38369
39000
  writeDefaultMagicContextConfig(configPath);
38370
39001
  prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
@@ -38413,6 +39044,18 @@ function runGhCommandWithDeps2(deps, args) {
38413
39044
  }
38414
39045
  }
38415
39046
  async function runIssueFlow3(options) {
39047
+ if (options.reportPath) {
39048
+ try {
39049
+ const report = await options.deps.collectDiagnostics(options.cwd);
39050
+ const outputPath = isAbsolute6(options.reportPath) ? options.reportPath : join33(options.cwd, options.reportPath);
39051
+ const bundled = await bundleIssueReport2(report, "Generated non-interactively by `doctor --issue --report`.", "Magic Context diagnostic report", { cwd: options.cwd, now: options.deps.now(), outputPath });
39052
+ options.prompts.log.info(`Report written to ${bundled.path}`);
39053
+ return 0;
39054
+ } catch (error) {
39055
+ console.error(error instanceof Error ? error.message : String(error));
39056
+ return 1;
39057
+ }
39058
+ }
38416
39059
  options.prompts.intro("Magic Context for Pi Issue Report");
38417
39060
  const title = await options.prompts.text("Issue title", {
38418
39061
  placeholder: "Short summary of the Pi problem",
@@ -38482,13 +39125,13 @@ async function runDoctor3(options = {}) {
38482
39125
  }
38483
39126
  const configMigrationWarnings = migrateConfigLocationsForCli(cwd, prompts.log);
38484
39127
  if (options.issue) {
38485
- return runIssueFlow3({ cwd, prompts, deps });
39128
+ return runIssueFlow3({ cwd, prompts, deps, reportPath: options.report });
38486
39129
  }
38487
39130
  let v22Db = null;
38488
39131
  const v22Result = await runV22BackfillCommands({
38489
39132
  name: "Pi",
38490
39133
  openDatabase: (readonly = true) => {
38491
- const dbPath = join32(getMagicContextStorageDir(), "context.db");
39134
+ const dbPath = join33(getMagicContextStorageDir(), "context.db");
38492
39135
  v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
38493
39136
  return v22Db;
38494
39137
  },
@@ -38541,9 +39184,11 @@ function valueAfter3(args, flag) {
38541
39184
  }
38542
39185
  function parseDoctorArgs(args) {
38543
39186
  const rekeyV22DirIdentity = valueAfter3(args, "--rekey-v22-dir-identity");
39187
+ const report = valueAfter3(args, "--report");
38544
39188
  return {
38545
39189
  force: args.includes("--force"),
38546
- issue: args.includes("--issue"),
39190
+ issue: args.includes("--issue") || report !== null,
39191
+ ...report !== null ? { report } : {},
38547
39192
  help: args.includes("--help") || args.includes("-h"),
38548
39193
  checkV22Backfill: args.includes("--check-v22-backfill"),
38549
39194
  retryV22Backfill: args.includes("--retry-v22-backfill"),
@@ -38553,7 +39198,7 @@ function parseDoctorArgs(args) {
38553
39198
  function doctor(args = []) {
38554
39199
  return runDoctor3(parseDoctorArgs(args));
38555
39200
  }
38556
- var import_comment_json14, PACKAGE_NAME2 = "@cortexkit/pi-magic-context", MIN_PI_VERSION = "0.74.0", ROW_COUNT_TABLES2, DEFAULT_DEPS5;
39201
+ var import_comment_json13, PACKAGE_NAME2 = "@cortexkit/pi-magic-context", MIN_PI_VERSION = "0.74.0", ROW_COUNT_TABLES2, DEFAULT_DEPS5;
38557
39202
  var init_doctor_pi = __esm(async () => {
38558
39203
  init_migrate_config_location();
38559
39204
  init_project_security();
@@ -38568,6 +39213,7 @@ var init_doctor_pi = __esm(async () => {
38568
39213
  init_diagnostics_pi();
38569
39214
  init_embedding_runtime();
38570
39215
  init_github_issue();
39216
+ init_log_lines();
38571
39217
  init_logs_pi();
38572
39218
  init_paths();
38573
39219
  init_pi_helpers();
@@ -38580,7 +39226,7 @@ var init_doctor_pi = __esm(async () => {
38580
39226
  init_storage_versions(),
38581
39227
  init_v22_backfill_commands()
38582
39228
  ]);
38583
- import_comment_json14 = __toESM(require_src3(), 1);
39229
+ import_comment_json13 = __toESM(require_src3(), 1);
38584
39230
  ROW_COUNT_TABLES2 = ["tags", "compartments", "memories", "notes", "dream_runs"];
38585
39231
  DEFAULT_DEPS5 = {
38586
39232
  prompts: promptIO,
@@ -38598,8 +39244,8 @@ var init_doctor_pi = __esm(async () => {
38598
39244
  });
38599
39245
 
38600
39246
  // src/commands/doctor.ts
38601
- import { existsSync as existsSync34, rmSync as rmSync5 } from "node:fs";
38602
- import { join as join33 } from "node:path";
39247
+ import { existsSync as existsSync35, rmSync as rmSync5 } from "node:fs";
39248
+ import { join as join34 } from "node:path";
38603
39249
  async function runDoctor4(options) {
38604
39250
  if (options.clear)
38605
39251
  return runClear();
@@ -38617,7 +39263,7 @@ async function runDoctor4(options) {
38617
39263
  const result = await runV22BackfillCommands({
38618
39264
  name: "Magic Context",
38619
39265
  openDatabase: (readonly = true) => {
38620
- const dbPath = join33(getMagicContextStorageDir(), "context.db");
39266
+ const dbPath = join34(getMagicContextStorageDir(), "context.db");
38621
39267
  v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
38622
39268
  return v22Db;
38623
39269
  },
@@ -38631,7 +39277,7 @@ async function runDoctor4(options) {
38631
39277
  return result.exitCode;
38632
39278
  }
38633
39279
  await init_migrate();
38634
- const sweepDbPath = join33(getMagicContextStorageDir(), "context.db");
39280
+ const sweepDbPath = join34(getMagicContextStorageDir(), "context.db");
38635
39281
  let sweepDb = null;
38636
39282
  try {
38637
39283
  sweepDb = openExistingContextDatabaseForMutation(sweepDbPath);
@@ -38674,6 +39320,8 @@ async function dispatchDoctor(adapter, options) {
38674
39320
  piArgs.push("--force");
38675
39321
  if (options.issue)
38676
39322
  piArgs.push("--issue");
39323
+ if (options.report)
39324
+ piArgs.push("--report", options.report);
38677
39325
  return doctor(piArgs);
38678
39326
  }
38679
39327
  case "omp":
@@ -38727,7 +39375,7 @@ async function runClear() {
38727
39375
  const s = spinner2();
38728
39376
  s.start(`Clearing ${item.path}`);
38729
39377
  try {
38730
- if (existsSync34(item.path)) {
39378
+ if (existsSync35(item.path)) {
38731
39379
  rmSync5(item.path, { recursive: true, force: true });
38732
39380
  }
38733
39381
  s.stop(`Cleared ${item.path}`);
@@ -38823,6 +39471,7 @@ function printUsage() {
38823
39471
  console.log(" doctor Check and fix configuration issues");
38824
39472
  console.log(" doctor --force Force-clear plugin cache");
38825
39473
  console.log(" doctor --issue Collect diagnostics and open a GitHub issue");
39474
+ console.log(" doctor --issue --report <path> Write diagnostics without prompting");
38826
39475
  console.log(" doctor --clear Interactive cache cleanup picker");
38827
39476
  console.log(" doctor --check-v22-backfill Show v22 memory backfill status");
38828
39477
  console.log(" doctor --retry-v22-backfill Retry failed v22 memory backfill rows");
@@ -38898,9 +39547,11 @@ async function main(argv = process.argv.slice(2)) {
38898
39547
  }
38899
39548
  await init_doctor();
38900
39549
  const rekeyV22DirIdentity = valueAfter4(rest, "--rekey-v22-dir-identity");
39550
+ const report = valueAfter4(rest, "--report");
38901
39551
  return runDoctor4({
38902
39552
  force: rest.includes("--force"),
38903
- issue: rest.includes("--issue"),
39553
+ issue: rest.includes("--issue") || report !== null,
39554
+ ...report !== null ? { report } : {},
38904
39555
  clear: rest.includes("--clear"),
38905
39556
  checkV22Backfill: rest.includes("--check-v22-backfill"),
38906
39557
  retryV22Backfill: rest.includes("--retry-v22-backfill"),