opencode-matrixx 2.6.8 → 2.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4550,18 +4550,18 @@ __export(exports_storage, {
4550
4550
  readState: () => readState,
4551
4551
  writeState: () => writeState
4552
4552
  });
4553
- import { existsSync as existsSync35, mkdirSync as mkdirSync13, readFileSync as readFileSync28, unlinkSync as unlinkSync7, writeFileSync as writeFileSync15 } from "fs";
4554
- import { dirname as dirname9, join as join44 } from "path";
4553
+ import { existsSync as existsSync38, mkdirSync as mkdirSync14, readFileSync as readFileSync31, unlinkSync as unlinkSync8, writeFileSync as writeFileSync16 } from "fs";
4554
+ import { dirname as dirname9, join as join48 } from "path";
4555
4555
  function getStateFilePath(directory, customPath) {
4556
- return customPath ? join44(directory, customPath) : join44(directory, DEFAULT_STATE_FILE);
4556
+ return customPath ? join48(directory, customPath) : join48(directory, DEFAULT_STATE_FILE);
4557
4557
  }
4558
4558
  function readState(directory, customPath) {
4559
4559
  const filePath = getStateFilePath(directory, customPath);
4560
- if (!existsSync35(filePath)) {
4560
+ if (!existsSync38(filePath)) {
4561
4561
  return null;
4562
4562
  }
4563
4563
  try {
4564
- const content = readFileSync28(filePath, "utf-8");
4564
+ const content = readFileSync31(filePath, "utf-8");
4565
4565
  const { data, body } = parseFrontmatter(content);
4566
4566
  const active = data.active;
4567
4567
  const iteration = data.iteration;
@@ -4597,8 +4597,8 @@ function writeState(directory, state3, customPath) {
4597
4597
  const filePath = getStateFilePath(directory, customPath);
4598
4598
  try {
4599
4599
  const dir = dirname9(filePath);
4600
- if (!existsSync35(dir)) {
4601
- mkdirSync13(dir, { recursive: true });
4600
+ if (!existsSync38(dir)) {
4601
+ mkdirSync14(dir, { recursive: true });
4602
4602
  }
4603
4603
  const sessionIdLine = state3.session_id ? `session_id: "${state3.session_id}"
4604
4604
  ` : "";
@@ -4615,7 +4615,7 @@ started_at: "${state3.started_at}"
4615
4615
  ${sessionIdLine}${ultraworkLine}${verificationLine}---
4616
4616
  ${state3.prompt}
4617
4617
  `;
4618
- writeFileSync15(filePath, content, "utf-8");
4618
+ writeFileSync16(filePath, content, "utf-8");
4619
4619
  return true;
4620
4620
  } catch {
4621
4621
  return false;
@@ -4624,8 +4624,8 @@ ${state3.prompt}
4624
4624
  function clearState(directory, customPath) {
4625
4625
  const filePath = getStateFilePath(directory, customPath);
4626
4626
  try {
4627
- if (existsSync35(filePath)) {
4628
- unlinkSync7(filePath);
4627
+ if (existsSync38(filePath)) {
4628
+ unlinkSync8(filePath);
4629
4629
  }
4630
4630
  return true;
4631
4631
  } catch {
@@ -5645,8 +5645,8 @@ var require_semaphore = __commonJS(function(exports) {
5645
5645
  this._waiting = [];
5646
5646
  }
5647
5647
  lock(thunk) {
5648
- return new Promise((resolve7, reject) => {
5649
- this._waiting.push({ thunk, resolve: resolve7, reject });
5648
+ return new Promise((resolve6, reject) => {
5649
+ this._waiting.push({ thunk, resolve: resolve6, reject });
5650
5650
  this.runNext();
5651
5651
  });
5652
5652
  }
@@ -7137,9 +7137,9 @@ ${JSON.stringify(message, null, 4)}`);
7137
7137
  if (typeof cancellationStrategy.sender.enableCancellation === "function") {
7138
7138
  cancellationStrategy.sender.enableCancellation(requestMessage);
7139
7139
  }
7140
- return new Promise(async (resolve7, reject) => {
7140
+ return new Promise(async (resolve6, reject) => {
7141
7141
  const resolveWithCleanup = (r) => {
7142
- resolve7(r);
7142
+ resolve6(r);
7143
7143
  cancellationStrategy.sender.cleanup(id);
7144
7144
  disposable?.dispose();
7145
7145
  };
@@ -7548,10 +7548,10 @@ var require_ril = __commonJS(function(exports) {
7548
7548
  return api_1.Disposable.create(() => this.stream.off("end", listener));
7549
7549
  }
7550
7550
  write(data, encoding) {
7551
- return new Promise((resolve7, reject) => {
7551
+ return new Promise((resolve6, reject) => {
7552
7552
  const callback = (error51) => {
7553
7553
  if (error51 === undefined || error51 === null) {
7554
- resolve7();
7554
+ resolve6();
7555
7555
  } else {
7556
7556
  reject(error51);
7557
7557
  }
@@ -7810,10 +7810,10 @@ var require_main = __commonJS(function(exports) {
7810
7810
  exports.generateRandomPipeName = generateRandomPipeName;
7811
7811
  function createClientPipeTransport(pipeName, encoding = "utf-8") {
7812
7812
  let connectResolve;
7813
- const connected = new Promise((resolve7, _reject) => {
7814
- connectResolve = resolve7;
7813
+ const connected = new Promise((resolve6, _reject) => {
7814
+ connectResolve = resolve6;
7815
7815
  });
7816
- return new Promise((resolve7, reject) => {
7816
+ return new Promise((resolve6, reject) => {
7817
7817
  let server = (0, net_1.createServer)((socket) => {
7818
7818
  server.close();
7819
7819
  connectResolve([
@@ -7824,7 +7824,7 @@ var require_main = __commonJS(function(exports) {
7824
7824
  server.on("error", reject);
7825
7825
  server.listen(pipeName, () => {
7826
7826
  server.removeListener("error", reject);
7827
- resolve7({
7827
+ resolve6({
7828
7828
  onConnected: () => {
7829
7829
  return connected;
7830
7830
  }
@@ -7843,10 +7843,10 @@ var require_main = __commonJS(function(exports) {
7843
7843
  exports.createServerPipeTransport = createServerPipeTransport;
7844
7844
  function createClientSocketTransport(port, encoding = "utf-8") {
7845
7845
  let connectResolve;
7846
- const connected = new Promise((resolve7, _reject) => {
7847
- connectResolve = resolve7;
7846
+ const connected = new Promise((resolve6, _reject) => {
7847
+ connectResolve = resolve6;
7848
7848
  });
7849
- return new Promise((resolve7, reject) => {
7849
+ return new Promise((resolve6, reject) => {
7850
7850
  const server = (0, net_1.createServer)((socket) => {
7851
7851
  server.close();
7852
7852
  connectResolve([
@@ -7857,7 +7857,7 @@ var require_main = __commonJS(function(exports) {
7857
7857
  server.on("error", reject);
7858
7858
  server.listen(port, "127.0.0.1", () => {
7859
7859
  server.removeListener("error", reject);
7860
- resolve7({
7860
+ resolve6({
7861
7861
  onConnected: () => {
7862
7862
  return connected;
7863
7863
  }
@@ -16061,8 +16061,8 @@ var require_TransformOperationExecutor = __commonJS(function(exports) {
16061
16061
  return value;
16062
16062
  return Buffer.from(value);
16063
16063
  } else if ((0, utils_1.isPromise)(value) && !isMap) {
16064
- return new Promise((resolve9, reject) => {
16065
- value.then((data) => resolve9(this.transform(undefined, data, targetType, undefined, undefined, level + 1)), reject);
16064
+ return new Promise((resolve8, reject) => {
16065
+ value.then((data) => resolve8(this.transform(undefined, data, targetType, undefined, undefined, level + 1)), reject);
16066
16066
  });
16067
16067
  } else if (!isMap && value !== null && typeof value === "object" && typeof value.then === "function") {
16068
16068
  return value;
@@ -55027,7 +55027,7 @@ var DELEGATE_TASK_ERROR_PATTERNS = [
55027
55027
  {
55028
55028
  pattern: "Cannot call primary agent",
55029
55029
  errorType: "primary_agent",
55030
- fixHint: "Primary agents cannot be called via task. Use a subagent like 'explore', 'oracle', or 'librarian'"
55030
+ fixHint: "Primary agents cannot be called via task. Use a subagent like 'explore', 'oracle', or 'librarian'. For 'architect', use /start-work to run Architect as session agent"
55031
55031
  },
55032
55032
  {
55033
55033
  pattern: "Operation timed out",
@@ -55228,93 +55228,6 @@ ${originalText}`;
55228
55228
  }
55229
55229
  };
55230
55230
  }
55231
- // src/hooks/directory-injector/factory.ts
55232
- function createDirectoryInjectorHook(ctx, processFile, clearInjectedPaths) {
55233
- const sessionCaches = new Map;
55234
- const truncator = createDynamicTruncator(ctx);
55235
- const toolExecuteAfter = async (input, output) => {
55236
- const toolName = input.tool.toLowerCase();
55237
- if (toolName === "read") {
55238
- await processFile({
55239
- ctx,
55240
- truncator,
55241
- sessionCaches,
55242
- filePath: output.title,
55243
- sessionID: input.sessionID,
55244
- output
55245
- });
55246
- return;
55247
- }
55248
- };
55249
- const toolExecuteBefore = async (input, output) => {};
55250
- const eventHandler = async ({ event }) => {
55251
- const props = event.properties;
55252
- if (event.type === "session.deleted") {
55253
- const sessionInfo = props?.info;
55254
- if (sessionInfo?.id) {
55255
- sessionCaches.delete(sessionInfo.id);
55256
- clearInjectedPaths(sessionInfo.id);
55257
- }
55258
- }
55259
- if (event.type === "session.compacted") {
55260
- const sessionID = props?.sessionID ?? props?.info?.id;
55261
- if (sessionID) {
55262
- sessionCaches.delete(sessionID);
55263
- clearInjectedPaths(sessionID);
55264
- }
55265
- }
55266
- };
55267
- return {
55268
- "tool.execute.before": toolExecuteBefore,
55269
- "tool.execute.after": toolExecuteAfter,
55270
- event: eventHandler
55271
- };
55272
- }
55273
- // src/hooks/directory-agents-injector/injector.ts
55274
- import { readFile } from "fs/promises";
55275
- import { dirname as dirname7 } from "path";
55276
-
55277
- // src/hooks/directory-agents-injector/finder.ts
55278
- import { access } from "fs/promises";
55279
- import { dirname as dirname6, join as join38, resolve as resolve2 } from "path";
55280
-
55281
- // src/hooks/directory-agents-injector/constants.ts
55282
- import { join as join37 } from "path";
55283
- var AGENTS_INJECTOR_STORAGE = join37(OPENCODE_STORAGE, "directory-agents");
55284
- var AGENTS_FILENAME = "AGENTS.md";
55285
-
55286
- // src/hooks/directory-agents-injector/finder.ts
55287
- function resolveFilePath2(rootDirectory, path10) {
55288
- if (!path10)
55289
- return null;
55290
- if (path10.startsWith("/"))
55291
- return path10;
55292
- return resolve2(rootDirectory, path10);
55293
- }
55294
- async function findAgentsMdUp(input) {
55295
- const found = [];
55296
- let current = input.startDir;
55297
- while (true) {
55298
- const isRootDir = current === input.rootDir;
55299
- if (!isRootDir) {
55300
- const agentsPath = join38(current, AGENTS_FILENAME);
55301
- const exists = await access(agentsPath).then(() => true).catch(() => false);
55302
- if (exists) {
55303
- found.push(agentsPath);
55304
- }
55305
- }
55306
- if (isRootDir)
55307
- break;
55308
- const parent = dirname6(current);
55309
- if (parent === current)
55310
- break;
55311
- if (!parent.startsWith(input.rootDir))
55312
- break;
55313
- current = parent;
55314
- }
55315
- return found.reverse();
55316
- }
55317
-
55318
55231
  // src/shared/session-injected-paths.ts
55319
55232
  import {
55320
55233
  existsSync as existsSync32,
@@ -55323,9 +55236,9 @@ import {
55323
55236
  unlinkSync as unlinkSync4,
55324
55237
  writeFileSync as writeFileSync12
55325
55238
  } from "fs";
55326
- import { join as join39 } from "path";
55239
+ import { join as join37 } from "path";
55327
55240
  function createInjectedPathsStorage(storageDir) {
55328
- const getStoragePath2 = (sessionID) => join39(storageDir, `${sessionID}.json`);
55241
+ const getStoragePath2 = (sessionID) => join37(storageDir, `${sessionID}.json`);
55329
55242
  const loadInjectedPaths = (sessionID) => {
55330
55243
  const filePath = getStoragePath2(sessionID);
55331
55244
  if (!existsSync32(filePath))
@@ -55362,6 +55275,11 @@ function createInjectedPathsStorage(storageDir) {
55362
55275
  };
55363
55276
  }
55364
55277
 
55278
+ // src/hooks/directory-agents-injector/constants.ts
55279
+ import { join as join38 } from "path";
55280
+ var AGENTS_INJECTOR_STORAGE = join38(OPENCODE_STORAGE, "directory-agents");
55281
+ var AGENTS_FILENAME = "AGENTS.md";
55282
+
55365
55283
  // src/hooks/directory-agents-injector/storage.ts
55366
55284
  var {
55367
55285
  loadInjectedPaths,
@@ -55369,47 +55287,581 @@ var {
55369
55287
  clearInjectedPaths
55370
55288
  } = createInjectedPathsStorage(AGENTS_INJECTOR_STORAGE);
55371
55289
 
55372
- // src/hooks/directory-agents-injector/injector.ts
55373
- function getSessionCache(sessionCaches, sessionID) {
55374
- if (!sessionCaches.has(sessionID)) {
55375
- sessionCaches.set(sessionID, loadInjectedPaths(sessionID));
55290
+ // src/hooks/rules-injector/output-path.ts
55291
+ function getRuleInjectionFilePath(output) {
55292
+ const metadata = output.metadata;
55293
+ const metadataFilePath = metadata && typeof metadata === "object" ? metadata.filePath : undefined;
55294
+ if (typeof metadataFilePath === "string" && metadataFilePath.length > 0) {
55295
+ return metadataFilePath;
55376
55296
  }
55377
- return sessionCaches.get(sessionID);
55297
+ if (typeof output.title === "string" && output.title.length > 0) {
55298
+ return output.title;
55299
+ }
55300
+ return null;
55378
55301
  }
55379
- async function processFilePathForAgentsInjection(input) {
55380
- const resolved = resolveFilePath2(input.ctx.directory, input.filePath);
55381
- if (!resolved)
55382
- return;
55383
- const dir = dirname7(resolved);
55384
- const cache2 = getSessionCache(input.sessionCaches, input.sessionID);
55385
- const agentsPaths = await findAgentsMdUp({ startDir: dir, rootDir: input.ctx.directory });
55386
- let dirty = false;
55387
- for (const agentsPath of agentsPaths) {
55388
- const agentsDir = dirname7(agentsPath);
55389
- if (cache2.has(agentsDir))
55302
+
55303
+ // src/hooks/rules-injector/storage.ts
55304
+ import {
55305
+ existsSync as existsSync33,
55306
+ mkdirSync as mkdirSync10,
55307
+ readFileSync as readFileSync26,
55308
+ unlinkSync as unlinkSync5,
55309
+ writeFileSync as writeFileSync13
55310
+ } from "fs";
55311
+ import { join as join40 } from "path";
55312
+
55313
+ // src/hooks/rules-injector/constants.ts
55314
+ import { join as join39 } from "path";
55315
+ var RULES_INJECTOR_STORAGE = join39(OPENCODE_STORAGE, "rules-injector");
55316
+ var PROJECT_MARKERS = [
55317
+ ".git",
55318
+ "pyproject.toml",
55319
+ "package.json",
55320
+ "Cargo.toml",
55321
+ "go.mod",
55322
+ ".venv"
55323
+ ];
55324
+ var PROJECT_RULE_SUBDIRS = [
55325
+ [".github", "instructions"],
55326
+ [".cursor", "rules"],
55327
+ [".matrixx", "rules"]
55328
+ ];
55329
+ var PROJECT_RULE_FILES = [
55330
+ ".github/copilot-instructions.md"
55331
+ ];
55332
+ var GITHUB_INSTRUCTIONS_PATTERN = /\.instructions\.md$/;
55333
+ var RULE_EXTENSIONS = [".md", ".mdc"];
55334
+
55335
+ // src/hooks/rules-injector/storage.ts
55336
+ function getStoragePath2(sessionID) {
55337
+ return join40(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
55338
+ }
55339
+ function loadInjectedRules(sessionID) {
55340
+ const filePath = getStoragePath2(sessionID);
55341
+ if (!existsSync33(filePath))
55342
+ return { contentHashes: new Set, realPaths: new Set };
55343
+ try {
55344
+ const content = readFileSync26(filePath, "utf-8");
55345
+ const data = JSON.parse(content);
55346
+ return {
55347
+ contentHashes: new Set(data.injectedHashes),
55348
+ realPaths: new Set(data.injectedRealPaths ?? [])
55349
+ };
55350
+ } catch {
55351
+ return { contentHashes: new Set, realPaths: new Set };
55352
+ }
55353
+ }
55354
+ function saveInjectedRules(sessionID, data) {
55355
+ if (!existsSync33(RULES_INJECTOR_STORAGE)) {
55356
+ mkdirSync10(RULES_INJECTOR_STORAGE, { recursive: true });
55357
+ }
55358
+ const storageData = {
55359
+ sessionID,
55360
+ injectedHashes: [...data.contentHashes],
55361
+ injectedRealPaths: [...data.realPaths],
55362
+ updatedAt: Date.now()
55363
+ };
55364
+ writeFileSync13(getStoragePath2(sessionID), JSON.stringify(storageData, null, 2));
55365
+ }
55366
+ function clearInjectedRules(sessionID) {
55367
+ const filePath = getStoragePath2(sessionID);
55368
+ if (existsSync33(filePath)) {
55369
+ unlinkSync5(filePath);
55370
+ }
55371
+ }
55372
+
55373
+ // src/hooks/post-read-injector/injector.ts
55374
+ import { readFileSync as readFileSync28 } from "fs";
55375
+ import { join as join43, relative as relative2, resolve as resolve2 } from "path";
55376
+
55377
+ // src/hooks/rules-injector/matcher.ts
55378
+ var import_picomatch = __toESM(require_picomatch2(), 1);
55379
+ import { createHash } from "crypto";
55380
+ import { relative } from "path";
55381
+ function shouldApplyRule(metadata, currentFilePath, projectRoot) {
55382
+ if (metadata.alwaysApply === true) {
55383
+ return { applies: true, reason: "alwaysApply" };
55384
+ }
55385
+ const globs = metadata.globs;
55386
+ if (!globs) {
55387
+ return { applies: false };
55388
+ }
55389
+ const patterns = Array.isArray(globs) ? globs : [globs];
55390
+ if (patterns.length === 0) {
55391
+ return { applies: false };
55392
+ }
55393
+ const relativePath = projectRoot ? relative(projectRoot, currentFilePath) : currentFilePath;
55394
+ for (const pattern of patterns) {
55395
+ if (import_picomatch.default.isMatch(relativePath, pattern, { dot: true, bash: true })) {
55396
+ return { applies: true, reason: `glob: ${pattern}` };
55397
+ }
55398
+ }
55399
+ return { applies: false };
55400
+ }
55401
+ function isDuplicateByRealPath(realPath, cache2) {
55402
+ return cache2.has(realPath);
55403
+ }
55404
+ function createContentHash(content) {
55405
+ return createHash("sha256").update(content).digest("hex").slice(0, 16);
55406
+ }
55407
+ function isDuplicateByContentHash(hash2, cache2) {
55408
+ return cache2.has(hash2);
55409
+ }
55410
+
55411
+ // src/hooks/rules-injector/parser.ts
55412
+ function parseRuleFrontmatter(content) {
55413
+ const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
55414
+ const match = content.match(frontmatterRegex);
55415
+ if (!match) {
55416
+ return { metadata: {}, body: content };
55417
+ }
55418
+ const yamlContent = match[1];
55419
+ const body = match[2];
55420
+ try {
55421
+ const metadata = parseYamlContent(yamlContent);
55422
+ return { metadata, body };
55423
+ } catch {
55424
+ return { metadata: {}, body: content };
55425
+ }
55426
+ }
55427
+ function parseYamlContent(yamlContent) {
55428
+ const lines = yamlContent.split(`
55429
+ `);
55430
+ const metadata = {};
55431
+ let i = 0;
55432
+ while (i < lines.length) {
55433
+ const line = lines[i];
55434
+ const colonIndex = line.indexOf(":");
55435
+ if (colonIndex === -1) {
55436
+ i++;
55390
55437
  continue;
55391
- try {
55392
- const content = await readFile(agentsPath, "utf-8");
55393
- const { result, truncated } = await input.truncator.truncate(input.sessionID, content);
55394
- const truncationNotice = truncated ? `
55438
+ }
55439
+ const key = line.slice(0, colonIndex).trim();
55440
+ const rawValue = line.slice(colonIndex + 1).trim();
55441
+ if (key === "description") {
55442
+ metadata.description = parseStringValue(rawValue);
55443
+ } else if (key === "alwaysApply") {
55444
+ metadata.alwaysApply = rawValue === "true";
55445
+ } else if (key === "globs" || key === "applyTo") {
55446
+ const { value, consumed } = parseArrayOrStringValue(rawValue, lines, i);
55447
+ metadata.globs = mergeGlobs(metadata.globs, value);
55448
+ i += consumed;
55449
+ continue;
55450
+ }
55451
+ i++;
55452
+ }
55453
+ return metadata;
55454
+ }
55455
+ function parseStringValue(value) {
55456
+ if (!value)
55457
+ return "";
55458
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
55459
+ return value.slice(1, -1);
55460
+ }
55461
+ return value;
55462
+ }
55463
+ function parseArrayOrStringValue(rawValue, lines, currentIndex) {
55464
+ if (rawValue.startsWith("[")) {
55465
+ return { value: parseInlineArray(rawValue), consumed: 1 };
55466
+ }
55467
+ if (!rawValue || rawValue === "") {
55468
+ const arrayItems = [];
55469
+ let consumed = 1;
55470
+ for (let j = currentIndex + 1;j < lines.length; j++) {
55471
+ const nextLine = lines[j];
55472
+ const arrayMatch = nextLine.match(/^\s+-\s*(.*)$/);
55473
+ if (arrayMatch) {
55474
+ const itemValue = parseStringValue(arrayMatch[1].trim());
55475
+ if (itemValue) {
55476
+ arrayItems.push(itemValue);
55477
+ }
55478
+ consumed++;
55479
+ } else if (nextLine.trim() === "") {
55480
+ consumed++;
55481
+ } else {
55482
+ break;
55483
+ }
55484
+ }
55485
+ if (arrayItems.length > 0) {
55486
+ return { value: arrayItems, consumed };
55487
+ }
55488
+ }
55489
+ const stringValue = parseStringValue(rawValue);
55490
+ if (stringValue.includes(",")) {
55491
+ const items = stringValue.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
55492
+ return { value: items, consumed: 1 };
55493
+ }
55494
+ return { value: stringValue, consumed: 1 };
55495
+ }
55496
+ function parseInlineArray(value) {
55497
+ const content = value.slice(1, value.lastIndexOf("]")).trim();
55498
+ if (!content)
55499
+ return [];
55500
+ const items = [];
55501
+ let current = "";
55502
+ let inQuote = false;
55503
+ let quoteChar = "";
55504
+ for (let i = 0;i < content.length; i++) {
55505
+ const char = content[i];
55506
+ if (!inQuote && (char === '"' || char === "'")) {
55507
+ inQuote = true;
55508
+ quoteChar = char;
55509
+ } else if (inQuote && char === quoteChar) {
55510
+ inQuote = false;
55511
+ quoteChar = "";
55512
+ } else if (!inQuote && char === ",") {
55513
+ const trimmed2 = current.trim();
55514
+ if (trimmed2) {
55515
+ items.push(parseStringValue(trimmed2));
55516
+ }
55517
+ current = "";
55518
+ } else {
55519
+ current += char;
55520
+ }
55521
+ }
55522
+ const trimmed = current.trim();
55523
+ if (trimmed) {
55524
+ items.push(parseStringValue(trimmed));
55525
+ }
55526
+ return items;
55527
+ }
55528
+ function mergeGlobs(existing, newValue) {
55529
+ if (!existing)
55530
+ return newValue;
55531
+ const existingArray = Array.isArray(existing) ? existing : [existing];
55532
+ const newArray = Array.isArray(newValue) ? newValue : [newValue];
55533
+ return [...existingArray, ...newArray];
55534
+ }
55535
+
55536
+ // src/hooks/rules-injector/project-root-finder.ts
55537
+ import { existsSync as existsSync34, statSync as statSync4 } from "fs";
55538
+ import { dirname as dirname6, join as join41 } from "path";
55539
+ function findProjectRoot(startPath) {
55540
+ let current;
55541
+ try {
55542
+ const stat = statSync4(startPath);
55543
+ current = stat.isDirectory() ? startPath : dirname6(startPath);
55544
+ } catch {
55545
+ current = dirname6(startPath);
55546
+ }
55547
+ while (true) {
55548
+ for (const marker of PROJECT_MARKERS) {
55549
+ const markerPath = join41(current, marker);
55550
+ if (existsSync34(markerPath)) {
55551
+ return current;
55552
+ }
55553
+ }
55554
+ const parent = dirname6(current);
55555
+ if (parent === current) {
55556
+ return null;
55557
+ }
55558
+ current = parent;
55559
+ }
55560
+ }
55561
+
55562
+ // src/hooks/rules-injector/rule-file-scanner.ts
55563
+ import { existsSync as existsSync35, readdirSync as readdirSync11, realpathSync as realpathSync2 } from "fs";
55564
+ import { join as join42 } from "path";
55565
+ function isGitHubInstructionsDir(dir) {
55566
+ return dir.includes(".github/instructions") || dir.endsWith(".github/instructions");
55567
+ }
55568
+ function isValidRuleFile(fileName, dir) {
55569
+ if (isGitHubInstructionsDir(dir)) {
55570
+ return GITHUB_INSTRUCTIONS_PATTERN.test(fileName);
55571
+ }
55572
+ return RULE_EXTENSIONS.some((ext) => fileName.endsWith(ext));
55573
+ }
55574
+ function findRuleFilesRecursive(dir, results) {
55575
+ if (!existsSync35(dir))
55576
+ return;
55577
+ try {
55578
+ const entries = readdirSync11(dir, { withFileTypes: true });
55579
+ for (const entry of entries) {
55580
+ const fullPath = join42(dir, entry.name);
55581
+ if (entry.isDirectory()) {
55582
+ findRuleFilesRecursive(fullPath, results);
55583
+ } else if (entry.isFile()) {
55584
+ if (isValidRuleFile(entry.name, dir)) {
55585
+ results.push(fullPath);
55586
+ }
55587
+ }
55588
+ }
55589
+ } catch {}
55590
+ }
55591
+ function safeRealpathSync(filePath) {
55592
+ try {
55593
+ return realpathSync2(filePath);
55594
+ } catch {
55595
+ return filePath;
55596
+ }
55597
+ }
55598
+
55599
+ // src/hooks/post-read-injector/constants.ts
55600
+ var MAX_DIRECTORY_CONTEXT_BYTES = 6144;
55601
+ var DIRECTORY_CONTEXT_HEADER = "Directory Context";
55602
+ var DIRECTORY_CONTEXT_SEPARATOR = `
55603
+ ---
55604
+ `;
55605
+ function buildTruncationMarker(omittedChars) {
55606
+ return `
55607
+ [${DIRECTORY_CONTEXT_HEADER} truncated: ${omittedChars} chars omitted]`;
55608
+ }
55609
+
55610
+ // src/hooks/post-read-injector/block.ts
55611
+ function buildDirectoryContextBlock(sections) {
55612
+ const header = `
55613
+
55614
+ [${DIRECTORY_CONTEXT_HEADER}]
55615
+ `;
55616
+ const fullBody = sections.join(DIRECTORY_CONTEXT_SEPARATOR);
55617
+ const full = `${header}${fullBody}`;
55618
+ if (full.length <= MAX_DIRECTORY_CONTEXT_BYTES)
55619
+ return full;
55620
+ const probeMarker = buildTruncationMarker(fullBody.length);
55621
+ const allowedBody = MAX_DIRECTORY_CONTEXT_BYTES - header.length - probeMarker.length;
55622
+ const sliced = fullBody.slice(0, Math.max(0, allowedBody));
55623
+ const omitted = fullBody.length - sliced.length;
55624
+ const marker = buildTruncationMarker(omitted);
55625
+ const block = `${header}${sliced}${marker}`;
55626
+ if (block.length <= MAX_DIRECTORY_CONTEXT_BYTES)
55627
+ return block;
55628
+ const overflow = block.length - MAX_DIRECTORY_CONTEXT_BYTES;
55629
+ return `${header}${sliced.slice(0, Math.max(0, sliced.length - overflow))}${marker}`;
55630
+ }
55631
+
55632
+ // src/hooks/post-read-injector/sections.ts
55633
+ import { readFileSync as readFileSync27 } from "fs";
55634
+ import { access, readFile } from "fs/promises";
55635
+ async function readAgentsSection(agentsPath, sessionID, truncator) {
55636
+ const exists = await access(agentsPath).then(() => true).catch(() => false);
55637
+ if (!exists)
55638
+ return null;
55639
+ try {
55640
+ const content = await readFile(agentsPath, "utf-8");
55641
+ const { result, truncated } = await truncator.truncate(sessionID, content);
55642
+ const notice = truncated ? `
55395
55643
 
55396
55644
  [Note: Content was truncated to save context window space. For full context, please read the file directly: ${agentsPath}]` : "";
55397
- input.output.output += `
55645
+ return `[Directory Context: ${agentsPath}]
55646
+ ${result}${notice}`;
55647
+ } catch {
55648
+ return null;
55649
+ }
55650
+ }
55651
+ async function readRuleSection(candidate, rel, reason, sessionID, truncator, rulesCache) {
55652
+ try {
55653
+ const raw = readFileSync27(candidate, "utf-8");
55654
+ const { body } = parseRuleFrontmatter(raw);
55655
+ const hash2 = createContentHash(body);
55656
+ if (isDuplicateByContentHash(hash2, rulesCache.contentHashes))
55657
+ return null;
55658
+ const { result, truncated } = await truncator.truncate(sessionID, body);
55659
+ const notice = truncated ? `
55660
+
55661
+ [Note: Content was truncated to save context window space. For full context, please read the file directly: ${rel}]` : "";
55662
+ rulesCache.contentHashes.add(hash2);
55663
+ return `[Rule: ${rel}]
55664
+ [Match: ${reason}]
55665
+ ${result}${notice}`;
55666
+ } catch {
55667
+ return null;
55668
+ }
55669
+ }
55398
55670
 
55399
- [Directory Context: ${agentsPath}]
55400
- ${result}${truncationNotice}`;
55401
- cache2.add(agentsDir);
55402
- dirty = true;
55403
- } catch {}
55671
+ // src/hooks/post-read-injector/unified-walk.ts
55672
+ import { dirname as dirname7 } from "path";
55673
+ function normalize(dir) {
55674
+ return dir.endsWith("/") && dir.length > 1 ? dir.slice(0, -1) : dir;
55675
+ }
55676
+ function collectAncestorDirs(filePath, rootDir, projectRoot, onVisit) {
55677
+ let visit2;
55678
+ if (typeof rootDir === "function")
55679
+ visit2 = rootDir;
55680
+ else if (typeof projectRoot === "function")
55681
+ visit2 = projectRoot;
55682
+ if (typeof onVisit === "function")
55683
+ visit2 = onVisit;
55684
+ let current;
55685
+ try {
55686
+ current = normalize(dirname7(filePath));
55687
+ } catch {
55688
+ return [];
55404
55689
  }
55405
- if (dirty) {
55406
- saveInjectedPaths(input.sessionID, cache2);
55690
+ const dirs = [];
55691
+ const seen = new Set;
55692
+ while (true) {
55693
+ if (!seen.has(current)) {
55694
+ seen.add(current);
55695
+ dirs.push(current);
55696
+ visit2?.(current);
55697
+ }
55698
+ const parent = normalize(dirname7(current));
55699
+ if (parent === current)
55700
+ break;
55701
+ current = parent;
55407
55702
  }
55703
+ return dirs;
55704
+ }
55705
+
55706
+ // src/hooks/post-read-injector/injector.ts
55707
+ function resolveUnifiedFilePath(rootDirectory, filePath) {
55708
+ if (!filePath)
55709
+ return null;
55710
+ if (filePath.startsWith("/"))
55711
+ return filePath;
55712
+ return resolve2(rootDirectory, filePath);
55713
+ }
55714
+ function createUnifiedPostReadProcessor(deps) {
55715
+ const { workspaceDirectory, truncator, onVisitDir } = deps;
55716
+ const agentsCaches = new Map;
55717
+ const rulesCaches = new Map;
55718
+ function getAgentsCache(sessionID) {
55719
+ let cache2 = agentsCaches.get(sessionID);
55720
+ if (!cache2) {
55721
+ cache2 = loadInjectedPaths(sessionID);
55722
+ agentsCaches.set(sessionID, cache2);
55723
+ }
55724
+ return cache2;
55725
+ }
55726
+ function getRulesCache(sessionID) {
55727
+ let cache2 = rulesCaches.get(sessionID);
55728
+ if (!cache2) {
55729
+ cache2 = loadInjectedRules(sessionID);
55730
+ rulesCaches.set(sessionID, cache2);
55731
+ }
55732
+ return cache2;
55733
+ }
55734
+ function clearSessionCache(sessionID) {
55735
+ agentsCaches.delete(sessionID);
55736
+ rulesCaches.delete(sessionID);
55737
+ }
55738
+ async function processFilePathForInjection(filePath, sessionID, output) {
55739
+ if (output.output.includes(`[${DIRECTORY_CONTEXT_HEADER}]`))
55740
+ return;
55741
+ const resolved = resolveUnifiedFilePath(workspaceDirectory, filePath);
55742
+ if (!resolved)
55743
+ return;
55744
+ const projectRoot = findProjectRoot(resolved);
55745
+ const agentsCache = getAgentsCache(sessionID);
55746
+ const rulesCache = getRulesCache(sessionID);
55747
+ const dirs = collectAncestorDirs(resolved, workspaceDirectory, projectRoot, onVisitDir);
55748
+ const sections = [];
55749
+ const seenRulePaths = new Set;
55750
+ let agentsDirty = false;
55751
+ let rulesDirty = false;
55752
+ for (const dir of dirs) {
55753
+ if (dir !== workspaceDirectory && (dir === workspaceDirectory || dir.startsWith(`${workspaceDirectory}/`))) {
55754
+ if (!agentsCache.has(dir)) {
55755
+ const section = await readAgentsSection(join43(dir, AGENTS_FILENAME), sessionID, truncator);
55756
+ if (section) {
55757
+ sections.push(section);
55758
+ agentsCache.add(dir);
55759
+ agentsDirty = true;
55760
+ }
55761
+ }
55762
+ }
55763
+ const inScope = !projectRoot || dir === projectRoot || dir.startsWith(`${projectRoot}/`) || projectRoot.startsWith(`${dir}/`);
55764
+ if (!inScope)
55765
+ continue;
55766
+ for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
55767
+ const files = [];
55768
+ findRuleFilesRecursive(join43(dir, parent, subdir), files);
55769
+ for (const candidate of files) {
55770
+ const realPath = safeRealpathSync(candidate);
55771
+ if (seenRulePaths.has(realPath))
55772
+ continue;
55773
+ seenRulePaths.add(realPath);
55774
+ if (isDuplicateByRealPath(realPath, rulesCache.realPaths))
55775
+ continue;
55776
+ const { metadata } = parseRuleFrontmatter(readFileSync28(candidate, "utf-8"));
55777
+ const match = shouldApplyRule(metadata, resolved, projectRoot);
55778
+ if (!match.applies)
55779
+ continue;
55780
+ const rel = projectRoot ? relative2(projectRoot, candidate) : candidate;
55781
+ const section = await readRuleSection(candidate, rel, match.reason ?? "matched", sessionID, truncator, rulesCache);
55782
+ if (section) {
55783
+ sections.push(section);
55784
+ rulesCache.realPaths.add(realPath);
55785
+ rulesDirty = true;
55786
+ }
55787
+ }
55788
+ }
55789
+ if (projectRoot && dir === projectRoot) {
55790
+ for (const single of PROJECT_RULE_FILES) {
55791
+ const candidate = join43(projectRoot, single);
55792
+ const realPath = safeRealpathSync(candidate);
55793
+ if (seenRulePaths.has(realPath))
55794
+ continue;
55795
+ seenRulePaths.add(realPath);
55796
+ if (isDuplicateByRealPath(realPath, rulesCache.realPaths))
55797
+ continue;
55798
+ const section = await readRuleSection(candidate, single, "copilot-instructions (always apply)", sessionID, truncator, rulesCache);
55799
+ if (section) {
55800
+ sections.push(section);
55801
+ rulesCache.realPaths.add(realPath);
55802
+ rulesDirty = true;
55803
+ }
55804
+ }
55805
+ }
55806
+ }
55807
+ if (sections.length === 0)
55808
+ return;
55809
+ output.output += buildDirectoryContextBlock(sections);
55810
+ if (agentsDirty)
55811
+ saveInjectedPaths(sessionID, agentsCache);
55812
+ if (rulesDirty)
55813
+ saveInjectedRules(sessionID, rulesCache);
55814
+ }
55815
+ return { processFilePathForInjection, clearSessionCache };
55816
+ }
55817
+
55818
+ // src/hooks/post-read-injector/hook.ts
55819
+ var DEFAULT_TRACKED_TOOLS = ["read", "write", "edit", "multiedit"];
55820
+ function createPostReadInjectorHook(ctx, options) {
55821
+ const truncator = createDynamicTruncator(ctx);
55822
+ const { processFilePathForInjection, clearSessionCache } = createUnifiedPostReadProcessor({
55823
+ workspaceDirectory: ctx.directory,
55824
+ truncator
55825
+ });
55826
+ const tracked = (options?.trackedTools ?? DEFAULT_TRACKED_TOOLS).map((tool) => tool.toLowerCase());
55827
+ const toolExecuteAfter = async (input, output) => {
55828
+ if (!tracked.includes(input.tool.toLowerCase()))
55829
+ return;
55830
+ const filePath = getRuleInjectionFilePath({ title: output.title, metadata: output.metadata });
55831
+ if (!filePath)
55832
+ return;
55833
+ await processFilePathForInjection(filePath, input.sessionID, output);
55834
+ };
55835
+ const toolExecuteBefore = async (input, output) => {};
55836
+ const eventHandler = async ({ event }) => {
55837
+ const props = event.properties;
55838
+ if (event.type === "session.deleted") {
55839
+ const info = props?.info;
55840
+ if (info?.id) {
55841
+ clearSessionCache(info.id);
55842
+ clearInjectedPaths(info.id);
55843
+ clearInjectedRules(info.id);
55844
+ }
55845
+ }
55846
+ if (event.type === "session.compacted") {
55847
+ const sessionID = props?.sessionID ?? props?.info?.id;
55848
+ if (sessionID) {
55849
+ clearSessionCache(sessionID);
55850
+ clearInjectedPaths(sessionID);
55851
+ clearInjectedRules(sessionID);
55852
+ }
55853
+ }
55854
+ };
55855
+ return {
55856
+ "tool.execute.before": toolExecuteBefore,
55857
+ "tool.execute.after": toolExecuteAfter,
55858
+ event: eventHandler
55859
+ };
55408
55860
  }
55409
55861
 
55410
55862
  // src/hooks/directory-agents-injector/hook.ts
55411
55863
  function createDirectoryAgentsInjectorHook(ctx) {
55412
- return createDirectoryInjectorHook(ctx, processFilePathForAgentsInjection, clearInjectedPaths);
55864
+ return createPostReadInjectorHook(ctx, { trackedTools: ["read"] });
55413
55865
  }
55414
55866
  // src/hooks/edit-error-recovery/hook.ts
55415
55867
  var EDIT_ERROR_PATTERNS = [
@@ -55531,7 +55983,7 @@ ${envContext}`;
55531
55983
  };
55532
55984
  }
55533
55985
  // src/hooks/env-file-write-guard/sensitive-file-matcher.ts
55534
- var import_picomatch = __toESM(require_picomatch2(), 1);
55986
+ var import_picomatch2 = __toESM(require_picomatch2(), 1);
55535
55987
  import { basename as basename3 } from "path";
55536
55988
  var DEFAULT_BLOCKED_PATTERNS = [
55537
55989
  ".env",
@@ -55551,7 +56003,7 @@ var DEFAULT_BLOCKED_PATTERNS = [
55551
56003
  ];
55552
56004
  function createSensitiveFileMatcher(blockedPatterns, allowedPaths) {
55553
56005
  const patterns = blockedPatterns ?? DEFAULT_BLOCKED_PATTERNS;
55554
- const isBlocked = import_picomatch.default(patterns, { dot: true, bash: true });
56006
+ const isBlocked = import_picomatch2.default(patterns, { dot: true, bash: true });
55555
56007
  const allowSet = new Set(allowedPaths ?? []);
55556
56008
  return function isSensitiveFile(filePath) {
55557
56009
  if (allowSet.has(filePath))
@@ -58864,8 +59316,8 @@ ${originalText}`;
58864
59316
  init_logger();
58865
59317
 
58866
59318
  // src/hooks/interactive-bash-session/constants.ts
58867
- import { join as join42 } from "path";
58868
- var INTERACTIVE_BASH_SESSION_STORAGE = join42(OPENCODE_STORAGE, "interactive-bash-session");
59319
+ import { join as join46 } from "path";
59320
+ var INTERACTIVE_BASH_SESSION_STORAGE = join46(OPENCODE_STORAGE, "interactive-bash-session");
58869
59321
  var MATRIXX_SESSION_PREFIX = "matrixx-";
58870
59322
  function buildSessionReminderMessage(sessions) {
58871
59323
  if (sessions.length === 0)
@@ -58960,22 +59412,22 @@ function findSubcommand(tokens) {
58960
59412
 
58961
59413
  // src/hooks/interactive-bash-session/storage.ts
58962
59414
  import {
58963
- existsSync as existsSync34,
58964
- mkdirSync as mkdirSync12,
58965
- readFileSync as readFileSync27,
58966
- unlinkSync as unlinkSync6,
58967
- writeFileSync as writeFileSync14
59415
+ existsSync as existsSync37,
59416
+ mkdirSync as mkdirSync13,
59417
+ readFileSync as readFileSync30,
59418
+ unlinkSync as unlinkSync7,
59419
+ writeFileSync as writeFileSync15
58968
59420
  } from "fs";
58969
- import { join as join43 } from "path";
58970
- function getStoragePath2(sessionID) {
58971
- return join43(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
59421
+ import { join as join47 } from "path";
59422
+ function getStoragePath3(sessionID) {
59423
+ return join47(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
58972
59424
  }
58973
59425
  function loadInteractiveBashSessionState(sessionID) {
58974
- const filePath = getStoragePath2(sessionID);
58975
- if (!existsSync34(filePath))
59426
+ const filePath = getStoragePath3(sessionID);
59427
+ if (!existsSync37(filePath))
58976
59428
  return null;
58977
59429
  try {
58978
- const content = readFileSync27(filePath, "utf-8");
59430
+ const content = readFileSync30(filePath, "utf-8");
58979
59431
  const serialized = JSON.parse(content);
58980
59432
  return {
58981
59433
  sessionID: serialized.sessionID,
@@ -58987,21 +59439,21 @@ function loadInteractiveBashSessionState(sessionID) {
58987
59439
  }
58988
59440
  }
58989
59441
  function saveInteractiveBashSessionState(state3) {
58990
- if (!existsSync34(INTERACTIVE_BASH_SESSION_STORAGE)) {
58991
- mkdirSync12(INTERACTIVE_BASH_SESSION_STORAGE, { recursive: true });
59442
+ if (!existsSync37(INTERACTIVE_BASH_SESSION_STORAGE)) {
59443
+ mkdirSync13(INTERACTIVE_BASH_SESSION_STORAGE, { recursive: true });
58992
59444
  }
58993
- const filePath = getStoragePath2(state3.sessionID);
59445
+ const filePath = getStoragePath3(state3.sessionID);
58994
59446
  const serialized = {
58995
59447
  sessionID: state3.sessionID,
58996
59448
  tmuxSessions: Array.from(state3.tmuxSessions),
58997
59449
  updatedAt: state3.updatedAt
58998
59450
  };
58999
- writeFileSync14(filePath, JSON.stringify(serialized, null, 2));
59451
+ writeFileSync15(filePath, JSON.stringify(serialized, null, 2));
59000
59452
  }
59001
59453
  function clearInteractiveBashSessionState(sessionID) {
59002
- const filePath = getStoragePath2(sessionID);
59003
- if (existsSync34(filePath)) {
59004
- unlinkSync6(filePath);
59454
+ const filePath = getStoragePath3(sessionID);
59455
+ if (existsSync37(filePath)) {
59456
+ unlinkSync7(filePath);
59005
59457
  }
59006
59458
  }
59007
59459
 
@@ -59344,7 +59796,7 @@ init_logger();
59344
59796
 
59345
59797
  // src/hooks/matrix-loop/completion-promise-detector.ts
59346
59798
  init_logger();
59347
- import { existsSync as existsSync36, readFileSync as readFileSync29 } from "fs";
59799
+ import { existsSync as existsSync39, readFileSync as readFileSync32 } from "fs";
59348
59800
  function escapeRegex2(str) {
59349
59801
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
59350
59802
  }
@@ -59355,9 +59807,9 @@ function detectCompletionInTranscript(transcriptPath, promise2) {
59355
59807
  if (!transcriptPath)
59356
59808
  return false;
59357
59809
  try {
59358
- if (!existsSync36(transcriptPath))
59810
+ if (!existsSync39(transcriptPath))
59359
59811
  return false;
59360
- const content = readFileSync29(transcriptPath, "utf-8");
59812
+ const content = readFileSync32(transcriptPath, "utf-8");
59361
59813
  const pattern = buildPromisePattern(promise2);
59362
59814
  const lines = content.split(`
59363
59815
  `).filter((line) => line.trim());
@@ -60063,10 +60515,10 @@ async function getAgentFromSession(sessionID, directory, client) {
60063
60515
  }
60064
60516
 
60065
60517
  // src/hooks/oracle-md-only/path-policy.ts
60066
- import { isAbsolute as isAbsolute2, relative, resolve as resolve4 } from "path";
60518
+ import { isAbsolute as isAbsolute2, relative as relative3, resolve as resolve4 } from "path";
60067
60519
  function isAllowedFile(filePath, workspaceRoot) {
60068
60520
  const resolved = resolve4(workspaceRoot, filePath);
60069
- const rel = relative(workspaceRoot, resolved);
60521
+ const rel = relative3(workspaceRoot, resolved);
60070
60522
  if (rel.startsWith("..") || isAbsolute2(rel)) {
60071
60523
  return false;
60072
60524
  }
@@ -60138,13 +60590,13 @@ function createOracleMdOnlyHook(ctx) {
60138
60590
  };
60139
60591
  }
60140
60592
  // src/hooks/plan-persister/hook.ts
60141
- import { existsSync as existsSync38, readdirSync as readdirSync12 } from "fs";
60593
+ import { existsSync as existsSync41, readdirSync as readdirSync13 } from "fs";
60142
60594
 
60143
60595
  // src/features/task-storage/storage.ts
60144
60596
  init_logger();
60145
60597
  import { randomUUID } from "crypto";
60146
- import { existsSync as existsSync37, mkdirSync as mkdirSync14, readdirSync as readdirSync11, readFileSync as readFileSync30, renameSync as renameSync3, unlinkSync as unlinkSync8, writeFileSync as writeFileSync16 } from "fs";
60147
- import { basename as basename5, dirname as dirname10, isAbsolute as isAbsolute3, join as join45 } from "path";
60598
+ import { existsSync as existsSync40, mkdirSync as mkdirSync15, readdirSync as readdirSync12, readFileSync as readFileSync33, renameSync as renameSync3, unlinkSync as unlinkSync9, writeFileSync as writeFileSync17 } from "fs";
60599
+ import { basename as basename5, dirname as dirname10, isAbsolute as isAbsolute3, join as join49 } from "path";
60148
60600
 
60149
60601
  // src/shared/task-system-gating.ts
60150
60602
  var TASK_SYSTEM_DEFAULT = true;
@@ -60168,18 +60620,18 @@ function isTaskSystemEnabled(config2) {
60168
60620
 
60169
60621
  // src/features/task-storage/storage.ts
60170
60622
  function getProjectTaskDir(directory) {
60171
- return join45(directory, ".matrixx", "tasks");
60623
+ return join49(directory, ".matrixx", "tasks");
60172
60624
  }
60173
60625
  function getTaskDir(config2 = {}, directory) {
60174
60626
  const tasksConfig = resolveTasksConfig(config2);
60175
60627
  const storagePath = tasksConfig.storage_path;
60176
60628
  if (storagePath) {
60177
- return isAbsolute3(storagePath) ? storagePath : join45(directory ?? process.cwd(), storagePath);
60629
+ return isAbsolute3(storagePath) ? storagePath : join49(directory ?? process.cwd(), storagePath);
60178
60630
  }
60179
60631
  if (tasksConfig.scope === "global" || !directory) {
60180
60632
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
60181
60633
  const listId = resolveTaskListId(config2);
60182
- return join45(configDir, "tasks", listId);
60634
+ return join49(configDir, "tasks", listId);
60183
60635
  }
60184
60636
  return getProjectTaskDir(directory);
60185
60637
  }
@@ -60196,16 +60648,16 @@ function resolveTaskListId(config2 = {}) {
60196
60648
  return sanitizePathSegment(basename5(process.cwd()));
60197
60649
  }
60198
60650
  function ensureDir2(dirPath) {
60199
- if (!existsSync37(dirPath)) {
60200
- mkdirSync14(dirPath, { recursive: true });
60651
+ if (!existsSync40(dirPath)) {
60652
+ mkdirSync15(dirPath, { recursive: true });
60201
60653
  }
60202
60654
  }
60203
60655
  function readJsonSafe(filePath, schema) {
60204
60656
  try {
60205
- if (!existsSync37(filePath)) {
60657
+ if (!existsSync40(filePath)) {
60206
60658
  return null;
60207
60659
  }
60208
- const content = readFileSync30(filePath, "utf-8");
60660
+ const content = readFileSync33(filePath, "utf-8");
60209
60661
  const parsed = JSON.parse(content);
60210
60662
  const result = schema.safeParse(parsed);
60211
60663
  if (!result.success) {
@@ -60221,12 +60673,12 @@ function writeJsonAtomic(filePath, data) {
60221
60673
  ensureDir2(dir);
60222
60674
  const tempPath = `${filePath}.tmp.${Date.now()}`;
60223
60675
  try {
60224
- writeFileSync16(tempPath, JSON.stringify(data, null, 2), "utf-8");
60676
+ writeFileSync17(tempPath, JSON.stringify(data, null, 2), "utf-8");
60225
60677
  renameSync3(tempPath, filePath);
60226
60678
  } catch (error51) {
60227
60679
  try {
60228
- if (existsSync37(tempPath)) {
60229
- unlinkSync8(tempPath);
60680
+ if (existsSync40(tempPath)) {
60681
+ unlinkSync9(tempPath);
60230
60682
  }
60231
60683
  } catch {}
60232
60684
  throw error51;
@@ -60249,21 +60701,21 @@ function generateTaskId() {
60249
60701
  }
60250
60702
  function migrateLegacyTasksIfNeeded(config2, directory) {
60251
60703
  const projectDir = getProjectTaskDir(directory);
60252
- const legacyDir = join45(getOpenCodeConfigDir({ binary: "opencode" }), "tasks", resolveTaskListId(config2));
60253
- if (existsSync37(projectDir)) {
60704
+ const legacyDir = join49(getOpenCodeConfigDir({ binary: "opencode" }), "tasks", resolveTaskListId(config2));
60705
+ if (existsSync40(projectDir)) {
60254
60706
  try {
60255
- const existing = readdirSync11(projectDir).filter((f) => f.startsWith("T-") && f.endsWith(".json"));
60707
+ const existing = readdirSync12(projectDir).filter((f) => f.startsWith("T-") && f.endsWith(".json"));
60256
60708
  if (existing.length > 0) {
60257
60709
  return { migrated: 0, legacyDir, projectDir };
60258
60710
  }
60259
60711
  } catch {}
60260
60712
  }
60261
- if (!existsSync37(legacyDir)) {
60713
+ if (!existsSync40(legacyDir)) {
60262
60714
  return { migrated: 0, legacyDir, projectDir };
60263
60715
  }
60264
60716
  let files = [];
60265
60717
  try {
60266
- files = readdirSync11(legacyDir).filter((f) => f.startsWith("T-") && f.endsWith(".json"));
60718
+ files = readdirSync12(legacyDir).filter((f) => f.startsWith("T-") && f.endsWith(".json"));
60267
60719
  } catch {
60268
60720
  return { migrated: 0, legacyDir, projectDir };
60269
60721
  }
@@ -60273,13 +60725,13 @@ function migrateLegacyTasksIfNeeded(config2, directory) {
60273
60725
  ensureDir2(projectDir);
60274
60726
  let migrated = 0;
60275
60727
  for (const file2 of files) {
60276
- const src = join45(legacyDir, file2);
60277
- const dest = join45(projectDir, file2);
60278
- if (existsSync37(dest))
60728
+ const src = join49(legacyDir, file2);
60729
+ const dest = join49(projectDir, file2);
60730
+ if (existsSync40(dest))
60279
60731
  continue;
60280
60732
  try {
60281
- const content = readFileSync30(src, "utf-8");
60282
- writeFileSync16(dest, content, "utf-8");
60733
+ const content = readFileSync33(src, "utf-8");
60734
+ writeFileSync17(dest, content, "utf-8");
60283
60735
  migrated++;
60284
60736
  } catch {}
60285
60737
  }
@@ -60289,17 +60741,17 @@ function migrateLegacyTasksIfNeeded(config2, directory) {
60289
60741
  return { migrated, legacyDir, projectDir };
60290
60742
  }
60291
60743
  function acquireLock(dirPath) {
60292
- const lockPath = join45(dirPath, ".lock");
60744
+ const lockPath = join49(dirPath, ".lock");
60293
60745
  const lockId = randomUUID();
60294
60746
  const createLock = (timestamp) => {
60295
- writeFileSync16(lockPath, JSON.stringify({ id: lockId, timestamp }), {
60747
+ writeFileSync17(lockPath, JSON.stringify({ id: lockId, timestamp }), {
60296
60748
  encoding: "utf-8",
60297
60749
  flag: "wx"
60298
60750
  });
60299
60751
  };
60300
60752
  const isStale = () => {
60301
60753
  try {
60302
- const lockContent = readFileSync30(lockPath, "utf-8");
60754
+ const lockContent = readFileSync33(lockPath, "utf-8");
60303
60755
  const lockData = JSON.parse(lockContent);
60304
60756
  const lockAge = Date.now() - lockData.timestamp;
60305
60757
  return lockAge > STALE_LOCK_THRESHOLD_MS;
@@ -60323,7 +60775,7 @@ function acquireLock(dirPath) {
60323
60775
  let acquired = tryAcquire();
60324
60776
  if (!acquired && isStale()) {
60325
60777
  try {
60326
- unlinkSync8(lockPath);
60778
+ unlinkSync9(lockPath);
60327
60779
  } catch {}
60328
60780
  acquired = tryAcquire();
60329
60781
  }
@@ -60337,13 +60789,13 @@ function acquireLock(dirPath) {
60337
60789
  acquired: true,
60338
60790
  release: () => {
60339
60791
  try {
60340
- if (!existsSync37(lockPath))
60792
+ if (!existsSync40(lockPath))
60341
60793
  return;
60342
- const lockContent = readFileSync30(lockPath, "utf-8");
60794
+ const lockContent = readFileSync33(lockPath, "utf-8");
60343
60795
  const lockData = JSON.parse(lockContent);
60344
60796
  if (lockData.id !== lockId)
60345
60797
  return;
60346
- unlinkSync8(lockPath);
60798
+ unlinkSync9(lockPath);
60347
60799
  } catch {}
60348
60800
  }
60349
60801
  };
@@ -60479,13 +60931,13 @@ function createPlanPersister(ctx, options) {
60479
60931
  if (!mission.session_ids?.includes(sessionID))
60480
60932
  return;
60481
60933
  const planPath = mission.active_plan;
60482
- if (!existsSync38(planPath))
60934
+ if (!existsSync41(planPath))
60483
60935
  return;
60484
60936
  let todos = [];
60485
60937
  try {
60486
60938
  const taskDir = getTaskDir({}, directory);
60487
- if (existsSync38(taskDir)) {
60488
- const files = readdirSync12(taskDir).filter((f) => f.startsWith("T-") && f.endsWith(".json"));
60939
+ if (existsSync41(taskDir)) {
60940
+ const files = readdirSync13(taskDir).filter((f) => f.startsWith("T-") && f.endsWith(".json"));
60489
60941
  const tasks = [];
60490
60942
  for (const f of files) {
60491
60943
  const parsed = readJsonSafe(`${taskDir}/${f}`, TaskObjectSchema);
@@ -61811,568 +62263,9 @@ function createRtkBashRewriterHook(_ctx, config2) {
61811
62263
  }
61812
62264
  };
61813
62265
  }
61814
- // src/hooks/rules-injector/project-root-finder.ts
61815
- import { existsSync as existsSync39, statSync as statSync5 } from "fs";
61816
- import { dirname as dirname11, join as join47 } from "path";
61817
-
61818
- // src/hooks/rules-injector/constants.ts
61819
- import { join as join46 } from "path";
61820
- var RULES_INJECTOR_STORAGE = join46(OPENCODE_STORAGE, "rules-injector");
61821
- var PROJECT_MARKERS = [
61822
- ".git",
61823
- "pyproject.toml",
61824
- "package.json",
61825
- "Cargo.toml",
61826
- "go.mod",
61827
- ".venv"
61828
- ];
61829
- var PROJECT_RULE_SUBDIRS = [
61830
- [".github", "instructions"],
61831
- [".cursor", "rules"],
61832
- [".matrixx", "rules"]
61833
- ];
61834
- var PROJECT_RULE_FILES = [
61835
- ".github/copilot-instructions.md"
61836
- ];
61837
- var GITHUB_INSTRUCTIONS_PATTERN = /\.instructions\.md$/;
61838
- var RULE_EXTENSIONS = [".md", ".mdc"];
61839
-
61840
- // src/hooks/rules-injector/project-root-finder.ts
61841
- function findProjectRoot(startPath) {
61842
- let current;
61843
- try {
61844
- const stat = statSync5(startPath);
61845
- current = stat.isDirectory() ? startPath : dirname11(startPath);
61846
- } catch {
61847
- current = dirname11(startPath);
61848
- }
61849
- while (true) {
61850
- for (const marker of PROJECT_MARKERS) {
61851
- const markerPath = join47(current, marker);
61852
- if (existsSync39(markerPath)) {
61853
- return current;
61854
- }
61855
- }
61856
- const parent = dirname11(current);
61857
- if (parent === current) {
61858
- return null;
61859
- }
61860
- current = parent;
61861
- }
61862
- }
61863
- // src/hooks/rules-injector/rule-file-finder.ts
61864
- import { existsSync as existsSync41, statSync as statSync6 } from "fs";
61865
- import { dirname as dirname12, join as join49 } from "path";
61866
-
61867
- // src/hooks/rules-injector/rule-file-scanner.ts
61868
- import { existsSync as existsSync40, readdirSync as readdirSync13, realpathSync as realpathSync2 } from "fs";
61869
- import { join as join48 } from "path";
61870
- function isGitHubInstructionsDir(dir) {
61871
- return dir.includes(".github/instructions") || dir.endsWith(".github/instructions");
61872
- }
61873
- function isValidRuleFile(fileName, dir) {
61874
- if (isGitHubInstructionsDir(dir)) {
61875
- return GITHUB_INSTRUCTIONS_PATTERN.test(fileName);
61876
- }
61877
- return RULE_EXTENSIONS.some((ext) => fileName.endsWith(ext));
61878
- }
61879
- function findRuleFilesRecursive(dir, results) {
61880
- if (!existsSync40(dir))
61881
- return;
61882
- try {
61883
- const entries = readdirSync13(dir, { withFileTypes: true });
61884
- for (const entry of entries) {
61885
- const fullPath = join48(dir, entry.name);
61886
- if (entry.isDirectory()) {
61887
- findRuleFilesRecursive(fullPath, results);
61888
- } else if (entry.isFile()) {
61889
- if (isValidRuleFile(entry.name, dir)) {
61890
- results.push(fullPath);
61891
- }
61892
- }
61893
- }
61894
- } catch {}
61895
- }
61896
- function safeRealpathSync(filePath) {
61897
- try {
61898
- return realpathSync2(filePath);
61899
- } catch {
61900
- return filePath;
61901
- }
61902
- }
61903
-
61904
- // src/hooks/rules-injector/rule-file-finder.ts
61905
- function findRuleFiles(projectRoot, currentFile) {
61906
- const candidates = [];
61907
- const seenRealPaths = new Set;
61908
- let currentDir = dirname12(currentFile);
61909
- let distance = 0;
61910
- while (true) {
61911
- for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
61912
- const ruleDir = join49(currentDir, parent, subdir);
61913
- const files = [];
61914
- findRuleFilesRecursive(ruleDir, files);
61915
- for (const filePath of files) {
61916
- const realPath = safeRealpathSync(filePath);
61917
- if (seenRealPaths.has(realPath))
61918
- continue;
61919
- seenRealPaths.add(realPath);
61920
- candidates.push({
61921
- path: filePath,
61922
- realPath,
61923
- isGlobal: false,
61924
- distance
61925
- });
61926
- }
61927
- }
61928
- if (projectRoot && currentDir === projectRoot)
61929
- break;
61930
- const parentDir = dirname12(currentDir);
61931
- if (parentDir === currentDir)
61932
- break;
61933
- currentDir = parentDir;
61934
- distance++;
61935
- }
61936
- if (projectRoot) {
61937
- for (const ruleFile of PROJECT_RULE_FILES) {
61938
- const filePath = join49(projectRoot, ruleFile);
61939
- if (existsSync41(filePath)) {
61940
- try {
61941
- const stat = statSync6(filePath);
61942
- if (stat.isFile()) {
61943
- const realPath = safeRealpathSync(filePath);
61944
- if (!seenRealPaths.has(realPath)) {
61945
- seenRealPaths.add(realPath);
61946
- candidates.push({
61947
- path: filePath,
61948
- realPath,
61949
- isGlobal: false,
61950
- distance: 0,
61951
- isSingleFile: true
61952
- });
61953
- }
61954
- }
61955
- } catch {}
61956
- }
61957
- }
61958
- }
61959
- candidates.sort((a, b) => {
61960
- if (a.isGlobal !== b.isGlobal) {
61961
- return a.isGlobal ? 1 : -1;
61962
- }
61963
- return a.distance - b.distance;
61964
- });
61965
- return candidates;
61966
- }
61967
- // src/hooks/rules-injector/storage.ts
61968
- import {
61969
- existsSync as existsSync42,
61970
- mkdirSync as mkdirSync15,
61971
- readFileSync as readFileSync31,
61972
- unlinkSync as unlinkSync9,
61973
- writeFileSync as writeFileSync17
61974
- } from "fs";
61975
- import { join as join50 } from "path";
61976
- function getStoragePath3(sessionID) {
61977
- return join50(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
61978
- }
61979
- function loadInjectedRules(sessionID) {
61980
- const filePath = getStoragePath3(sessionID);
61981
- if (!existsSync42(filePath))
61982
- return { contentHashes: new Set, realPaths: new Set };
61983
- try {
61984
- const content = readFileSync31(filePath, "utf-8");
61985
- const data = JSON.parse(content);
61986
- return {
61987
- contentHashes: new Set(data.injectedHashes),
61988
- realPaths: new Set(data.injectedRealPaths ?? [])
61989
- };
61990
- } catch {
61991
- return { contentHashes: new Set, realPaths: new Set };
61992
- }
61993
- }
61994
- function saveInjectedRules(sessionID, data) {
61995
- if (!existsSync42(RULES_INJECTOR_STORAGE)) {
61996
- mkdirSync15(RULES_INJECTOR_STORAGE, { recursive: true });
61997
- }
61998
- const storageData = {
61999
- sessionID,
62000
- injectedHashes: [...data.contentHashes],
62001
- injectedRealPaths: [...data.realPaths],
62002
- updatedAt: Date.now()
62003
- };
62004
- writeFileSync17(getStoragePath3(sessionID), JSON.stringify(storageData, null, 2));
62005
- }
62006
- function clearInjectedRules(sessionID) {
62007
- const filePath = getStoragePath3(sessionID);
62008
- if (existsSync42(filePath)) {
62009
- unlinkSync9(filePath);
62010
- }
62011
- }
62012
-
62013
- // src/hooks/rules-injector/cache.ts
62014
- function createSessionCacheStore() {
62015
- const sessionCaches = new Map;
62016
- function getSessionCache2(sessionID) {
62017
- if (!sessionCaches.has(sessionID)) {
62018
- sessionCaches.set(sessionID, loadInjectedRules(sessionID));
62019
- }
62020
- return sessionCaches.get(sessionID);
62021
- }
62022
- function clearSessionCache(sessionID) {
62023
- sessionCaches.delete(sessionID);
62024
- clearInjectedRules(sessionID);
62025
- }
62026
- return { getSessionCache: getSessionCache2, clearSessionCache };
62027
- }
62028
-
62029
- // src/hooks/rules-injector/injector.ts
62030
- import { readFileSync as readFileSync32, statSync as statSync7, watch } from "fs";
62031
- import { relative as relative3, resolve as resolve5 } from "path";
62032
-
62033
- // src/hooks/rules-injector/matcher.ts
62034
- var import_picomatch2 = __toESM(require_picomatch2(), 1);
62035
- import { createHash } from "crypto";
62036
- import { relative as relative2 } from "path";
62037
- function shouldApplyRule(metadata, currentFilePath, projectRoot) {
62038
- if (metadata.alwaysApply === true) {
62039
- return { applies: true, reason: "alwaysApply" };
62040
- }
62041
- const globs = metadata.globs;
62042
- if (!globs) {
62043
- return { applies: false };
62044
- }
62045
- const patterns2 = Array.isArray(globs) ? globs : [globs];
62046
- if (patterns2.length === 0) {
62047
- return { applies: false };
62048
- }
62049
- const relativePath = projectRoot ? relative2(projectRoot, currentFilePath) : currentFilePath;
62050
- for (const pattern of patterns2) {
62051
- if (import_picomatch2.default.isMatch(relativePath, pattern, { dot: true, bash: true })) {
62052
- return { applies: true, reason: `glob: ${pattern}` };
62053
- }
62054
- }
62055
- return { applies: false };
62056
- }
62057
- function isDuplicateByRealPath(realPath, cache2) {
62058
- return cache2.has(realPath);
62059
- }
62060
- function createContentHash(content) {
62061
- return createHash("sha256").update(content).digest("hex").slice(0, 16);
62062
- }
62063
- function isDuplicateByContentHash(hash2, cache2) {
62064
- return cache2.has(hash2);
62065
- }
62066
-
62067
- // src/hooks/rules-injector/parser.ts
62068
- function parseRuleFrontmatter(content) {
62069
- const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
62070
- const match = content.match(frontmatterRegex);
62071
- if (!match) {
62072
- return { metadata: {}, body: content };
62073
- }
62074
- const yamlContent = match[1];
62075
- const body = match[2];
62076
- try {
62077
- const metadata = parseYamlContent(yamlContent);
62078
- return { metadata, body };
62079
- } catch {
62080
- return { metadata: {}, body: content };
62081
- }
62082
- }
62083
- function parseYamlContent(yamlContent) {
62084
- const lines = yamlContent.split(`
62085
- `);
62086
- const metadata = {};
62087
- let i = 0;
62088
- while (i < lines.length) {
62089
- const line = lines[i];
62090
- const colonIndex = line.indexOf(":");
62091
- if (colonIndex === -1) {
62092
- i++;
62093
- continue;
62094
- }
62095
- const key = line.slice(0, colonIndex).trim();
62096
- const rawValue = line.slice(colonIndex + 1).trim();
62097
- if (key === "description") {
62098
- metadata.description = parseStringValue(rawValue);
62099
- } else if (key === "alwaysApply") {
62100
- metadata.alwaysApply = rawValue === "true";
62101
- } else if (key === "globs" || key === "applyTo") {
62102
- const { value, consumed } = parseArrayOrStringValue(rawValue, lines, i);
62103
- metadata.globs = mergeGlobs(metadata.globs, value);
62104
- i += consumed;
62105
- continue;
62106
- }
62107
- i++;
62108
- }
62109
- return metadata;
62110
- }
62111
- function parseStringValue(value) {
62112
- if (!value)
62113
- return "";
62114
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
62115
- return value.slice(1, -1);
62116
- }
62117
- return value;
62118
- }
62119
- function parseArrayOrStringValue(rawValue, lines, currentIndex) {
62120
- if (rawValue.startsWith("[")) {
62121
- return { value: parseInlineArray(rawValue), consumed: 1 };
62122
- }
62123
- if (!rawValue || rawValue === "") {
62124
- const arrayItems = [];
62125
- let consumed = 1;
62126
- for (let j = currentIndex + 1;j < lines.length; j++) {
62127
- const nextLine = lines[j];
62128
- const arrayMatch = nextLine.match(/^\s+-\s*(.*)$/);
62129
- if (arrayMatch) {
62130
- const itemValue = parseStringValue(arrayMatch[1].trim());
62131
- if (itemValue) {
62132
- arrayItems.push(itemValue);
62133
- }
62134
- consumed++;
62135
- } else if (nextLine.trim() === "") {
62136
- consumed++;
62137
- } else {
62138
- break;
62139
- }
62140
- }
62141
- if (arrayItems.length > 0) {
62142
- return { value: arrayItems, consumed };
62143
- }
62144
- }
62145
- const stringValue = parseStringValue(rawValue);
62146
- if (stringValue.includes(",")) {
62147
- const items = stringValue.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
62148
- return { value: items, consumed: 1 };
62149
- }
62150
- return { value: stringValue, consumed: 1 };
62151
- }
62152
- function parseInlineArray(value) {
62153
- const content = value.slice(1, value.lastIndexOf("]")).trim();
62154
- if (!content)
62155
- return [];
62156
- const items = [];
62157
- let current = "";
62158
- let inQuote = false;
62159
- let quoteChar = "";
62160
- for (let i = 0;i < content.length; i++) {
62161
- const char = content[i];
62162
- if (!inQuote && (char === '"' || char === "'")) {
62163
- inQuote = true;
62164
- quoteChar = char;
62165
- } else if (inQuote && char === quoteChar) {
62166
- inQuote = false;
62167
- quoteChar = "";
62168
- } else if (!inQuote && char === ",") {
62169
- const trimmed2 = current.trim();
62170
- if (trimmed2) {
62171
- items.push(parseStringValue(trimmed2));
62172
- }
62173
- current = "";
62174
- } else {
62175
- current += char;
62176
- }
62177
- }
62178
- const trimmed = current.trim();
62179
- if (trimmed) {
62180
- items.push(parseStringValue(trimmed));
62181
- }
62182
- return items;
62183
- }
62184
- function mergeGlobs(existing, newValue) {
62185
- if (!existing)
62186
- return newValue;
62187
- const existingArray = Array.isArray(existing) ? existing : [existing];
62188
- const newArray = Array.isArray(newValue) ? newValue : [newValue];
62189
- return [...existingArray, ...newArray];
62190
- }
62191
-
62192
- // src/hooks/rules-injector/injector.ts
62193
- var parsedRuleCache = new Map;
62194
- var RULE_WATCHER_DEBOUNCE_MS = 1000;
62195
- var ruleWatchers = new Map;
62196
- var ruleWatcherDebounceTimers = new Map;
62197
- function makeRuleCacheKey(realPath, cwd, mtimeMs) {
62198
- return `${realPath}\x00${cwd}\x00${mtimeMs}`;
62199
- }
62200
- function invalidateRuleCacheForPath(realPath) {
62201
- const prefix = `${realPath}\x00`;
62202
- for (const key of parsedRuleCache.keys()) {
62203
- if (key.startsWith(prefix)) {
62204
- parsedRuleCache.delete(key);
62205
- }
62206
- }
62207
- }
62208
- function setupRuleWatcher(realPath) {
62209
- if (ruleWatchers.has(realPath))
62210
- return;
62211
- try {
62212
- const watcher = watch(realPath, () => {
62213
- const existing = ruleWatcherDebounceTimers.get(realPath);
62214
- if (existing)
62215
- clearTimeout(existing);
62216
- const timer = setTimeout(() => {
62217
- ruleWatcherDebounceTimers.delete(realPath);
62218
- invalidateRuleCacheForPath(realPath);
62219
- }, RULE_WATCHER_DEBOUNCE_MS);
62220
- if (typeof timer.unref === "function") {
62221
- timer.unref?.();
62222
- }
62223
- ruleWatcherDebounceTimers.set(realPath, timer);
62224
- });
62225
- watcher.on("error", () => {
62226
- ruleWatchers.delete(realPath);
62227
- });
62228
- ruleWatchers.set(realPath, watcher);
62229
- } catch {}
62230
- }
62231
- function getCachedParsedRule(filePath, realPath, cwd) {
62232
- try {
62233
- const stat = statSync7(filePath);
62234
- const key = makeRuleCacheKey(realPath, cwd, stat.mtimeMs);
62235
- const cached2 = parsedRuleCache.get(key);
62236
- if (cached2 && cached2.size === stat.size) {
62237
- return { metadata: cached2.metadata, body: cached2.body };
62238
- }
62239
- const rawContent = readFileSync32(filePath, "utf-8");
62240
- const { metadata, body } = parseRuleFrontmatter(rawContent);
62241
- parsedRuleCache.set(key, {
62242
- mtimeMs: stat.mtimeMs,
62243
- size: stat.size,
62244
- metadata,
62245
- body
62246
- });
62247
- setupRuleWatcher(realPath);
62248
- return { metadata, body };
62249
- } catch {
62250
- const rawContent = readFileSync32(filePath, "utf-8");
62251
- return parseRuleFrontmatter(rawContent);
62252
- }
62253
- }
62254
- function resolveFilePath3(workspaceDirectory, path12) {
62255
- if (!path12)
62256
- return null;
62257
- if (path12.startsWith("/"))
62258
- return path12;
62259
- return resolve5(workspaceDirectory, path12);
62260
- }
62261
- function createRuleInjectionProcessor(deps) {
62262
- const { workspaceDirectory, truncator, getSessionCache: getSessionCache2 } = deps;
62263
- async function processFilePathForInjection(filePath, sessionID, output) {
62264
- const resolved = resolveFilePath3(workspaceDirectory, filePath);
62265
- if (!resolved)
62266
- return;
62267
- const projectRoot = findProjectRoot(resolved);
62268
- const cache2 = getSessionCache2(sessionID);
62269
- const ruleFileCandidates = findRuleFiles(projectRoot, resolved);
62270
- const toInject = [];
62271
- let dirty = false;
62272
- for (const candidate of ruleFileCandidates) {
62273
- if (isDuplicateByRealPath(candidate.realPath, cache2.realPaths))
62274
- continue;
62275
- try {
62276
- const { metadata, body } = getCachedParsedRule(candidate.path, candidate.realPath, workspaceDirectory);
62277
- let matchReason;
62278
- if (candidate.isSingleFile) {
62279
- matchReason = "copilot-instructions (always apply)";
62280
- } else {
62281
- const matchResult = shouldApplyRule(metadata, resolved, projectRoot);
62282
- if (!matchResult.applies)
62283
- continue;
62284
- matchReason = matchResult.reason ?? "matched";
62285
- }
62286
- const contentHash = createContentHash(body);
62287
- if (isDuplicateByContentHash(contentHash, cache2.contentHashes))
62288
- continue;
62289
- const relativePath = projectRoot ? relative3(projectRoot, candidate.path) : candidate.path;
62290
- toInject.push({
62291
- relativePath,
62292
- matchReason,
62293
- content: body,
62294
- distance: candidate.distance
62295
- });
62296
- cache2.realPaths.add(candidate.realPath);
62297
- cache2.contentHashes.add(contentHash);
62298
- dirty = true;
62299
- } catch {}
62300
- }
62301
- if (toInject.length === 0)
62302
- return;
62303
- toInject.sort((a, b) => a.distance - b.distance);
62304
- for (const rule of toInject) {
62305
- const { result, truncated } = await truncator.truncate(sessionID, rule.content);
62306
- const truncationNotice = truncated ? `
62307
-
62308
- [Note: Content was truncated to save context window space. For full context, please read the file directly: ${rule.relativePath}]` : "";
62309
- output.output += `
62310
-
62311
- [Rule: ${rule.relativePath}]
62312
- [Match: ${rule.matchReason}]
62313
- ${result}${truncationNotice}`;
62314
- }
62315
- if (dirty) {
62316
- saveInjectedRules(sessionID, cache2);
62317
- }
62318
- }
62319
- return { processFilePathForInjection };
62320
- }
62321
-
62322
- // src/hooks/rules-injector/output-path.ts
62323
- function getRuleInjectionFilePath(output) {
62324
- const metadata = output.metadata;
62325
- const metadataFilePath = metadata && typeof metadata === "object" ? metadata.filePath : undefined;
62326
- if (typeof metadataFilePath === "string" && metadataFilePath.length > 0) {
62327
- return metadataFilePath;
62328
- }
62329
- if (typeof output.title === "string" && output.title.length > 0) {
62330
- return output.title;
62331
- }
62332
- return null;
62333
- }
62334
-
62335
62266
  // src/hooks/rules-injector/hook.ts
62336
- var TRACKED_TOOLS = ["read", "write", "edit", "multiedit"];
62337
62267
  function createRulesInjectorHook(ctx) {
62338
- const truncator = createDynamicTruncator(ctx);
62339
- const { getSessionCache: getSessionCache2, clearSessionCache } = createSessionCacheStore();
62340
- const { processFilePathForInjection } = createRuleInjectionProcessor({
62341
- workspaceDirectory: ctx.directory,
62342
- truncator,
62343
- getSessionCache: getSessionCache2
62344
- });
62345
- const toolExecuteAfter = async (input, output) => {
62346
- const toolName = input.tool.toLowerCase();
62347
- if (TRACKED_TOOLS.includes(toolName)) {
62348
- const filePath = getRuleInjectionFilePath(output);
62349
- if (!filePath)
62350
- return;
62351
- await processFilePathForInjection(filePath, input.sessionID, output);
62352
- return;
62353
- }
62354
- };
62355
- const toolExecuteBefore = async (input, output) => {};
62356
- const eventHandler = async ({ event }) => {
62357
- const props = event.properties;
62358
- if (event.type === "session.deleted") {
62359
- const sessionInfo = props?.info;
62360
- if (sessionInfo?.id) {
62361
- clearSessionCache(sessionInfo.id);
62362
- }
62363
- }
62364
- if (event.type === "session.compacted") {
62365
- const sessionID = props?.sessionID ?? props?.info?.id;
62366
- if (sessionID) {
62367
- clearSessionCache(sessionID);
62368
- }
62369
- }
62370
- };
62371
- return {
62372
- "tool.execute.before": toolExecuteBefore,
62373
- "tool.execute.after": toolExecuteAfter,
62374
- event: eventHandler
62375
- };
62268
+ return createPostReadInjectorHook(ctx, { trackedTools: ["read", "write", "edit", "multiedit"] });
62376
62269
  }
62377
62270
  // src/hooks/runtime-fallback/auto-retry.ts
62378
62271
  init_logger();
@@ -64967,8 +64860,8 @@ var FAILURE_RESET_WINDOW_MS = 5 * 60 * 1000;
64967
64860
  init_logger();
64968
64861
 
64969
64862
  // src/hooks/task-continuation-enforcer/idle-event.ts
64970
- import { existsSync as existsSync44, readdirSync as readdirSync15 } from "fs";
64971
- import { join as join53 } from "path";
64863
+ import { existsSync as existsSync43, readdirSync as readdirSync15 } from "fs";
64864
+ import { join as join52 } from "path";
64972
64865
  init_logger();
64973
64866
 
64974
64867
  // src/hooks/task-continuation-enforcer/abort-detection.ts
@@ -64991,12 +64884,12 @@ function isLastAssistantMessageAborted(messages) {
64991
64884
  init_logger();
64992
64885
 
64993
64886
  // src/hooks/task-continuation-enforcer/continuation-injection.ts
64994
- import { existsSync as existsSync43, readdirSync as readdirSync14 } from "fs";
64995
- import { join as join52 } from "path";
64887
+ import { existsSync as existsSync42, readdirSync as readdirSync14 } from "fs";
64888
+ import { join as join51 } from "path";
64996
64889
  init_logger();
64997
64890
  // src/hooks/task-continuation-enforcer/staleness.ts
64998
- import { statSync as statSync8 } from "fs";
64999
- import { join as join51 } from "path";
64891
+ import { statSync as statSync6 } from "fs";
64892
+ import { join as join50 } from "path";
65000
64893
  var DEFAULT_STALE_AFTER_HOURS = 24;
65001
64894
  var HOUR_MS = 60 * 60 * 1000;
65002
64895
  function getStaleAfterMs(config2) {
@@ -65005,7 +64898,7 @@ function getStaleAfterMs(config2) {
65005
64898
  }
65006
64899
  function getTaskAgeMs(taskPath) {
65007
64900
  try {
65008
- const stat = statSync8(taskPath);
64901
+ const stat = statSync6(taskPath);
65009
64902
  return Date.now() - stat.mtimeMs;
65010
64903
  } catch {
65011
64904
  return null;
@@ -65016,7 +64909,7 @@ function isTaskStale(taskPath, staleAfterMs) {
65016
64909
  return ageMs !== null && ageMs > staleAfterMs;
65017
64910
  }
65018
64911
  function filterFreshIncompleteTasks(tasks, taskDir, staleAfterMs) {
65019
- return tasks.filter((t) => !isTaskStale(join51(taskDir, `${t.id}.json`), staleAfterMs));
64912
+ return tasks.filter((t) => !isTaskStale(join50(taskDir, `${t.id}.json`), staleAfterMs));
65020
64913
  }
65021
64914
  function formatTaskAge(ageMs) {
65022
64915
  const hours = Math.floor(ageMs / HOUR_MS);
@@ -65117,7 +65010,7 @@ async function injectContinuation(args) {
65117
65010
  let taskDir = "";
65118
65011
  try {
65119
65012
  taskDir = getTaskDir(config2, ctx.directory);
65120
- if (!existsSync43(taskDir)) {
65013
+ if (!existsSync42(taskDir)) {
65121
65014
  const hadNonExplorerBgTasks = backgroundManager ? hasNonExplorerBgTasks(backgroundManager.getTasksByParentSession(sessionID)) : false;
65122
65015
  if (hadNonExplorerBgTasks) {
65123
65016
  log(`[${HOOK_NAME14}] Bootstrap injection: no task dir (hadNonExplorerBgTasks)`, { sessionID, taskDir });
@@ -65200,7 +65093,7 @@ async function injectContinuation(args) {
65200
65093
  const incompleteTasks = getIncompleteTasks(filteredTasks);
65201
65094
  const freshIncompleteTasks = filterFreshIncompleteTasks(incompleteTasks, taskDir, staleAfterMs);
65202
65095
  const taskList = incompleteTasks.map((task) => {
65203
- const ageMs = getTaskAgeMs(join52(taskDir, `${task.id}.json`));
65096
+ const ageMs = getTaskAgeMs(join51(taskDir, `${task.id}.json`));
65204
65097
  const staleSuffix = ageMs !== null && ageMs > staleAfterMs ? ` (stale: ${formatTaskAge(ageMs)})` : "";
65205
65098
  return `- [${task.status}] ${task.subject} (${task.id})${staleSuffix}`;
65206
65099
  }).join(`
@@ -65382,7 +65275,7 @@ async function handleSessionIdle(args) {
65382
65275
  let taskDir = "";
65383
65276
  try {
65384
65277
  taskDir = getTaskDir(config2, ctx.directory);
65385
- if (!existsSync44(taskDir)) {
65278
+ if (!existsSync43(taskDir)) {
65386
65279
  const hadNonExplorerBgTasks = backgroundManager ? hasNonExplorerBgTasks(backgroundManager.getTasksByParentSession(sessionID)) : false;
65387
65280
  if (hadNonExplorerBgTasks) {
65388
65281
  log(`[${HOOK_NAME14}] No task dir \u2014 bootstrap (hadBgTasks)`, { sessionID, taskDir });
@@ -65421,7 +65314,7 @@ async function handleSessionIdle(args) {
65421
65314
  const incompleteTasks = getIncompleteTasks(filteredTasks);
65422
65315
  incompleteCount = incompleteTasks.length;
65423
65316
  const staleAfterMs = getStaleAfterMs(config2);
65424
- const staleIncompleteCount = incompleteTasks.filter((t) => isTaskStale(join53(taskDir, `${t.id}.json`), staleAfterMs)).length;
65317
+ const staleIncompleteCount = incompleteTasks.filter((t) => isTaskStale(join52(taskDir, `${t.id}.json`), staleAfterMs)).length;
65425
65318
  const activeIncompleteCount = incompleteCount - staleIncompleteCount;
65426
65319
  if (activeIncompleteCount === 0 && staleIncompleteCount > 0) {
65427
65320
  log(`[${HOOK_NAME14}] Skipped: only stale tasks remain`, {
@@ -65868,8 +65761,8 @@ var TASK_NOTEPAD_FRAGMENT = "task-notepad";
65868
65761
  var TODO_FETCH_ERROR_FRAGMENT = "Failed to fetch todos for task-notepad";
65869
65762
  // src/hooks/task-notepad/hook.ts
65870
65763
  init_logger();
65871
- import { existsSync as existsSync45, mkdirSync as mkdirSync16, readdirSync as readdirSync16, readFileSync as readFileSync33, statSync as statSync9, writeFileSync as writeFileSync18 } from "fs";
65872
- import { dirname as dirname13, join as join54 } from "path";
65764
+ import { existsSync as existsSync44, mkdirSync as mkdirSync16, readdirSync as readdirSync16, readFileSync as readFileSync34, statSync as statSync7, writeFileSync as writeFileSync18 } from "fs";
65765
+ import { dirname as dirname11, join as join53 } from "path";
65873
65766
  function createTaskNotepadHook(ctx) {
65874
65767
  return {
65875
65768
  "tool.execute.after": async (input, output) => {
@@ -65920,8 +65813,8 @@ async function fetchTodos(ctx, sessionID) {
65920
65813
  }
65921
65814
  }
65922
65815
  function resolveActivePlan(directory) {
65923
- const plansDir = join54(directory, PLAN_DIR_NAME, PLANS_SUBDIR);
65924
- if (!existsSync45(plansDir))
65816
+ const plansDir = join53(directory, PLAN_DIR_NAME, PLANS_SUBDIR);
65817
+ if (!existsSync44(plansDir))
65925
65818
  return null;
65926
65819
  let entries;
65927
65820
  try {
@@ -65933,9 +65826,9 @@ function resolveActivePlan(directory) {
65933
65826
  for (const entry of entries) {
65934
65827
  if (!entry.endsWith(PLAN_EXTENSION))
65935
65828
  continue;
65936
- const fullPath = join54(plansDir, entry);
65829
+ const fullPath = join53(plansDir, entry);
65937
65830
  try {
65938
- const stats = statSync9(fullPath);
65831
+ const stats = statSync7(fullPath);
65939
65832
  if (!stats.isFile())
65940
65833
  continue;
65941
65834
  const candidate = {
@@ -65952,18 +65845,18 @@ function resolveActivePlan(directory) {
65952
65845
  }
65953
65846
  function ensureNotepad(directory, planName, todo) {
65954
65847
  const notepadPath = notepadPathFor(directory, planName, todo.id);
65955
- if (existsSync45(notepadPath))
65848
+ if (existsSync44(notepadPath))
65956
65849
  return;
65957
- mkdirSync16(dirname13(notepadPath), { recursive: true });
65850
+ mkdirSync16(dirname11(notepadPath), { recursive: true });
65958
65851
  const content = renderNotepad(todo);
65959
65852
  writeFileSync18(notepadPath, content, "utf-8");
65960
65853
  log(`[${HOOK_NAME16}] Created task notepad`, { plan: planName, taskID: todo.id });
65961
65854
  }
65962
65855
  function appendCompletion(directory, planName, todo) {
65963
65856
  const notepadPath = notepadPathFor(directory, planName, todo.id);
65964
- if (!existsSync45(notepadPath))
65857
+ if (!existsSync44(notepadPath))
65965
65858
  return;
65966
- const existing = readFileSync33(notepadPath, "utf-8");
65859
+ const existing = readFileSync34(notepadPath, "utf-8");
65967
65860
  if (existing.includes("**Status**: completed"))
65968
65861
  return;
65969
65862
  const stamp = new Date().toISOString();
@@ -65976,7 +65869,7 @@ function appendCompletion(directory, planName, todo) {
65976
65869
  log(`[${HOOK_NAME16}] Appended completion to notepad`, { plan: planName, taskID: todo.id });
65977
65870
  }
65978
65871
  function notepadPathFor(directory, planName, taskID) {
65979
- return join54(directory, PLAN_DIR_NAME, NOTEPAD_DIR_NAME, planName, TASKS_SUBDIR, `${taskID}${NOTEPAD_EXTENSION}`);
65872
+ return join53(directory, PLAN_DIR_NAME, NOTEPAD_DIR_NAME, planName, TASKS_SUBDIR, `${taskID}${NOTEPAD_EXTENSION}`);
65980
65873
  }
65981
65874
  function renderNotepad(todo) {
65982
65875
  const priority = todo.priority ?? "medium";
@@ -67185,6 +67078,7 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
67185
67078
  // src/hooks/tool-output-truncator.ts
67186
67079
  var DEFAULT_MAX_TOKENS = 50000;
67187
67080
  var WEBFETCH_MAX_TOKENS = 1e4;
67081
+ var READ_MAX_TOKENS = 1e4;
67188
67082
  var TRUNCATABLE_TOOLS = [
67189
67083
  "grep",
67190
67084
  "Grep",
@@ -67197,11 +67091,19 @@ var TRUNCATABLE_TOOLS = [
67197
67091
  "interactive_bash",
67198
67092
  "Interactive_bash",
67199
67093
  "webfetch",
67200
- "WebFetch"
67094
+ "WebFetch",
67095
+ "read",
67096
+ "Read",
67097
+ "lookup_type",
67098
+ "list_types"
67201
67099
  ];
67202
67100
  var TOOL_SPECIFIC_MAX_TOKENS = {
67203
67101
  webfetch: WEBFETCH_MAX_TOKENS,
67204
- WebFetch: WEBFETCH_MAX_TOKENS
67102
+ WebFetch: WEBFETCH_MAX_TOKENS,
67103
+ read: READ_MAX_TOKENS,
67104
+ Read: READ_MAX_TOKENS,
67105
+ lookup_type: READ_MAX_TOKENS,
67106
+ list_types: READ_MAX_TOKENS
67205
67107
  };
67206
67108
  function createToolOutputTruncatorHook(ctx, options) {
67207
67109
  const truncator = createDynamicTruncator(ctx);
@@ -67651,8 +67553,8 @@ function createWebFetchRedirectGuardHook(_ctx) {
67651
67553
  };
67652
67554
  }
67653
67555
  // src/hooks/write-existing-file-guard/hook.ts
67654
- import { existsSync as existsSync46 } from "fs";
67655
- import { isAbsolute as isAbsolute4, join as join55, normalize, resolve as resolve6, sep } from "path";
67556
+ import { existsSync as existsSync45 } from "fs";
67557
+ import { isAbsolute as isAbsolute4, join as join54, normalize as normalize2, resolve as resolve5, sep } from "path";
67656
67558
  function createWriteExistingFileGuardHook(ctx) {
67657
67559
  return {
67658
67560
  "tool.execute.before": async (input, output) => {
@@ -67665,9 +67567,9 @@ function createWriteExistingFileGuardHook(ctx) {
67665
67567
  if (!filePath) {
67666
67568
  return;
67667
67569
  }
67668
- const resolvedPath = normalize(isAbsolute4(filePath) ? filePath : resolve6(ctx.directory, filePath));
67669
- if (existsSync46(resolvedPath)) {
67670
- const matrixxRoot = join55(ctx.directory, ".matrixx") + sep;
67570
+ const resolvedPath = normalize2(isAbsolute4(filePath) ? filePath : resolve5(ctx.directory, filePath));
67571
+ if (existsSync45(resolvedPath)) {
67572
+ const matrixxRoot = join54(ctx.directory, ".matrixx") + sep;
67671
67573
  const isMatrixMarkdown = resolvedPath.startsWith(matrixxRoot) && resolvedPath.endsWith(".md");
67672
67574
  const normalizedPath = resolvedPath.replace(/\\/g, "/");
67673
67575
  const isPlansPath = normalizedPath.includes(".matrixx/plans");
@@ -67845,8 +67747,8 @@ function createAnthropicEffortHook() {
67845
67747
  };
67846
67748
  }
67847
67749
  // src/tools/lsp/lsp-client.ts
67848
- import { readFileSync as readFileSync35 } from "fs";
67849
- import { extname as extname2, resolve as resolve7 } from "path";
67750
+ import { readFileSync as readFileSync36 } from "fs";
67751
+ import { extname as extname2, resolve as resolve6 } from "path";
67850
67752
  import { pathToFileURL as pathToFileURL2 } from "url";
67851
67753
 
67852
67754
  // src/tools/lsp/language-mappings.ts
@@ -68112,14 +68014,14 @@ function getLanguageId(ext) {
68112
68014
  return EXT_TO_LANG[ext] || "plaintext";
68113
68015
  }
68114
68016
  // src/tools/lsp/server-installation.ts
68115
- import { existsSync as existsSync47 } from "fs";
68116
- import { join as join56 } from "path";
68017
+ import { existsSync as existsSync46 } from "fs";
68018
+ import { join as join55 } from "path";
68117
68019
  function isServerInstalled(command) {
68118
68020
  if (command.length === 0)
68119
68021
  return false;
68120
68022
  const cmd = command[0];
68121
68023
  if (cmd.includes("/") || cmd.includes("\\")) {
68122
- if (existsSync47(cmd))
68024
+ if (existsSync46(cmd))
68123
68025
  return true;
68124
68026
  }
68125
68027
  const isWindows = process.platform === "win32";
@@ -68141,23 +68043,23 @@ function isServerInstalled(command) {
68141
68043
  const paths = pathEnv.split(pathSeparator);
68142
68044
  for (const p of paths) {
68143
68045
  for (const suffix of exts) {
68144
- if (existsSync47(join56(p, cmd + suffix))) {
68046
+ if (existsSync46(join55(p, cmd + suffix))) {
68145
68047
  return true;
68146
68048
  }
68147
68049
  }
68148
68050
  }
68149
68051
  const cwd = process.cwd();
68150
68052
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
68151
- const dataDir = join56(getDataDir(), "opencode");
68053
+ const dataDir = join55(getDataDir(), "opencode");
68152
68054
  const additionalBases = [
68153
- join56(cwd, "node_modules", ".bin"),
68154
- join56(configDir, "bin"),
68155
- join56(configDir, "node_modules", ".bin"),
68156
- join56(dataDir, "bin")
68055
+ join55(cwd, "node_modules", ".bin"),
68056
+ join55(configDir, "bin"),
68057
+ join55(configDir, "node_modules", ".bin"),
68058
+ join55(dataDir, "bin")
68157
68059
  ];
68158
68060
  for (const base of additionalBases) {
68159
68061
  for (const suffix of exts) {
68160
- if (existsSync47(join56(base, cmd + suffix))) {
68062
+ if (existsSync46(join55(base, cmd + suffix))) {
68161
68063
  return true;
68162
68064
  }
68163
68065
  }
@@ -68168,13 +68070,13 @@ function isServerInstalled(command) {
68168
68070
  return false;
68169
68071
  }
68170
68072
  // src/tools/lsp/server-config-loader.ts
68171
- import { existsSync as existsSync48, readFileSync as readFileSync34 } from "fs";
68172
- import { join as join57 } from "path";
68073
+ import { existsSync as existsSync47, readFileSync as readFileSync35 } from "fs";
68074
+ import { join as join56 } from "path";
68173
68075
  function loadJsonFile(path12) {
68174
- if (!existsSync48(path12))
68076
+ if (!existsSync47(path12))
68175
68077
  return null;
68176
68078
  try {
68177
- return parseJsonc(readFileSync34(path12, "utf-8"));
68079
+ return parseJsonc(readFileSync35(path12, "utf-8"));
68178
68080
  } catch {
68179
68081
  return null;
68180
68082
  }
@@ -68183,9 +68085,9 @@ function getConfigPaths3() {
68183
68085
  const cwd = process.cwd();
68184
68086
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
68185
68087
  return {
68186
- project: detectConfigFile(join57(cwd, ".opencode", "matrixx")).path,
68187
- user: detectConfigFile(join57(configDir, "matrixx")).path,
68188
- opencode: detectConfigFile(join57(configDir, "opencode")).path
68088
+ project: detectConfigFile(join56(cwd, ".opencode", "matrixx")).path,
68089
+ user: detectConfigFile(join56(configDir, "matrixx")).path,
68090
+ opencode: detectConfigFile(join56(configDir, "opencode")).path
68189
68091
  };
68190
68092
  }
68191
68093
  function loadAllConfigs() {
@@ -68303,17 +68205,17 @@ import { Readable, Writable } from "stream";
68303
68205
  // src/tools/lsp/lsp-process.ts
68304
68206
  init_logger();
68305
68207
  import { spawn as nodeSpawn } from "child_process";
68306
- import { existsSync as existsSync49, statSync as statSync10 } from "fs";
68208
+ import { existsSync as existsSync48, statSync as statSync8 } from "fs";
68307
68209
  var {spawn: bunSpawn } = globalThis.Bun;
68308
68210
  function shouldUseNodeSpawn() {
68309
68211
  return process.platform === "win32";
68310
68212
  }
68311
68213
  function validateCwd(cwd) {
68312
68214
  try {
68313
- if (!existsSync49(cwd)) {
68215
+ if (!existsSync48(cwd)) {
68314
68216
  return { valid: false, error: `Working directory does not exist: ${cwd}` };
68315
68217
  }
68316
- const stats = statSync10(cwd);
68218
+ const stats = statSync8(cwd);
68317
68219
  if (!stats.isDirectory()) {
68318
68220
  return { valid: false, error: `Path is not a directory: ${cwd}` };
68319
68221
  }
@@ -68325,8 +68227,8 @@ function validateCwd(cwd) {
68325
68227
  function wrapNodeProcess(proc) {
68326
68228
  let resolveExited;
68327
68229
  let exitCode = null;
68328
- const exitedPromise = new Promise((resolve7) => {
68329
- resolveExited = resolve7;
68230
+ const exitedPromise = new Promise((resolve6) => {
68231
+ resolveExited = resolve6;
68330
68232
  });
68331
68233
  proc.on("exit", (code) => {
68332
68234
  exitCode = code ?? 1;
@@ -68346,9 +68248,9 @@ function wrapNodeProcess(proc) {
68346
68248
  nodeStream.on("data", (chunk) => {
68347
68249
  const uint8 = new Uint8Array(chunk);
68348
68250
  if (waitingResolve) {
68349
- const resolve7 = waitingResolve;
68251
+ const resolve6 = waitingResolve;
68350
68252
  waitingResolve = null;
68351
- resolve7({ done: false, value: uint8 });
68253
+ resolve6({ done: false, value: uint8 });
68352
68254
  } else {
68353
68255
  chunks.push(uint8);
68354
68256
  }
@@ -68356,17 +68258,17 @@ function wrapNodeProcess(proc) {
68356
68258
  nodeStream.on("end", () => {
68357
68259
  streamEnded = true;
68358
68260
  if (waitingResolve) {
68359
- const resolve7 = waitingResolve;
68261
+ const resolve6 = waitingResolve;
68360
68262
  waitingResolve = null;
68361
- resolve7({ done: true, value: undefined });
68263
+ resolve6({ done: true, value: undefined });
68362
68264
  }
68363
68265
  });
68364
68266
  nodeStream.on("error", () => {
68365
68267
  streamEnded = true;
68366
68268
  if (waitingResolve) {
68367
- const resolve7 = waitingResolve;
68269
+ const resolve6 = waitingResolve;
68368
68270
  waitingResolve = null;
68369
- resolve7({ done: true, value: undefined });
68271
+ resolve6({ done: true, value: undefined });
68370
68272
  }
68371
68273
  });
68372
68274
  } else {
@@ -68374,13 +68276,13 @@ function wrapNodeProcess(proc) {
68374
68276
  }
68375
68277
  return {
68376
68278
  read() {
68377
- return new Promise((resolve7) => {
68279
+ return new Promise((resolve6) => {
68378
68280
  if (chunks.length > 0) {
68379
- resolve7({ done: false, value: chunks.shift() });
68281
+ resolve6({ done: false, value: chunks.shift() });
68380
68282
  } else if (streamEnded) {
68381
- resolve7({ done: true, value: undefined });
68283
+ resolve6({ done: true, value: undefined });
68382
68284
  } else {
68383
- waitingResolve = resolve7;
68285
+ waitingResolve = resolve6;
68384
68286
  }
68385
68287
  });
68386
68288
  }
@@ -68468,7 +68370,7 @@ class LSPClientTransport {
68468
68370
  throw new Error(`Failed to spawn LSP server: ${this.server.command.join(" ")}`);
68469
68371
  }
68470
68372
  this.startStderrReading();
68471
- await new Promise((resolve7) => setTimeout(resolve7, 100));
68373
+ await new Promise((resolve6) => setTimeout(resolve6, 100));
68472
68374
  if (this.proc.exitCode !== null) {
68473
68375
  const stderr = this.stderrBuffer.join(`
68474
68376
  `);
@@ -68600,8 +68502,8 @@ recent stderr: ${stderr}` : ""}`));
68600
68502
  try {
68601
68503
  proc.kill();
68602
68504
  let timeoutId;
68603
- const timeoutPromise = new Promise((resolve7) => {
68604
- timeoutId = setTimeout(resolve7, 5000);
68505
+ const timeoutPromise = new Promise((resolve6) => {
68506
+ timeoutId = setTimeout(resolve6, 5000);
68605
68507
  });
68606
68508
  await Promise.race([
68607
68509
  proc.exited.then(() => {
@@ -68613,7 +68515,7 @@ recent stderr: ${stderr}` : ""}`));
68613
68515
  log("[LSPClient] Process did not exit within timeout, escalating to SIGKILL");
68614
68516
  try {
68615
68517
  proc.kill("SIGKILL");
68616
- await Promise.race([proc.exited, new Promise((resolve7) => setTimeout(resolve7, 1000))]);
68518
+ await Promise.race([proc.exited, new Promise((resolve6) => setTimeout(resolve6, 1000))]);
68617
68519
  } catch {}
68618
68520
  }
68619
68521
  } catch {}
@@ -68693,9 +68595,9 @@ class LSPClient extends LSPClientConnection {
68693
68595
  documentVersions = new Map;
68694
68596
  lastSyncedText = new Map;
68695
68597
  async openFile(filePath) {
68696
- const absPath = resolve7(filePath);
68598
+ const absPath = resolve6(filePath);
68697
68599
  const uri = pathToFileURL2(absPath).href;
68698
- const text = readFileSync35(absPath, "utf-8");
68600
+ const text = readFileSync36(absPath, "utf-8");
68699
68601
  if (!this.openedFiles.has(absPath)) {
68700
68602
  const ext = extname2(absPath);
68701
68603
  const languageId = getLanguageId(ext);
@@ -68731,7 +68633,7 @@ class LSPClient extends LSPClientConnection {
68731
68633
  });
68732
68634
  }
68733
68635
  async definition(filePath, line, character) {
68734
- const absPath = resolve7(filePath);
68636
+ const absPath = resolve6(filePath);
68735
68637
  await this.openFile(absPath);
68736
68638
  return this.sendRequest("textDocument/definition", {
68737
68639
  textDocument: { uri: pathToFileURL2(absPath).href },
@@ -68739,7 +68641,7 @@ class LSPClient extends LSPClientConnection {
68739
68641
  });
68740
68642
  }
68741
68643
  async references(filePath, line, character, includeDeclaration = true) {
68742
- const absPath = resolve7(filePath);
68644
+ const absPath = resolve6(filePath);
68743
68645
  await this.openFile(absPath);
68744
68646
  return this.sendRequest("textDocument/references", {
68745
68647
  textDocument: { uri: pathToFileURL2(absPath).href },
@@ -68748,7 +68650,7 @@ class LSPClient extends LSPClientConnection {
68748
68650
  });
68749
68651
  }
68750
68652
  async documentSymbols(filePath) {
68751
- const absPath = resolve7(filePath);
68653
+ const absPath = resolve6(filePath);
68752
68654
  await this.openFile(absPath);
68753
68655
  return this.sendRequest("textDocument/documentSymbol", {
68754
68656
  textDocument: { uri: pathToFileURL2(absPath).href }
@@ -68758,7 +68660,7 @@ class LSPClient extends LSPClientConnection {
68758
68660
  return this.sendRequest("workspace/symbol", { query });
68759
68661
  }
68760
68662
  async diagnostics(filePath) {
68761
- const absPath = resolve7(filePath);
68663
+ const absPath = resolve6(filePath);
68762
68664
  const uri = pathToFileURL2(absPath).href;
68763
68665
  await this.openFile(absPath);
68764
68666
  await new Promise((r) => setTimeout(r, 500));
@@ -68773,7 +68675,7 @@ class LSPClient extends LSPClientConnection {
68773
68675
  return { items: this.diagnosticsStore.get(uri) ?? [] };
68774
68676
  }
68775
68677
  async prepareRename(filePath, line, character) {
68776
- const absPath = resolve7(filePath);
68678
+ const absPath = resolve6(filePath);
68777
68679
  await this.openFile(absPath);
68778
68680
  return this.sendRequest("textDocument/prepareRename", {
68779
68681
  textDocument: { uri: pathToFileURL2(absPath).href },
@@ -68781,7 +68683,7 @@ class LSPClient extends LSPClientConnection {
68781
68683
  });
68782
68684
  }
68783
68685
  async rename(filePath, line, character, newName) {
68784
- const absPath = resolve7(filePath);
68686
+ const absPath = resolve6(filePath);
68785
68687
  await this.openFile(absPath);
68786
68688
  return this.sendRequest("textDocument/rename", {
68787
68689
  textDocument: { uri: pathToFileURL2(absPath).href },
@@ -69033,31 +68935,31 @@ class LSPServerManager {
69033
68935
  }
69034
68936
  var lspManager = LSPServerManager.getInstance();
69035
68937
  // src/tools/lsp/lsp-client-wrapper.ts
69036
- import { existsSync as existsSync50, statSync as statSync11 } from "fs";
69037
- import { dirname as dirname14, extname as extname3, join as join58, resolve as resolve8 } from "path";
68938
+ import { existsSync as existsSync49, statSync as statSync9 } from "fs";
68939
+ import { dirname as dirname12, extname as extname3, join as join57, resolve as resolve7 } from "path";
69038
68940
  import { fileURLToPath as fileURLToPath3 } from "url";
69039
68941
  function findWorkspaceRoot(filePath) {
69040
- let dir = resolve8(filePath);
68942
+ let dir = resolve7(filePath);
69041
68943
  try {
69042
- const stat = statSync11(dir);
68944
+ const stat = statSync9(dir);
69043
68945
  if (!stat.isDirectory()) {
69044
- dir = dirname14(dir);
68946
+ dir = dirname12(dir);
69045
68947
  }
69046
68948
  } catch {
69047
- dir = dirname14(dir);
68949
+ dir = dirname12(dir);
69048
68950
  }
69049
68951
  const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
69050
68952
  let prevDir = "";
69051
68953
  while (dir !== prevDir) {
69052
68954
  for (const marker of markers) {
69053
- if (existsSync50(join58(dir, marker))) {
68955
+ if (existsSync49(join57(dir, marker))) {
69054
68956
  return dir;
69055
68957
  }
69056
68958
  }
69057
68959
  prevDir = dir;
69058
- dir = dirname14(dir);
68960
+ dir = dirname12(dir);
69059
68961
  }
69060
- return dirname14(resolve8(filePath));
68962
+ return dirname12(resolve7(filePath));
69061
68963
  }
69062
68964
  function uriToPath(uri) {
69063
68965
  return fileURLToPath3(uri);
@@ -69098,7 +69000,7 @@ function formatServerLookupError(result) {
69098
69000
  `);
69099
69001
  }
69100
69002
  async function withLspClient(filePath, fn) {
69101
- const absPath = resolve8(filePath);
69003
+ const absPath = resolve7(filePath);
69102
69004
  const ext = extname3(absPath);
69103
69005
  const result = findServerForExtension(ext);
69104
69006
  if (result.status !== "found") {
@@ -81652,10 +81554,10 @@ var lsp_goto_definition = tool({
81652
81554
  }
81653
81555
  });
81654
81556
  // src/tools/lsp/workspace-edit.ts
81655
- import { readFileSync as readFileSync36, writeFileSync as writeFileSync19 } from "fs";
81557
+ import { readFileSync as readFileSync37, writeFileSync as writeFileSync19 } from "fs";
81656
81558
  function applyTextEditsToFile(filePath, edits) {
81657
81559
  try {
81658
- const content = readFileSync36(filePath, "utf-8");
81560
+ const content = readFileSync37(filePath, "utf-8");
81659
81561
  const lines = content.split(`
81660
81562
  `);
81661
81563
  const sortedEdits = [...edits].sort((a, b) => {
@@ -81721,7 +81623,7 @@ function applyWorkspaceEdit(edit) {
81721
81623
  try {
81722
81624
  const oldPath = uriToPath(change.oldUri);
81723
81625
  const newPath = uriToPath(change.newUri);
81724
- const content = readFileSync36(oldPath, "utf-8");
81626
+ const content = readFileSync37(oldPath, "utf-8");
81725
81627
  writeFileSync19(newPath, content, "utf-8");
81726
81628
  __require("fs").unlinkSync(oldPath);
81727
81629
  result.filesModified.push(newPath);
@@ -81860,12 +81762,12 @@ var lsp_symbols = tool({
81860
81762
  }
81861
81763
  });
81862
81764
  // src/tools/ast-grep/cli.ts
81863
- import { existsSync as existsSync54 } from "fs";
81765
+ import { existsSync as existsSync53 } from "fs";
81864
81766
  var {spawn: spawn9 } = globalThis.Bun;
81865
81767
 
81866
81768
  // src/tools/ast-grep/cli-binary-path-resolution.ts
81867
81769
  init_logger();
81868
- import { existsSync as existsSync53 } from "fs";
81770
+ import { existsSync as existsSync52 } from "fs";
81869
81771
 
81870
81772
  // src/tools/ast-grep/language-support.ts
81871
81773
  var CLI_LANGUAGES = [
@@ -81900,15 +81802,15 @@ var DEFAULT_MAX_OUTPUT_BYTES = 1 * 1024 * 1024;
81900
81802
  var DEFAULT_MAX_MATCHES = 500;
81901
81803
 
81902
81804
  // src/tools/ast-grep/sg-cli-path.ts
81903
- import { existsSync as existsSync52, statSync as statSync12 } from "fs";
81805
+ import { existsSync as existsSync51, statSync as statSync10 } from "fs";
81904
81806
  import { createRequire as createRequire4 } from "module";
81905
- import { dirname as dirname15, join as join60 } from "path";
81807
+ import { dirname as dirname13, join as join59 } from "path";
81906
81808
 
81907
81809
  // src/tools/ast-grep/downloader.ts
81908
- import { existsSync as existsSync51 } from "fs";
81810
+ import { existsSync as existsSync50 } from "fs";
81909
81811
  import { createRequire as createRequire3 } from "module";
81910
81812
  import { homedir as homedir9 } from "os";
81911
- import { join as join59 } from "path";
81813
+ import { join as join58 } from "path";
81912
81814
  init_logger();
81913
81815
  var REPO2 = "ast-grep/ast-grep";
81914
81816
  var DEFAULT_VERSION = "0.40.0";
@@ -81933,12 +81835,12 @@ var PLATFORM_MAP2 = {
81933
81835
  function getCacheDir3() {
81934
81836
  if (process.platform === "win32") {
81935
81837
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
81936
- const base2 = localAppData || join59(homedir9(), "AppData", "Local");
81937
- return join59(base2, "matrixx", "bin");
81838
+ const base2 = localAppData || join58(homedir9(), "AppData", "Local");
81839
+ return join58(base2, "matrixx", "bin");
81938
81840
  }
81939
81841
  const xdgCache = process.env.XDG_CACHE_HOME;
81940
- const base = xdgCache || join59(homedir9(), ".cache");
81941
- return join59(base, "matrixx", "bin");
81842
+ const base = xdgCache || join58(homedir9(), ".cache");
81843
+ return join58(base, "matrixx", "bin");
81942
81844
  }
81943
81845
  function getBinaryName3() {
81944
81846
  return process.platform === "win32" ? "sg.exe" : "sg";
@@ -81955,8 +81857,8 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
81955
81857
  }
81956
81858
  const cacheDir = getCacheDir3();
81957
81859
  const binaryName = getBinaryName3();
81958
- const binaryPath = join59(cacheDir, binaryName);
81959
- if (existsSync51(binaryPath)) {
81860
+ const binaryPath = join58(cacheDir, binaryName);
81861
+ if (existsSync50(binaryPath)) {
81960
81862
  return binaryPath;
81961
81863
  }
81962
81864
  const { arch, os: os7 } = platformInfo;
@@ -81964,7 +81866,7 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
81964
81866
  const downloadUrl = `https://github.com/${REPO2}/releases/download/${version3}/${assetName}`;
81965
81867
  log(`[matrixx] Downloading ast-grep binary...`);
81966
81868
  try {
81967
- const archivePath = join59(cacheDir, assetName);
81869
+ const archivePath = join58(cacheDir, assetName);
81968
81870
  ensureCacheDir(cacheDir);
81969
81871
  await downloadArchive(downloadUrl, archivePath);
81970
81872
  await extractZipArchive(archivePath, cacheDir);
@@ -81989,7 +81891,7 @@ async function ensureAstGrepBinary() {
81989
81891
  // src/tools/ast-grep/sg-cli-path.ts
81990
81892
  function isValidBinary(filePath) {
81991
81893
  try {
81992
- return statSync12(filePath).size > 1e4;
81894
+ return statSync10(filePath).size > 1e4;
81993
81895
  } catch {
81994
81896
  return false;
81995
81897
  }
@@ -82017,9 +81919,9 @@ function findSgCliPathSync() {
82017
81919
  try {
82018
81920
  const require2 = createRequire4(import.meta.url);
82019
81921
  const cliPackageJsonPath = require2.resolve("@ast-grep/cli/package.json");
82020
- const cliDirectory = dirname15(cliPackageJsonPath);
82021
- const sgPath = join60(cliDirectory, binaryName);
82022
- if (existsSync52(sgPath) && isValidBinary(sgPath)) {
81922
+ const cliDirectory = dirname13(cliPackageJsonPath);
81923
+ const sgPath = join59(cliDirectory, binaryName);
81924
+ if (existsSync51(sgPath) && isValidBinary(sgPath)) {
82023
81925
  return sgPath;
82024
81926
  }
82025
81927
  } catch {}
@@ -82028,10 +81930,10 @@ function findSgCliPathSync() {
82028
81930
  try {
82029
81931
  const require2 = createRequire4(import.meta.url);
82030
81932
  const packageJsonPath = require2.resolve(`${platformPackage}/package.json`);
82031
- const packageDirectory = dirname15(packageJsonPath);
81933
+ const packageDirectory = dirname13(packageJsonPath);
82032
81934
  const astGrepBinaryName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
82033
- const binaryPath = join60(packageDirectory, astGrepBinaryName);
82034
- if (existsSync52(binaryPath) && isValidBinary(binaryPath)) {
81935
+ const binaryPath = join59(packageDirectory, astGrepBinaryName);
81936
+ if (existsSync51(binaryPath) && isValidBinary(binaryPath)) {
82035
81937
  return binaryPath;
82036
81938
  }
82037
81939
  } catch {}
@@ -82039,7 +81941,7 @@ function findSgCliPathSync() {
82039
81941
  if (process.platform === "darwin") {
82040
81942
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
82041
81943
  for (const path12 of homebrewPaths) {
82042
- if (existsSync52(path12) && isValidBinary(path12)) {
81944
+ if (existsSync51(path12) && isValidBinary(path12)) {
82043
81945
  return path12;
82044
81946
  }
82045
81947
  }
@@ -82065,7 +81967,7 @@ function setSgCliPath(path12) {
82065
81967
  var resolvedCliPath3 = null;
82066
81968
  var initPromise3 = null;
82067
81969
  async function getAstGrepPath() {
82068
- if (resolvedCliPath3 !== null && existsSync53(resolvedCliPath3)) {
81970
+ if (resolvedCliPath3 !== null && existsSync52(resolvedCliPath3)) {
82069
81971
  return resolvedCliPath3;
82070
81972
  }
82071
81973
  if (initPromise3) {
@@ -82073,7 +81975,7 @@ async function getAstGrepPath() {
82073
81975
  }
82074
81976
  initPromise3 = (async () => {
82075
81977
  const syncPath = findSgCliPathSync();
82076
- if (syncPath && existsSync53(syncPath)) {
81978
+ if (syncPath && existsSync52(syncPath)) {
82077
81979
  resolvedCliPath3 = syncPath;
82078
81980
  setSgCliPath(syncPath);
82079
81981
  return syncPath;
@@ -82172,7 +82074,7 @@ async function runSg(options) {
82172
82074
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
82173
82075
  args.push(...paths);
82174
82076
  let cliPath = getSgCliPath();
82175
- if (!cliPath || !existsSync54(cliPath)) {
82077
+ if (!cliPath || !existsSync53(cliPath)) {
82176
82078
  const downloadedPath = await getAstGrepPath();
82177
82079
  if (downloadedPath) {
82178
82080
  cliPath = downloadedPath;
@@ -84460,18 +84362,18 @@ var {spawn: spawn10 } = globalThis.Bun;
84460
84362
 
84461
84363
  // src/tools/grep/constants.ts
84462
84364
  import { spawnSync as spawnSync2 } from "child_process";
84463
- import { existsSync as existsSync59 } from "fs";
84464
- import { dirname as dirname16, join as join62 } from "path";
84365
+ import { existsSync as existsSync58 } from "fs";
84366
+ import { dirname as dirname14, join as join61 } from "path";
84465
84367
 
84466
84368
  // src/tools/grep/downloader.ts
84467
- import { existsSync as existsSync58, readdirSync as readdirSync18 } from "fs";
84468
- import { join as join61 } from "path";
84369
+ import { existsSync as existsSync57, readdirSync as readdirSync18 } from "fs";
84370
+ import { join as join60 } from "path";
84469
84371
  function findFileRecursive(dir, filename) {
84470
84372
  try {
84471
84373
  const entries = readdirSync18(dir, { withFileTypes: true, recursive: true });
84472
84374
  for (const entry of entries) {
84473
84375
  if (entry.isFile() && entry.name === filename) {
84474
- return join61(entry.parentPath ?? dir, entry.name);
84376
+ return join60(entry.parentPath ?? dir, entry.name);
84475
84377
  }
84476
84378
  }
84477
84379
  } catch {
@@ -84492,11 +84394,11 @@ function getPlatformKey() {
84492
84394
  }
84493
84395
  function getInstallDir() {
84494
84396
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
84495
- return join61(homeDir, ".cache", "matrixx", "bin");
84397
+ return join60(homeDir, ".cache", "matrixx", "bin");
84496
84398
  }
84497
84399
  function getRgPath() {
84498
84400
  const isWindows = process.platform === "win32";
84499
- return join61(getInstallDir(), isWindows ? "rg.exe" : "rg");
84401
+ return join60(getInstallDir(), isWindows ? "rg.exe" : "rg");
84500
84402
  }
84501
84403
  async function extractTarGz2(archivePath, destDir) {
84502
84404
  const platformKey = getPlatformKey();
@@ -84513,7 +84415,7 @@ async function extractZip2(archivePath, destDir) {
84513
84415
  const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
84514
84416
  const foundPath = findFileRecursive(destDir, binaryName);
84515
84417
  if (foundPath) {
84516
- const destPath = join61(destDir, binaryName);
84418
+ const destPath = join60(destDir, binaryName);
84517
84419
  if (foundPath !== destPath) {
84518
84420
  const { renameSync: renameSync4 } = await import("fs");
84519
84421
  renameSync4(foundPath, destPath);
@@ -84528,13 +84430,13 @@ async function downloadAndInstallRipgrep() {
84528
84430
  }
84529
84431
  const installDir = getInstallDir();
84530
84432
  const rgPath = getRgPath();
84531
- if (existsSync58(rgPath)) {
84433
+ if (existsSync57(rgPath)) {
84532
84434
  return rgPath;
84533
84435
  }
84534
84436
  ensureCacheDir(installDir);
84535
84437
  const filename = `ripgrep-${RG_VERSION}-${config4.platform}.${config4.extension}`;
84536
84438
  const url3 = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
84537
- const archivePath = join61(installDir, filename);
84439
+ const archivePath = join60(installDir, filename);
84538
84440
  try {
84539
84441
  await downloadArchive(url3, archivePath);
84540
84442
  if (config4.extension === "tar.gz") {
@@ -84543,7 +84445,7 @@ async function downloadAndInstallRipgrep() {
84543
84445
  await extractZip2(archivePath, installDir);
84544
84446
  }
84545
84447
  ensureExecutable(rgPath);
84546
- if (!existsSync58(rgPath)) {
84448
+ if (!existsSync57(rgPath)) {
84547
84449
  throw new Error("ripgrep binary not found after extraction");
84548
84450
  }
84549
84451
  return rgPath;
@@ -84555,7 +84457,7 @@ async function downloadAndInstallRipgrep() {
84555
84457
  }
84556
84458
  function getInstalledRipgrepPath() {
84557
84459
  const rgPath = getRgPath();
84558
- return existsSync58(rgPath) ? rgPath : null;
84460
+ return existsSync57(rgPath) ? rgPath : null;
84559
84461
  }
84560
84462
 
84561
84463
  // src/tools/grep/constants.ts
@@ -84575,18 +84477,18 @@ function findExecutable(name) {
84575
84477
  }
84576
84478
  function getOpenCodeBundledRg() {
84577
84479
  const execPath = process.execPath;
84578
- const execDir = dirname16(execPath);
84480
+ const execDir = dirname14(execPath);
84579
84481
  const isWindows = process.platform === "win32";
84580
84482
  const rgName = isWindows ? "rg.exe" : "rg";
84581
84483
  const candidates = [
84582
- join62(getDataDir(), "opencode", "bin", rgName),
84583
- join62(execDir, rgName),
84584
- join62(execDir, "bin", rgName),
84585
- join62(execDir, "..", "bin", rgName),
84586
- join62(execDir, "..", "libexec", rgName)
84484
+ join61(getDataDir(), "opencode", "bin", rgName),
84485
+ join61(execDir, rgName),
84486
+ join61(execDir, "bin", rgName),
84487
+ join61(execDir, "..", "bin", rgName),
84488
+ join61(execDir, "..", "libexec", rgName)
84587
84489
  ];
84588
84490
  for (const candidate of candidates) {
84589
- if (existsSync59(candidate)) {
84491
+ if (existsSync58(candidate)) {
84590
84492
  return candidate;
84591
84493
  }
84592
84494
  }
@@ -85090,17 +84992,17 @@ var HandoffSchema = exports_external.object({
85090
84992
  sections: HandoffSectionSchema
85091
84993
  });
85092
84994
  // src/features/handoff/storage.ts
85093
- import { existsSync as existsSync60, mkdirSync as mkdirSync17, readFileSync as readFileSync39, renameSync as renameSync4, writeFileSync as writeFileSync22 } from "fs";
85094
- import { join as join63 } from "path";
84995
+ import { existsSync as existsSync59, mkdirSync as mkdirSync17, readFileSync as readFileSync40, renameSync as renameSync4, writeFileSync as writeFileSync22 } from "fs";
84996
+ import { join as join62 } from "path";
85095
84997
  function getHandoffFilePath(directory) {
85096
- return join63(directory, HANDOFF_FILE_PATH);
84998
+ return join62(directory, HANDOFF_FILE_PATH);
85097
84999
  }
85098
85000
  function getHandoffConsumedFilePath(directory) {
85099
- return join63(directory, HANDOFF_CONSUMED_FILE_PATH);
85001
+ return join62(directory, HANDOFF_CONSUMED_FILE_PATH);
85100
85002
  }
85101
85003
  function handoffFileExists(directory) {
85102
85004
  try {
85103
- return existsSync60(getHandoffFilePath(directory));
85005
+ return existsSync59(getHandoffFilePath(directory));
85104
85006
  } catch {
85105
85007
  return false;
85106
85008
  }
@@ -85108,9 +85010,9 @@ function handoffFileExists(directory) {
85108
85010
  function readHandoffFile(directory) {
85109
85011
  const filePath = getHandoffFilePath(directory);
85110
85012
  try {
85111
- if (!existsSync60(filePath))
85013
+ if (!existsSync59(filePath))
85112
85014
  return null;
85113
- return readFileSync39(filePath, "utf-8");
85015
+ return readFileSync40(filePath, "utf-8");
85114
85016
  } catch {
85115
85017
  return null;
85116
85018
  }
@@ -85134,7 +85036,7 @@ function writeHandoffFile(directory, content) {
85134
85036
  }
85135
85037
  function ensureHandoffDir(directory) {
85136
85038
  try {
85137
- mkdirSync17(join63(directory, ".matrixx"), { recursive: true });
85039
+ mkdirSync17(join62(directory, ".matrixx"), { recursive: true });
85138
85040
  return true;
85139
85041
  } catch {
85140
85042
  return false;
@@ -85289,15 +85191,15 @@ ${body}
85289
85191
  }
85290
85192
 
85291
85193
  // src/tools/handoff/list-handler.ts
85292
- import { existsSync as existsSync61, readdirSync as readdirSync19, statSync as statSync14 } from "fs";
85293
- import { join as join64 } from "path";
85194
+ import { existsSync as existsSync60, readdirSync as readdirSync19, statSync as statSync12 } from "fs";
85195
+ import { join as join63 } from "path";
85294
85196
  var MATRIX_DIR = ".matrixx";
85295
85197
  function isHandoffFile(name) {
85296
85198
  return name === "handoff.md" || name.startsWith("handoff.consumed");
85297
85199
  }
85298
85200
  function handleList(directory) {
85299
- const matrixxDir = join64(directory, MATRIX_DIR);
85300
- if (!existsSync61(matrixxDir)) {
85201
+ const matrixxDir = join63(directory, MATRIX_DIR);
85202
+ if (!existsSync60(matrixxDir)) {
85301
85203
  return "No handoffs found in .matrixx/";
85302
85204
  }
85303
85205
  let entries;
@@ -85314,11 +85216,11 @@ function handleList(directory) {
85314
85216
  lines.push(`Handoff files in ${matrixxDir}:`);
85315
85217
  lines.push("");
85316
85218
  for (const name of handoffs) {
85317
- const fullPath = join64(matrixxDir, name);
85219
+ const fullPath = join63(matrixxDir, name);
85318
85220
  let size = "?";
85319
85221
  let mtime = "?";
85320
85222
  try {
85321
- const stat2 = statSync14(fullPath);
85223
+ const stat2 = statSync12(fullPath);
85322
85224
  size = `${stat2.size}B`;
85323
85225
  mtime = stat2.mtime.toISOString();
85324
85226
  } catch {}
@@ -85538,9 +85440,9 @@ The Bash tool can execute these commands directly. Do NOT retry with interactive
85538
85440
  }
85539
85441
  });
85540
85442
  // src/tools/pdf-extract-figures/tools.ts
85541
- import { existsSync as existsSync62, mkdtempSync, writeFileSync as writeFileSync23 } from "fs";
85443
+ import { existsSync as existsSync61, mkdtempSync, writeFileSync as writeFileSync23 } from "fs";
85542
85444
  import { tmpdir as tmpdir5 } from "os";
85543
- import { join as join65 } from "path";
85445
+ import { join as join64 } from "path";
85544
85446
  var PYTHON_SCRIPT = `#!/usr/bin/env python3
85545
85447
  import sys
85546
85448
  import json
@@ -85642,7 +85544,7 @@ function validateArgs(args) {
85642
85544
  if (!args.file_path) {
85643
85545
  return "Error: 'file_path' is required.";
85644
85546
  }
85645
- if (!existsSync62(args.file_path)) {
85547
+ if (!existsSync61(args.file_path)) {
85646
85548
  return `Error: File not found: ${args.file_path}`;
85647
85549
  }
85648
85550
  if (!args.file_path.toLowerCase().endsWith(".pdf")) {
@@ -85691,11 +85593,11 @@ async function runExtraction(args) {
85691
85593
  }
85692
85594
  let tmpDir;
85693
85595
  try {
85694
- tmpDir = mkdtempSync(join65(tmpdir5(), "matrixx-pdf-extract-"));
85596
+ tmpDir = mkdtempSync(join64(tmpdir5(), "matrixx-pdf-extract-"));
85695
85597
  } catch {
85696
85598
  return "Error: Could not create temporary directory.";
85697
85599
  }
85698
- const scriptPath = join65(tmpDir, "extract_pdf_figures.py");
85600
+ const scriptPath = join64(tmpDir, "extract_pdf_figures.py");
85699
85601
  writeFileSync23(scriptPath, PYTHON_SCRIPT);
85700
85602
  const payload = buildArgsPayload(args);
85701
85603
  log("[pdf_extract_figures] Running extraction", { file_path: args.file_path, payload });
@@ -85743,11 +85645,11 @@ function createPdfExtractFiguresTool() {
85743
85645
  return { pdf_extract_figures };
85744
85646
  }
85745
85647
  // src/tools/plan/plan-create.ts
85746
- import { existsSync as existsSync63 } from "fs";
85648
+ import { existsSync as existsSync62 } from "fs";
85747
85649
  import { basename as basename7 } from "path";
85748
85650
 
85749
85651
  // src/tools/plan/types.ts
85750
- import { basename as basename6, isAbsolute as isAbsolute5, join as join66, relative as relative4, resolve as resolve9 } from "path";
85652
+ import { basename as basename6, isAbsolute as isAbsolute5, join as join65, relative as relative4, resolve as resolve8 } from "path";
85751
85653
 
85752
85654
  // src/tools/plan/constants.ts
85753
85655
  var PLANS_DIR3 = ".matrixx/plans";
@@ -85773,8 +85675,8 @@ function validatePlanFilePath(filePath, directory) {
85773
85675
  if (!PLAN_FILENAME_KEBAB_REGEX.test(base)) {
85774
85676
  return { error: `fileName must match kebab-case ^[a-z0-9-]+\\.md$: ${base}` };
85775
85677
  }
85776
- const resolved = isAbsolute5(filePath) ? resolve9(filePath) : resolve9(join66(directory, filePath));
85777
- const plansDir = resolve9(join66(directory, PLANS_DIR3));
85678
+ const resolved = isAbsolute5(filePath) ? resolve8(filePath) : resolve8(join65(directory, filePath));
85679
+ const plansDir = resolve8(join65(directory, PLANS_DIR3));
85778
85680
  const relToPlans = relative4(plansDir, resolved);
85779
85681
  if (relToPlans.startsWith("..") || isAbsolute5(relToPlans)) {
85780
85682
  return { error: `filePath must be inside ${PLANS_DIR3}: ${filePath}` };
@@ -85817,7 +85719,7 @@ Uses atomicWrite (.tmp.pid+rename) + upsertMetadataComment. Warns if file alread
85817
85719
  }
85818
85720
  const resolved = validation.resolved;
85819
85721
  ensurePlanDir(directory);
85820
- if (existsSync63(resolved)) {
85722
+ if (existsSync62(resolved)) {
85821
85723
  return JSON.stringify({
85822
85724
  error: "file_exists",
85823
85725
  message: `Plan file already exists: ${resolved}. Use plan_read + plan_update to modify.`,
@@ -85848,7 +85750,7 @@ Uses atomicWrite (.tmp.pid+rename) + upsertMetadataComment. Warns if file alread
85848
85750
  });
85849
85751
  }
85850
85752
  // src/tools/plan/plan-delete.ts
85851
- import { existsSync as existsSync64, unlinkSync as unlinkSync10 } from "fs";
85753
+ import { existsSync as existsSync63, unlinkSync as unlinkSync10 } from "fs";
85852
85754
  function createPlanDeleteTool(ctx) {
85853
85755
  return tool({
85854
85756
  description: `Delete a plan file under .matrixx/plans/*.md. Scoped unlink inside PLANS_DIR, refuses outside paths.`,
@@ -85864,7 +85766,7 @@ function createPlanDeleteTool(ctx) {
85864
85766
  return JSON.stringify({ error: "invalid_file_path", message: validation.error });
85865
85767
  }
85866
85768
  const resolved = validation.resolved;
85867
- if (!existsSync64(resolved)) {
85769
+ if (!existsSync63(resolved)) {
85868
85770
  return JSON.stringify({ error: "file_not_found", message: `File not found: ${resolved}` });
85869
85771
  }
85870
85772
  unlinkSync10(resolved);
@@ -85877,8 +85779,8 @@ function createPlanDeleteTool(ctx) {
85877
85779
  });
85878
85780
  }
85879
85781
  // src/tools/plan/plan-list.ts
85880
- import { existsSync as existsSync65, readdirSync as readdirSync20, statSync as statSync15 } from "fs";
85881
- import { join as join67 } from "path";
85782
+ import { existsSync as existsSync64, readdirSync as readdirSync20, statSync as statSync13 } from "fs";
85783
+ import { join as join66 } from "path";
85882
85784
  function createPlanListTool(ctx) {
85883
85785
  return tool({
85884
85786
  description: `List plan files under .matrixx/plans/*.md. Filters *.md with kebab-case, sorts by mtime.`,
@@ -85886,15 +85788,15 @@ function createPlanListTool(ctx) {
85886
85788
  execute: async (_args, context) => {
85887
85789
  try {
85888
85790
  const directory = resolveDirectory(context?.directory, ctx?.directory);
85889
- const plansDir = join67(directory, PLANS_DIR3);
85890
- if (!existsSync65(plansDir)) {
85791
+ const plansDir = join66(directory, PLANS_DIR3);
85792
+ if (!existsSync64(plansDir)) {
85891
85793
  return JSON.stringify({ plans: [] });
85892
85794
  }
85893
85795
  const entries = readdirSync20(plansDir).filter((f) => f.endsWith(".md") && PLAN_FILENAME_KEBAB_REGEX.test(f));
85894
85796
  const plans = entries.map((fileName) => {
85895
- const filePath = join67(plansDir, fileName);
85797
+ const filePath = join66(plansDir, fileName);
85896
85798
  try {
85897
- const stat2 = statSync15(filePath);
85799
+ const stat2 = statSync13(filePath);
85898
85800
  return {
85899
85801
  fileName,
85900
85802
  filePath,
@@ -85915,7 +85817,7 @@ function createPlanListTool(ctx) {
85915
85817
  });
85916
85818
  }
85917
85819
  // src/tools/plan/plan-read.ts
85918
- import { existsSync as existsSync66, statSync as statSync16 } from "fs";
85820
+ import { existsSync as existsSync65, statSync as statSync14 } from "fs";
85919
85821
  function createPlanReadTool(ctx) {
85920
85822
  return tool({
85921
85823
  description: `Read a plan file from .matrixx/plans/*.md with hashline-tagged output (1#AB|content) + lsp-style. Enforces scoping and ${MAX_PLAN_FILE_BYTES2} byte cap.`,
@@ -85931,11 +85833,11 @@ function createPlanReadTool(ctx) {
85931
85833
  return JSON.stringify({ error: "invalid_file_path", message: validation.error });
85932
85834
  }
85933
85835
  const resolved = validation.resolved;
85934
- if (!existsSync66(resolved)) {
85836
+ if (!existsSync65(resolved)) {
85935
85837
  return JSON.stringify({ error: "file_not_found", message: `File not found: ${resolved}` });
85936
85838
  }
85937
85839
  try {
85938
- const stat2 = statSync16(resolved);
85840
+ const stat2 = statSync14(resolved);
85939
85841
  if (stat2.size > MAX_PLAN_FILE_BYTES2) {
85940
85842
  return JSON.stringify({
85941
85843
  error: "file_too_large",
@@ -85963,7 +85865,7 @@ function createPlanReadTool(ctx) {
85963
85865
  });
85964
85866
  }
85965
85867
  // src/tools/plan/plan-update.ts
85966
- import { existsSync as existsSync67 } from "fs";
85868
+ import { existsSync as existsSync66 } from "fs";
85967
85869
 
85968
85870
  // src/features/tool-metadata-store/store.ts
85969
85871
  var pendingStore = new Map;
@@ -87026,7 +86928,7 @@ function createPlanUpdateTool(ctx) {
87026
86928
  return JSON.stringify({ error: "invalid_file_path", message: validation.error });
87027
86929
  }
87028
86930
  const resolved = validation.resolved;
87029
- if (!existsSync67(resolved)) {
86931
+ if (!existsSync66(resolved)) {
87030
86932
  return JSON.stringify({ error: "file_not_found", message: `File not found: ${resolved}` });
87031
86933
  }
87032
86934
  const result = await executeHashlineEditTool({ filePath: resolved, edits }, context, ctx);
@@ -87039,9 +86941,9 @@ function createPlanUpdateTool(ctx) {
87039
86941
  });
87040
86942
  }
87041
86943
  // src/tools/preset/tools.ts
87042
- import { existsSync as existsSync68, mkdirSync as mkdirSync18, readFileSync as readFileSync40, writeFileSync as writeFileSync24 } from "fs";
86944
+ import { existsSync as existsSync67, mkdirSync as mkdirSync18, readFileSync as readFileSync41, writeFileSync as writeFileSync24 } from "fs";
87043
86945
  import { homedir as homedir10 } from "os";
87044
- import { dirname as dirname17, join as join68 } from "path";
86946
+ import { dirname as dirname15, join as join67 } from "path";
87045
86947
 
87046
86948
  // src/features/preset-state/manager.ts
87047
86949
  init_logger();
@@ -87060,15 +86962,15 @@ var ACTIONS = ["list", "show", "set"];
87060
86962
  var SCOPES = ["global", "project"];
87061
86963
  function resolveConfigPath(scope, directory) {
87062
86964
  if (scope === "global") {
87063
- return join68(homedir10(), ".config", "opencode", "matrixx.jsonc");
86965
+ return join67(homedir10(), ".config", "opencode", "matrixx.jsonc");
87064
86966
  }
87065
- return join68(directory ?? process.cwd(), ".opencode", "matrixx.jsonc");
86967
+ return join67(directory ?? process.cwd(), ".opencode", "matrixx.jsonc");
87066
86968
  }
87067
86969
  function persistActivePreset(presetName, scope, directory) {
87068
86970
  const configPath = resolveConfigPath(scope, directory);
87069
86971
  let raw = {};
87070
- if (existsSync68(configPath)) {
87071
- const content = readFileSync40(configPath, "utf-8");
86972
+ if (existsSync67(configPath)) {
86973
+ const content = readFileSync41(configPath, "utf-8");
87072
86974
  const parsed = parseJsoncSafe(content);
87073
86975
  if (parsed.errors.length > 0) {
87074
86976
  return {
@@ -87078,7 +86980,7 @@ function persistActivePreset(presetName, scope, directory) {
87078
86980
  }
87079
86981
  raw = parsed.data ?? {};
87080
86982
  } else {
87081
- mkdirSync18(dirname17(configPath), { recursive: true });
86983
+ mkdirSync18(dirname15(configPath), { recursive: true });
87082
86984
  }
87083
86985
  raw.active_preset = presetName;
87084
86986
  writeFileSync24(configPath, `${JSON.stringify(raw, null, 2)}
@@ -87181,9 +87083,9 @@ function createPresetTool(options) {
87181
87083
  return { preset };
87182
87084
  }
87183
87085
  // src/tools/session-manager/constants.ts
87184
- import { join as join69 } from "path";
87185
- var TODO_DIR = join69(getOpenCodeConfigDir({ binary: "opencode" }), "todos");
87186
- var TRANSCRIPT_DIR2 = join69(getOpenCodeConfigDir({ binary: "opencode" }), "transcripts");
87086
+ import { join as join68 } from "path";
87087
+ var TODO_DIR = join68(getOpenCodeConfigDir({ binary: "opencode" }), "todos");
87088
+ var TRANSCRIPT_DIR2 = join68(getOpenCodeConfigDir({ binary: "opencode" }), "transcripts");
87187
87089
  var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
87188
87090
 
87189
87091
  Returns a list of available session IDs with metadata including message count, date range, and agents used.
@@ -87255,9 +87157,9 @@ Agents Used: build, oracle, librarian
87255
87157
  Has Todos: Yes (12 items, 8 completed)
87256
87158
  Has Transcript: Yes (234 entries)`;
87257
87159
  // src/tools/session-manager/storage.ts
87258
- import { existsSync as existsSync69 } from "fs";
87160
+ import { existsSync as existsSync68 } from "fs";
87259
87161
  import { readdir, readFile as readFile3 } from "fs/promises";
87260
- import { join as join70 } from "path";
87162
+ import { join as join69 } from "path";
87261
87163
  var sdkClient = null;
87262
87164
  function setStorageClient(client2) {
87263
87165
  sdkClient = client2;
@@ -87276,7 +87178,7 @@ async function getMainSessions(options) {
87276
87178
  return [];
87277
87179
  }
87278
87180
  }
87279
- if (!existsSync69(SESSION_STORAGE))
87181
+ if (!existsSync68(SESSION_STORAGE))
87280
87182
  return [];
87281
87183
  const sessions = [];
87282
87184
  try {
@@ -87284,13 +87186,13 @@ async function getMainSessions(options) {
87284
87186
  for (const projectDir of projectDirs) {
87285
87187
  if (!projectDir.isDirectory())
87286
87188
  continue;
87287
- const projectPath = join70(SESSION_STORAGE, projectDir.name);
87189
+ const projectPath = join69(SESSION_STORAGE, projectDir.name);
87288
87190
  const sessionFiles = await readdir(projectPath);
87289
87191
  for (const file3 of sessionFiles) {
87290
87192
  if (!file3.endsWith(".json"))
87291
87193
  continue;
87292
87194
  try {
87293
- const content = await readFile3(join70(projectPath, file3), "utf-8");
87195
+ const content = await readFile3(join69(projectPath, file3), "utf-8");
87294
87196
  const meta3 = JSON.parse(content);
87295
87197
  if (meta3.parentID)
87296
87198
  continue;
@@ -87315,7 +87217,7 @@ async function getAllSessions() {
87315
87217
  return [];
87316
87218
  }
87317
87219
  }
87318
- if (!existsSync69(MESSAGE_STORAGE))
87220
+ if (!existsSync68(MESSAGE_STORAGE))
87319
87221
  return [];
87320
87222
  const sessions = [];
87321
87223
  async function scanDirectory(dir) {
@@ -87323,7 +87225,7 @@ async function getAllSessions() {
87323
87225
  const entries = await readdir(dir, { withFileTypes: true });
87324
87226
  for (const entry of entries) {
87325
87227
  if (entry.isDirectory()) {
87326
- const sessionPath = join70(dir, entry.name);
87228
+ const sessionPath = join69(dir, entry.name);
87327
87229
  const files = await readdir(sessionPath);
87328
87230
  if (files.some((f) => f.endsWith(".json"))) {
87329
87231
  sessions.push(entry.name);
@@ -87384,7 +87286,7 @@ async function readSessionMessages(sessionID) {
87384
87286
  }
87385
87287
  }
87386
87288
  const messageDir = getMessageDir(sessionID);
87387
- if (!messageDir || !existsSync69(messageDir))
87289
+ if (!messageDir || !existsSync68(messageDir))
87388
87290
  return [];
87389
87291
  const messages2 = [];
87390
87292
  try {
@@ -87393,7 +87295,7 @@ async function readSessionMessages(sessionID) {
87393
87295
  if (!file3.endsWith(".json"))
87394
87296
  continue;
87395
87297
  try {
87396
- const content = await readFile3(join70(messageDir, file3), "utf-8");
87298
+ const content = await readFile3(join69(messageDir, file3), "utf-8");
87397
87299
  const meta3 = JSON.parse(content);
87398
87300
  const parts = await readParts2(meta3.id);
87399
87301
  messages2.push({
@@ -87417,8 +87319,8 @@ async function readSessionMessages(sessionID) {
87417
87319
  });
87418
87320
  }
87419
87321
  async function readParts2(messageID) {
87420
- const partDir = join70(PART_STORAGE, messageID);
87421
- if (!existsSync69(partDir))
87322
+ const partDir = join69(PART_STORAGE, messageID);
87323
+ if (!existsSync68(partDir))
87422
87324
  return [];
87423
87325
  const parts = [];
87424
87326
  try {
@@ -87427,7 +87329,7 @@ async function readParts2(messageID) {
87427
87329
  if (!file3.endsWith(".json"))
87428
87330
  continue;
87429
87331
  try {
87430
- const content = await readFile3(join70(partDir, file3), "utf-8");
87332
+ const content = await readFile3(join69(partDir, file3), "utf-8");
87431
87333
  parts.push(JSON.parse(content));
87432
87334
  } catch {}
87433
87335
  }
@@ -87451,14 +87353,14 @@ async function readSessionTodos(sessionID) {
87451
87353
  return [];
87452
87354
  }
87453
87355
  }
87454
- if (!existsSync69(TODO_DIR))
87356
+ if (!existsSync68(TODO_DIR))
87455
87357
  return [];
87456
87358
  try {
87457
87359
  const allFiles = await readdir(TODO_DIR);
87458
87360
  const todoFiles = allFiles.filter((f) => f.includes(sessionID) && f.endsWith(".json"));
87459
87361
  for (const file3 of todoFiles) {
87460
87362
  try {
87461
- const content = await readFile3(join70(TODO_DIR, file3), "utf-8");
87363
+ const content = await readFile3(join69(TODO_DIR, file3), "utf-8");
87462
87364
  const data = JSON.parse(content);
87463
87365
  if (Array.isArray(data)) {
87464
87366
  return data.map((item) => ({
@@ -87476,10 +87378,10 @@ async function readSessionTodos(sessionID) {
87476
87378
  return [];
87477
87379
  }
87478
87380
  async function readSessionTranscript(sessionID) {
87479
- if (!existsSync69(TRANSCRIPT_DIR2))
87381
+ if (!existsSync68(TRANSCRIPT_DIR2))
87480
87382
  return 0;
87481
- const transcriptFile = join70(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
87482
- if (!existsSync69(transcriptFile))
87383
+ const transcriptFile = join69(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
87384
+ if (!existsSync68(transcriptFile))
87483
87385
  return 0;
87484
87386
  try {
87485
87387
  const content = await readFile3(transcriptFile, "utf-8");
@@ -87979,20 +87881,20 @@ function createSkillTool(options = {}) {
87979
87881
  }
87980
87882
  var skill = createSkillTool();
87981
87883
  // src/tools/slashcommand/command-discovery.ts
87982
- import { existsSync as existsSync70, readdirSync as readdirSync21, readFileSync as readFileSync41 } from "fs";
87983
- import { basename as basename8, join as join71 } from "path";
87884
+ import { existsSync as existsSync69, readdirSync as readdirSync21, readFileSync as readFileSync42 } from "fs";
87885
+ import { basename as basename8, join as join70 } from "path";
87984
87886
  function discoverCommandsFromDir2(commandsDir, scope) {
87985
- if (!existsSync70(commandsDir))
87887
+ if (!existsSync69(commandsDir))
87986
87888
  return [];
87987
87889
  const entries = readdirSync21(commandsDir, { withFileTypes: true });
87988
87890
  const commands2 = [];
87989
87891
  for (const entry of entries) {
87990
87892
  if (!isMarkdownFile(entry))
87991
87893
  continue;
87992
- const commandPath = join71(commandsDir, entry.name);
87894
+ const commandPath = join70(commandsDir, entry.name);
87993
87895
  const commandName = basename8(entry.name, ".md");
87994
87896
  try {
87995
- const content = readFileSync41(commandPath, "utf-8");
87897
+ const content = readFileSync42(commandPath, "utf-8");
87996
87898
  const { data, body } = parseFrontmatter(content);
87997
87899
  const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
87998
87900
  const metadata = {
@@ -88016,8 +87918,8 @@ function discoverCommandsFromDir2(commandsDir, scope) {
88016
87918
  }
88017
87919
  function discoverCommandsSync(directory) {
88018
87920
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
88019
- const opencodeGlobalDir = join71(configDir, "command");
88020
- const opencodeProjectDir = join71(directory ?? process.cwd(), ".opencode", "command");
87921
+ const opencodeGlobalDir = join70(configDir, "command");
87922
+ const opencodeProjectDir = join70(directory ?? process.cwd(), ".opencode", "command");
88021
87923
  const opencodeGlobalCommands = discoverCommandsFromDir2(opencodeGlobalDir, "opencode");
88022
87924
  const opencodeProjectCommands = discoverCommandsFromDir2(opencodeProjectDir, "opencode-project");
88023
87925
  const builtinCommandsMap = loadBuiltinCommands();
@@ -88041,7 +87943,7 @@ function discoverCommandsSync(directory) {
88041
87943
  ];
88042
87944
  }
88043
87945
  // src/tools/slashcommand/command-output-formatter.ts
88044
- import { dirname as dirname18 } from "path";
87946
+ import { dirname as dirname16 } from "path";
88045
87947
  async function formatLoadedCommand(command, userMessage) {
88046
87948
  const sections = [];
88047
87949
  sections.push(`# /${command.name} Command
@@ -88080,7 +87982,7 @@ async function formatLoadedCommand(command, userMessage) {
88080
87982
  if (!content && command.lazyContentLoader) {
88081
87983
  content = await command.lazyContentLoader.load();
88082
87984
  }
88083
- const commandDir = command.path ? dirname18(command.path) : process.cwd();
87985
+ const commandDir = command.path ? dirname16(command.path) : process.cwd();
88084
87986
  const withFileReferences = await resolveFileReferencesInText(content, commandDir);
88085
87987
  const resolvedContent = await resolveCommandsInText(withFileReferences);
88086
87988
  let finalContent = resolvedContent.trim();
@@ -88821,11 +88723,11 @@ function createBackgroundOutput(manager, client2) {
88821
88723
  });
88822
88724
  }
88823
88725
  // src/tools/background-task/create-background-revive.ts
88824
- import { existsSync as existsSync72 } from "fs";
88726
+ import { existsSync as existsSync71 } from "fs";
88825
88727
 
88826
88728
  // src/features/background-agent/handle-index.ts
88827
- import { existsSync as existsSync71, mkdirSync as mkdirSync19, readdirSync as readdirSync22, readFileSync as readFileSync42, renameSync as renameSync5, unlinkSync as unlinkSync11, writeFileSync as writeFileSync25 } from "fs";
88828
- import { dirname as dirname19, join as join72 } from "path";
88729
+ import { existsSync as existsSync70, mkdirSync as mkdirSync19, readdirSync as readdirSync22, readFileSync as readFileSync43, renameSync as renameSync5, unlinkSync as unlinkSync11, writeFileSync as writeFileSync25 } from "fs";
88730
+ import { dirname as dirname17, join as join71 } from "path";
88829
88731
 
88830
88732
  // src/features/background-agent/constants.ts
88831
88733
  var TASK_TTL_MS = 30 * 60 * 1000;
@@ -88876,13 +88778,13 @@ var BgHandleSchema = exports_external.object({
88876
88778
  completedAt: exports_external.number().optional()
88877
88779
  }).strict();
88878
88780
  function getBgHandleDir(directory) {
88879
- return join72(directory, ".matrixx", BG_HANDLE_DIR_NAME);
88781
+ return join71(directory, ".matrixx", BG_HANDLE_DIR_NAME);
88880
88782
  }
88881
88783
  function getHandlePath(directory, taskId) {
88882
- return join72(getBgHandleDir(directory), `${taskId}.json`);
88784
+ return join71(getBgHandleDir(directory), `${taskId}.json`);
88883
88785
  }
88884
88786
  function ensureDir3(dirPath) {
88885
- if (!existsSync71(dirPath)) {
88787
+ if (!existsSync70(dirPath)) {
88886
88788
  mkdirSync19(dirPath, { recursive: true });
88887
88789
  }
88888
88790
  }
@@ -88906,14 +88808,14 @@ function toHandle(task) {
88906
88808
  }
88907
88809
  function writeHandle(directory, task) {
88908
88810
  const filePath = getHandlePath(directory, task.id);
88909
- ensureDir3(dirname19(filePath));
88811
+ ensureDir3(dirname17(filePath));
88910
88812
  const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
88911
88813
  try {
88912
88814
  writeFileSync25(tempPath, JSON.stringify(toHandle(task), null, 2), "utf-8");
88913
88815
  renameSync5(tempPath, filePath);
88914
88816
  } catch (error95) {
88915
88817
  try {
88916
- if (existsSync71(tempPath)) {
88818
+ if (existsSync70(tempPath)) {
88917
88819
  unlinkSync11(tempPath);
88918
88820
  }
88919
88821
  } catch {}
@@ -88922,10 +88824,10 @@ function writeHandle(directory, task) {
88922
88824
  }
88923
88825
  function readHandleFile(filePath) {
88924
88826
  try {
88925
- if (!existsSync71(filePath)) {
88827
+ if (!existsSync70(filePath)) {
88926
88828
  return null;
88927
88829
  }
88928
- const parsed = JSON.parse(readFileSync42(filePath, "utf-8"));
88830
+ const parsed = JSON.parse(readFileSync43(filePath, "utf-8"));
88929
88831
  const result = BgHandleSchema.safeParse(parsed);
88930
88832
  return result.success ? result.data : null;
88931
88833
  } catch {
@@ -88934,7 +88836,7 @@ function readHandleFile(filePath) {
88934
88836
  }
88935
88837
  function readHandles(directory) {
88936
88838
  const dir = getBgHandleDir(directory);
88937
- if (!existsSync71(dir)) {
88839
+ if (!existsSync70(dir)) {
88938
88840
  return [];
88939
88841
  }
88940
88842
  const handles = [];
@@ -88942,7 +88844,7 @@ function readHandles(directory) {
88942
88844
  if (!name.startsWith(BG_HANDLE_FILE_PREFIX) || !name.endsWith(".json")) {
88943
88845
  continue;
88944
88846
  }
88945
- const handle = readHandleFile(join72(dir, name));
88847
+ const handle = readHandleFile(join71(dir, name));
88946
88848
  if (handle) {
88947
88849
  handles.push(handle);
88948
88850
  }
@@ -88951,7 +88853,7 @@ function readHandles(directory) {
88951
88853
  }
88952
88854
  function sweepStaleHandles(directory, ttlMs = TASK_TTL_MS, now = Date.now()) {
88953
88855
  const dir = getBgHandleDir(directory);
88954
- if (!existsSync71(dir)) {
88856
+ if (!existsSync70(dir)) {
88955
88857
  return 0;
88956
88858
  }
88957
88859
  let removed = 0;
@@ -88959,7 +88861,7 @@ function sweepStaleHandles(directory, ttlMs = TASK_TTL_MS, now = Date.now()) {
88959
88861
  if (!name.startsWith(BG_HANDLE_FILE_PREFIX) || !name.endsWith(".json")) {
88960
88862
  continue;
88961
88863
  }
88962
- const filePath = join72(dir, name);
88864
+ const filePath = join71(dir, name);
88963
88865
  const handle = readHandleFile(filePath);
88964
88866
  const timestamp = handle?.completedAt ?? handle?.startedAt ?? handle?.queuedAt;
88965
88867
  if (handle && timestamp !== undefined && now - timestamp <= ttlMs) {
@@ -89027,7 +88929,7 @@ Revive one with background_revive(taskId="<id>", prompt="<new instruction>").`;
89027
88929
  }
89028
88930
  function resolveFailure(identifier, message, directory) {
89029
88931
  if (message.includes("not found for revive")) {
89030
- const handleOnDisk = existsSync72(getHandlePath(directory, identifier));
88932
+ const handleOnDisk = existsSync71(getHandlePath(directory, identifier));
89031
88933
  return { reason: handleOnDisk ? "unknown-task" : "expired", detail: message };
89032
88934
  }
89033
88935
  if (message.includes("still active"))
@@ -89442,9 +89344,9 @@ function createAssemblyTool(options) {
89442
89344
  });
89443
89345
  }
89444
89346
  // src/tools/dcp-switch-profile/tools.ts
89445
- import { existsSync as existsSync73, writeFileSync as writeFileSync26 } from "fs";
89347
+ import { existsSync as existsSync72, writeFileSync as writeFileSync26 } from "fs";
89446
89348
  import { homedir as homedir11 } from "os";
89447
- import { join as join73 } from "path";
89349
+ import { join as join72 } from "path";
89448
89350
 
89449
89351
  // src/config/schema/dcp.ts
89450
89352
  var DcpCompressOverrideSchema = exports_external.object({
@@ -89644,11 +89546,11 @@ var DcpConfigSchema = exports_external.object({
89644
89546
  });
89645
89547
 
89646
89548
  // src/tools/dcp-switch-profile/tools.ts
89647
- var DCP_PLUGIN_DIR = join73(homedir11(), ".config", "opencode", "node_modules", "@tarquinen", "opencode-dcp");
89648
- var DCP_SYMLINK = join73(homedir11(), ".config", "opencode", "dcp.jsonc");
89549
+ var DCP_PLUGIN_DIR = join72(homedir11(), ".config", "opencode", "node_modules", "@tarquinen", "opencode-dcp");
89550
+ var DCP_SYMLINK = join72(homedir11(), ".config", "opencode", "dcp.jsonc");
89649
89551
  var VALID_PROFILES = ["economy", "balanced", "performance", "ultimate", "brutal"];
89650
89552
  function checkDcpInstalled() {
89651
- if (!existsSync73(DCP_PLUGIN_DIR)) {
89553
+ if (!existsSync72(DCP_PLUGIN_DIR)) {
89652
89554
  return `DCP is not installed at ${DCP_PLUGIN_DIR}. Install it with: npm install --prefix ~/.config/opencode @tarquinen/opencode-dcp`;
89653
89555
  }
89654
89556
  return null;
@@ -90571,7 +90473,7 @@ async function executeBackgroundTask(args, ctx, executorCtx, parentContext, agen
90571
90473
 
90572
90474
  Task ID: ${task.id}`;
90573
90475
  }
90574
- await new Promise((resolve10) => setTimeout(resolve10, timing.WAIT_FOR_SESSION_INTERVAL_MS));
90476
+ await new Promise((resolve9) => setTimeout(resolve9, timing.WAIT_FOR_SESSION_INTERVAL_MS));
90575
90477
  const updated = manager.getTask(task.id);
90576
90478
  if (updated && isLaunchTerminalStatus(updated.status)) {
90577
90479
  if (isQueueSaturated(updated.status, updated.terminalReason)) {
@@ -91106,10 +91008,11 @@ Create the work plan directly - that's your job as the planning agent.`
91106
91008
  if (!matchedAgent) {
91107
91009
  const isPrimaryAgent = agents.filter((a) => a.mode === "primary").find((agent) => agent.name.toLowerCase() === agentToUse.toLowerCase() || agent.name.toLowerCase() === resolvedDisplayName.toLowerCase());
91108
91010
  if (isPrimaryAgent) {
91011
+ const architectHint = isPrimaryAgent.name.toLowerCase() === "architect" ? " Use /start-work to run Architect as session agent (issue #111 option b)." : "";
91109
91012
  return {
91110
91013
  agentToUse: "",
91111
91014
  categoryModel: undefined,
91112
- error: `Cannot call primary agent "${isPrimaryAgent.name}" via task. Primary agents are top-level orchestrators.`
91015
+ error: `Cannot call primary agent "${isPrimaryAgent.name}" via task. Primary agents are top-level orchestrators.${architectHint}`
91113
91016
  };
91114
91017
  }
91115
91018
  const availableAgents = callableAgents.map((a) => a.name).sort().join(", ");
@@ -91536,7 +91439,7 @@ async function pollSyncSession(ctx, client2, input) {
91536
91439
 
91537
91440
  Session ID: ${input.sessionID}`;
91538
91441
  }
91539
- await new Promise((resolve10) => setTimeout(resolve10, syncTiming.POLL_INTERVAL_MS));
91442
+ await new Promise((resolve9) => setTimeout(resolve9, syncTiming.POLL_INTERVAL_MS));
91540
91443
  pollCount++;
91541
91444
  let statusResult;
91542
91445
  try {
@@ -92083,7 +91986,7 @@ async function executeUnstableAgentTask(args, ctx, executorCtx, parentContext, a
92083
91986
 
92084
91987
  Task ID: ${task.id}`;
92085
91988
  }
92086
- await new Promise((resolve10) => setTimeout(resolve10, timing.WAIT_FOR_SESSION_INTERVAL_MS));
91989
+ await new Promise((resolve9) => setTimeout(resolve9, timing.WAIT_FOR_SESSION_INTERVAL_MS));
92087
91990
  const updated = manager.getTask(task.id);
92088
91991
  sessionID = updated?.sessionID;
92089
91992
  }
@@ -92124,7 +92027,7 @@ Task ID: ${task.id}`;
92124
92027
 
92125
92028
  Session ID: ${sessionID}`;
92126
92029
  }
92127
- await new Promise((resolve10) => setTimeout(resolve10, timingCfg.POLL_INTERVAL_MS));
92030
+ await new Promise((resolve9) => setTimeout(resolve9, timingCfg.POLL_INTERVAL_MS));
92128
92031
  const currentTask = manager.getTask(task.id);
92129
92032
  if (currentTask && (currentTask.status === "interrupt" || currentTask.status === "error" || currentTask.status === "cancelled")) {
92130
92033
  terminalStatus = { status: currentTask.status, error: currentTask.error };
@@ -92768,8 +92671,8 @@ Original error: ${createResult.error}`;
92768
92671
  });
92769
92672
  }
92770
92673
  // src/tools/task/task-cleanup.ts
92771
- import { existsSync as existsSync74, readdirSync as readdirSync23, readFileSync as readFileSync43, unlinkSync as unlinkSync12 } from "fs";
92772
- import { join as join74 } from "path";
92674
+ import { existsSync as existsSync73, readdirSync as readdirSync23, readFileSync as readFileSync44, unlinkSync as unlinkSync12 } from "fs";
92675
+ import { join as join73 } from "path";
92773
92676
  init_logger();
92774
92677
  function parseOlderThan(value) {
92775
92678
  const match = value.trim().match(/^(\d+)(d|h|m)$/);
@@ -92829,17 +92732,17 @@ Returns counts: {deleted, remaining, deletedIds}`,
92829
92732
  }
92830
92733
  const directory = context?.directory ?? ctx?.directory ?? process.cwd();
92831
92734
  const taskDir = getTaskDir(config4, directory);
92832
- if (!existsSync74(taskDir)) {
92735
+ if (!existsSync73(taskDir)) {
92833
92736
  return JSON.stringify({ deleted: 0, remaining: 0, deletedIds: [] });
92834
92737
  }
92835
92738
  const files = readdirSync23(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-"));
92836
92739
  const total = files.length;
92837
92740
  const deletedIds = [];
92838
92741
  for (const file3 of files) {
92839
- const filePath = join74(taskDir, file3);
92742
+ const filePath = join73(taskDir, file3);
92840
92743
  let raw;
92841
92744
  try {
92842
- const content = readFileSync43(filePath, "utf-8");
92745
+ const content = readFileSync44(filePath, "utf-8");
92843
92746
  raw = JSON.parse(content);
92844
92747
  } catch {
92845
92748
  continue;
@@ -92872,8 +92775,8 @@ Returns counts: {deleted, remaining, deletedIds}`,
92872
92775
  });
92873
92776
  }
92874
92777
  // src/tools/task/task-create.ts
92875
- import { readdirSync as readdirSync24, statSync as statSync17 } from "fs";
92876
- import { join as join75 } from "path";
92778
+ import { readdirSync as readdirSync24, statSync as statSync15 } from "fs";
92779
+ import { join as join74 } from "path";
92877
92780
  init_logger();
92878
92781
  function createTaskCreateTool(config4, ctx) {
92879
92782
  return tool({
@@ -92942,7 +92845,7 @@ async function handleCreate2(args, config4, ctx, context) {
92942
92845
  projectRoot: directory
92943
92846
  };
92944
92847
  const validatedTask = TaskObjectSchema.parse(task);
92945
- writeJsonAtomic(join75(taskDir, `${taskId}.json`), validatedTask);
92848
+ writeJsonAtomic(join74(taskDir, `${taskId}.json`), validatedTask);
92946
92849
  return JSON.stringify({
92947
92850
  task: {
92948
92851
  id: validatedTask.id,
@@ -92971,7 +92874,7 @@ function findDuplicateTask(taskDir, subject, directory) {
92971
92874
  return null;
92972
92875
  }
92973
92876
  for (const file3 of files) {
92974
- const filePath = join75(taskDir, file3);
92877
+ const filePath = join74(taskDir, file3);
92975
92878
  let existing;
92976
92879
  try {
92977
92880
  existing = readJsonSafe(filePath, TaskObjectSchema);
@@ -92990,7 +92893,7 @@ function findDuplicateTask(taskDir, subject, directory) {
92990
92893
  continue;
92991
92894
  let mtimeMs;
92992
92895
  try {
92993
- mtimeMs = statSync17(filePath).mtimeMs;
92896
+ mtimeMs = statSync15(filePath).mtimeMs;
92994
92897
  } catch (error95) {
92995
92898
  log(`[task-create] Failed to stat task file ${filePath} during dedup scan`, error95);
92996
92899
  continue;
@@ -93002,7 +92905,7 @@ function findDuplicateTask(taskDir, subject, directory) {
93002
92905
  return null;
93003
92906
  }
93004
92907
  // src/tools/task/task-get.ts
93005
- import { join as join76 } from "path";
92908
+ import { join as join75 } from "path";
93006
92909
  function parseTaskId(id) {
93007
92910
  if (!TASK_ID_PATTERN.test(id))
93008
92911
  return null;
@@ -93028,7 +92931,7 @@ Returns null if the task does not exist or the file is invalid.`,
93028
92931
  }
93029
92932
  const directory = context?.directory ?? ctx?.directory ?? process.cwd();
93030
92933
  const taskDir = getTaskDir(config4, directory);
93031
- const taskPath = join76(taskDir, `${taskId}.json`);
92934
+ const taskPath = join75(taskDir, `${taskId}.json`);
93032
92935
  const task = readJsonSafe(taskPath, TaskObjectSchema);
93033
92936
  return JSON.stringify({ task: task ?? null });
93034
92937
  } catch (error95) {
@@ -93041,8 +92944,8 @@ Returns null if the task does not exist or the file is invalid.`,
93041
92944
  });
93042
92945
  }
93043
92946
  // src/tools/task/task-list.ts
93044
- import { existsSync as existsSync75, readdirSync as readdirSync25 } from "fs";
93045
- import { join as join77 } from "path";
92947
+ import { existsSync as existsSync74, readdirSync as readdirSync25 } from "fs";
92948
+ import { join as join76 } from "path";
93046
92949
  function createTaskList(config4, ctx) {
93047
92950
  return tool({
93048
92951
  description: `[TRACKING \u2014 local progress records only. Spawns nothing, executes nothing.]
@@ -93061,7 +92964,7 @@ Optional \`parentID\` filter: when provided, returns only tasks whose parentID m
93061
92964
  const parentID = args.parentID;
93062
92965
  const directory = context?.directory ?? ctx?.directory ?? process.cwd();
93063
92966
  const taskDir = getTaskDir(config4, directory);
93064
- if (!existsSync75(taskDir)) {
92967
+ if (!existsSync74(taskDir)) {
93065
92968
  return JSON.stringify({ tasks: [] });
93066
92969
  }
93067
92970
  const files = readdirSync25(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-")).map((f) => f.replace(".json", ""));
@@ -93070,7 +92973,7 @@ Optional \`parentID\` filter: when provided, returns only tasks whose parentID m
93070
92973
  }
93071
92974
  const allTasks = [];
93072
92975
  for (const fileId of files) {
93073
- const task = readJsonSafe(join77(taskDir, `${fileId}.json`), TaskObjectSchema);
92976
+ const task = readJsonSafe(join76(taskDir, `${fileId}.json`), TaskObjectSchema);
93074
92977
  if (task) {
93075
92978
  allTasks.push(task);
93076
92979
  }
@@ -93099,7 +93002,7 @@ Optional \`parentID\` filter: when provided, returns only tasks whose parentID m
93099
93002
  });
93100
93003
  }
93101
93004
  // src/tools/task/task-update.ts
93102
- import { join as join78 } from "path";
93005
+ import { join as join77 } from "path";
93103
93006
  function parseTaskId2(id) {
93104
93007
  if (!TASK_ID_PATTERN.test(id))
93105
93008
  return null;
@@ -93146,7 +93049,7 @@ async function handleUpdate(args, config4, ctx, context) {
93146
93049
  return JSON.stringify({ error: "task_lock_unavailable" });
93147
93050
  }
93148
93051
  try {
93149
- const taskPath = join78(taskDir, `${taskId}.json`);
93052
+ const taskPath = join77(taskDir, `${taskId}.json`);
93150
93053
  const task = readJsonSafe(taskPath, TaskObjectSchema);
93151
93054
  if (!task) {
93152
93055
  return JSON.stringify({ error: "task_not_found" });
@@ -93682,7 +93585,7 @@ class ConcurrencyManager {
93682
93585
  if (this.tryAcquireSlot(model)) {
93683
93586
  return { granted: true };
93684
93587
  }
93685
- return new Promise((resolve10) => {
93588
+ return new Promise((resolve9) => {
93686
93589
  const queue = this.queues.get(model) ?? [];
93687
93590
  let timer;
93688
93591
  const entry = {
@@ -93694,7 +93597,7 @@ class ConcurrencyManager {
93694
93597
  entry.settled = true;
93695
93598
  if (timer !== undefined)
93696
93599
  clearTimeout(timer);
93697
- resolve10(outcome);
93600
+ resolve9(outcome);
93698
93601
  }
93699
93602
  };
93700
93603
  queue.push(entry);
@@ -93711,7 +93614,7 @@ class ConcurrencyManager {
93711
93614
  if (index !== -1)
93712
93615
  pending.splice(index, 1);
93713
93616
  }
93714
- resolve10({ granted: false, reason: "timeout", waitedMs: Date.now() - entry.enqueuedAt });
93617
+ resolve9({ granted: false, reason: "timeout", waitedMs: Date.now() - entry.enqueuedAt });
93715
93618
  }, timeoutMs);
93716
93619
  });
93717
93620
  }
@@ -93910,19 +93813,19 @@ function detectRepetitiveToolUse(window2) {
93910
93813
  }
93911
93814
 
93912
93815
  // src/features/background-agent/message-dir.ts
93913
- import { existsSync as existsSync76, readdirSync as readdirSync26, readFileSync as readFileSync44 } from "fs";
93914
- import { join as join79 } from "path";
93816
+ import { existsSync as existsSync75, readdirSync as readdirSync26, readFileSync as readFileSync45 } from "fs";
93817
+ import { join as join78 } from "path";
93915
93818
  var MESSAGE_DIR_CACHE_CAP = 1000;
93916
93819
  var messageDirCache = new Map;
93917
93820
  function computeMessageDir(sessionID) {
93918
- if (!existsSync76(MESSAGE_STORAGE))
93821
+ if (!existsSync75(MESSAGE_STORAGE))
93919
93822
  return null;
93920
- const directPath = join79(MESSAGE_STORAGE, sessionID);
93921
- if (existsSync76(directPath))
93823
+ const directPath = join78(MESSAGE_STORAGE, sessionID);
93824
+ if (existsSync75(directPath))
93922
93825
  return directPath;
93923
93826
  for (const dir of readdirSync26(MESSAGE_STORAGE)) {
93924
- const sessionPath = join79(MESSAGE_STORAGE, dir, sessionID);
93925
- if (existsSync76(sessionPath))
93827
+ const sessionPath = join78(MESSAGE_STORAGE, dir, sessionID);
93828
+ if (existsSync75(sessionPath))
93926
93829
  return sessionPath;
93927
93830
  }
93928
93831
  return null;
@@ -93960,7 +93863,7 @@ function findNearestMessageExcludingCompaction(messageDir) {
93960
93863
  const parsedByFile = new Map;
93961
93864
  for (const file3 of files) {
93962
93865
  try {
93963
- const content = readFileSync44(join79(messageDir, file3), "utf-8");
93866
+ const content = readFileSync45(join78(messageDir, file3), "utf-8");
93964
93867
  const parsed = JSON.parse(content);
93965
93868
  parsedByFile.set(file3, parsed);
93966
93869
  if (hasFullAgentAndModel(parsed)) {
@@ -96842,7 +96745,7 @@ class TmuxSessionManager {
96842
96745
  } catch (err) {
96843
96746
  log("[tmux-session-manager] session status check error", { error: String(err) });
96844
96747
  }
96845
- await new Promise((resolve10) => setTimeout(resolve10, SESSION_READY_POLL_INTERVAL_MS));
96748
+ await new Promise((resolve9) => setTimeout(resolve9, SESSION_READY_POLL_INTERVAL_MS));
96846
96749
  }
96847
96750
  log("[tmux-session-manager] session ready timeout", {
96848
96751
  sessionId,
@@ -97025,7 +96928,7 @@ class TmuxSessionManager {
97025
96928
  var SESSION_TIMEOUT_MS3 = 10 * 60 * 1000;
97026
96929
  var MIN_STABILITY_TIME_MS4 = 10 * 1000;
97027
96930
  // src/agents/dynamic-agent-prompt-builder.ts
97028
- import { readFileSync as readFileSync45 } from "fs";
96931
+ import { readFileSync as readFileSync46 } from "fs";
97029
96932
  init_logger();
97030
96933
  function categorizeTools(toolNames) {
97031
96934
  return toolNames.map((name) => {
@@ -97313,6 +97216,28 @@ Oracle creates plans, not code. Invoke oracle to decompose complex requests into
97313
97216
  **Exception**: This is the ONLY case where you announce before acting. For all other work, start immediately without status updates.
97314
97217
  </Oracle_Usage>`;
97315
97218
  }
97219
+ function buildArchitectReferralSection() {
97220
+ return `<Architect_Usage>
97221
+ ## Architect \u2014 Session Orchestrator (/start-work-only)
97222
+
97223
+ Architect is a /start-work-only session agent \u2014 it orchestrates work via a session until ALL tasks in a todo list are done. Architect is NOT callable via task().
97224
+
97225
+ ### WHEN to Refer:
97226
+
97227
+ | Trigger | Action |
97228
+ | User provides a todo list path (.matrixx/plans/{name}.md) | /start-work FIRST, then Architect orchestrates |
97229
+ | Multiple tasks need to be completed in sequence or parallel | /start-work, NOT task() |
97230
+ | Work requires coordination across multiple specialized agents | /start-work, NOT task() |
97231
+ | Todo list path provided OR multiple tasks requiring multi-agent orchestration | /start-work |
97232
+
97233
+ ### HARD ROUTING RULE \u2014 Architect Referral (NON-NEGOTIABLE):
97234
+ - ANY task that executes \`.matrixx/plans/*.md\` MUST use \`/start-work\` \u2014 NEVER \`task(subagent_type="architect")\`
97235
+ - Architect is excluded from the task-delegation list by design. Do NOT attempt \`task(subagent_type="architect")\` \u2014 it will be rejected. Use \`/start-work\` instead.
97236
+
97237
+ ### Usage Pattern:
97238
+ Architect owns todo-list execution end to end. Invoke /start-work with the plan path so Architect can decompose and orchestrate the work across specialized agents.
97239
+ </Architect_Usage>`;
97240
+ }
97316
97241
  function buildHardBlocksSection() {
97317
97242
  const blocks = [
97318
97243
  "| Type error suppression (`as any`, `@ts-ignore`) | Never |",
@@ -97388,11 +97313,11 @@ function readDisciplineFile() {
97388
97313
  const p = resolveContextModeDisciplinePath();
97389
97314
  if (!p)
97390
97315
  throw new Error("discipline file not found");
97391
- const raw = readFileSync45(p, "utf8");
97316
+ const raw = readFileSync46(p, "utf8");
97392
97317
  let version4 = "1.0.169";
97393
97318
  try {
97394
97319
  const pkgResolved = __require.resolve("context-mode/package.json");
97395
- const pkgRaw = readFileSync45(pkgResolved, "utf8");
97320
+ const pkgRaw = readFileSync46(pkgResolved, "utf8");
97396
97321
  const pkg = JSON.parse(pkgRaw);
97397
97322
  if (pkg.version)
97398
97323
  version4 = pkg.version;
@@ -98375,17 +98300,13 @@ function buildDynamicOrchestratorPrompt(ctx) {
98375
98300
  return basePrompt.replace("{CATEGORY_SECTION}", categorySection).replace("{AGENT_SECTION}", agentSection).replace("{DECISION_MATRIX}", decisionMatrix).replace("{SKILLS_SECTION}", skillsSection).replace("{{CATEGORY_SKILLS_DELEGATION_GUIDE}}", categorySkillsGuide);
98376
98301
  }
98377
98302
  function createArchitectAgent(ctx) {
98378
- const restrictions = createAgentToolRestrictions([
98379
- "task"
98380
- ]);
98381
98303
  const baseConfig = {
98382
98304
  description: "Orchestrates work via task() to complete ALL tasks in a todo list until fully done. (Architect - Matrixx)",
98383
98305
  mode: MODE,
98384
98306
  ...ctx.model ? { model: ctx.model } : {},
98385
98307
  temperature: 0.1,
98386
98308
  prompt: buildDynamicOrchestratorPrompt(ctx),
98387
- color: "#10B981",
98388
- ...restrictions
98309
+ color: "#10B981"
98389
98310
  };
98390
98311
  return baseConfig;
98391
98312
  }
@@ -98497,9 +98418,9 @@ function createBddContractAgent(model) {
98497
98418
  createBddContractAgent.mode = MODE2;
98498
98419
 
98499
98420
  // src/agents/builtin-agents/resolve-file-uri.ts
98500
- import { existsSync as existsSync77, readFileSync as readFileSync46 } from "fs";
98421
+ import { existsSync as existsSync76, readFileSync as readFileSync47 } from "fs";
98501
98422
  import { homedir as homedir12 } from "os";
98502
- import { isAbsolute as isAbsolute6, resolve as resolve10 } from "path";
98423
+ import { isAbsolute as isAbsolute6, resolve as resolve9 } from "path";
98503
98424
  function resolvePromptAppend(promptAppend, configDir) {
98504
98425
  if (!promptAppend.startsWith("file://"))
98505
98426
  return promptAppend;
@@ -98508,15 +98429,15 @@ function resolvePromptAppend(promptAppend, configDir) {
98508
98429
  try {
98509
98430
  const decoded = decodeURIComponent(encoded);
98510
98431
  const expanded = decoded.startsWith("~/") ? decoded.replace(/^~\//, `${homedir12()}/`) : decoded;
98511
- filePath = isAbsolute6(expanded) ? expanded : resolve10(configDir ?? process.cwd(), expanded);
98432
+ filePath = isAbsolute6(expanded) ? expanded : resolve9(configDir ?? process.cwd(), expanded);
98512
98433
  } catch {
98513
98434
  return `[WARNING: Malformed file URI (invalid percent-encoding): ${promptAppend}]`;
98514
98435
  }
98515
- if (!existsSync77(filePath)) {
98436
+ if (!existsSync76(filePath)) {
98516
98437
  return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
98517
98438
  }
98518
98439
  try {
98519
- return readFileSync46(filePath, "utf8");
98440
+ return readFileSync47(filePath, "utf8");
98520
98441
  } catch {
98521
98442
  return `[WARNING: Could not read file: ${promptAppend}]`;
98522
98443
  }
@@ -99545,6 +99466,7 @@ function buildDynamicMorpheusPrompt(availableAgents, availableTools = [], availa
99545
99466
  const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
99546
99467
  const delegationTable = buildDelegationTable(availableAgents);
99547
99468
  const oracleSection = buildOracleSection(availableAgents);
99469
+ const architectReferral = buildArchitectReferralSection();
99548
99470
  const hardBlocks = buildHardBlocksSection();
99549
99471
  const antiPatterns = buildAntiPatternsSection();
99550
99472
  const hasContextMode = availableTools.some((t) => t.name.startsWith("ctx_"));
@@ -99841,6 +99763,8 @@ If verification fails:
99841
99763
 
99842
99764
  ${oracleSection}
99843
99765
 
99766
+ ${architectReferral}
99767
+
99844
99768
  ${taskManagementSection}
99845
99769
 
99846
99770
  <Tone_and_Style>
@@ -104309,10 +104233,12 @@ function applyToolConfig(params) {
104309
104233
  }
104310
104234
  const architect = agentByKey(params.agentResult, "architect");
104311
104235
  if (architect) {
104312
- architect.permission = {
104313
- ...architect.permission,
104314
- ...isTaskSystem ? { task: "allow", "task_*": "allow", teammate: "allow", ...denyTodoTools } : { todowrite: "allow", todoread: "allow", ...denyTaskTools }
104315
- };
104236
+ const defaults = isTaskSystem ? { task: "allow", "task_*": "allow", teammate: "allow", ...denyTodoTools } : { todowrite: "allow", todoread: "allow", ...denyTaskTools };
104237
+ const permission = architect.permission ?? {};
104238
+ for (const [key, value] of Object.entries(defaults)) {
104239
+ permission[key] ??= value;
104240
+ }
104241
+ architect.permission = permission;
104316
104242
  }
104317
104243
  const morpheus = agentByKey(params.agentResult, "morpheus");
104318
104244
  if (morpheus) {