gossipcat 0.6.6 → 0.6.8

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.
@@ -420,11 +420,11 @@ var require_codegen = __commonJS({
420
420
  const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
421
421
  return `${varKind} ${this.name}${rhs};` + _n;
422
422
  }
423
- optimizeNames(names, constants3) {
423
+ optimizeNames(names, constants4) {
424
424
  if (!names[this.name.str])
425
425
  return;
426
426
  if (this.rhs)
427
- this.rhs = optimizeExpr(this.rhs, names, constants3);
427
+ this.rhs = optimizeExpr(this.rhs, names, constants4);
428
428
  return this;
429
429
  }
430
430
  get names() {
@@ -441,10 +441,10 @@ var require_codegen = __commonJS({
441
441
  render({ _n }) {
442
442
  return `${this.lhs} = ${this.rhs};` + _n;
443
443
  }
444
- optimizeNames(names, constants3) {
444
+ optimizeNames(names, constants4) {
445
445
  if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
446
446
  return;
447
- this.rhs = optimizeExpr(this.rhs, names, constants3);
447
+ this.rhs = optimizeExpr(this.rhs, names, constants4);
448
448
  return this;
449
449
  }
450
450
  get names() {
@@ -505,8 +505,8 @@ var require_codegen = __commonJS({
505
505
  optimizeNodes() {
506
506
  return `${this.code}` ? this : void 0;
507
507
  }
508
- optimizeNames(names, constants3) {
509
- this.code = optimizeExpr(this.code, names, constants3);
508
+ optimizeNames(names, constants4) {
509
+ this.code = optimizeExpr(this.code, names, constants4);
510
510
  return this;
511
511
  }
512
512
  get names() {
@@ -535,12 +535,12 @@ var require_codegen = __commonJS({
535
535
  }
536
536
  return nodes.length > 0 ? this : void 0;
537
537
  }
538
- optimizeNames(names, constants3) {
538
+ optimizeNames(names, constants4) {
539
539
  const { nodes } = this;
540
540
  let i = nodes.length;
541
541
  while (i--) {
542
542
  const n = nodes[i];
543
- if (n.optimizeNames(names, constants3))
543
+ if (n.optimizeNames(names, constants4))
544
544
  continue;
545
545
  subtractNames(names, n.names);
546
546
  nodes.splice(i, 1);
@@ -593,12 +593,12 @@ var require_codegen = __commonJS({
593
593
  return void 0;
594
594
  return this;
595
595
  }
596
- optimizeNames(names, constants3) {
596
+ optimizeNames(names, constants4) {
597
597
  var _a3;
598
- this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants3);
599
- if (!(super.optimizeNames(names, constants3) || this.else))
598
+ this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants4);
599
+ if (!(super.optimizeNames(names, constants4) || this.else))
600
600
  return;
601
- this.condition = optimizeExpr(this.condition, names, constants3);
601
+ this.condition = optimizeExpr(this.condition, names, constants4);
602
602
  return this;
603
603
  }
604
604
  get names() {
@@ -621,10 +621,10 @@ var require_codegen = __commonJS({
621
621
  render(opts) {
622
622
  return `for(${this.iteration})` + super.render(opts);
623
623
  }
624
- optimizeNames(names, constants3) {
625
- if (!super.optimizeNames(names, constants3))
624
+ optimizeNames(names, constants4) {
625
+ if (!super.optimizeNames(names, constants4))
626
626
  return;
627
- this.iteration = optimizeExpr(this.iteration, names, constants3);
627
+ this.iteration = optimizeExpr(this.iteration, names, constants4);
628
628
  return this;
629
629
  }
630
630
  get names() {
@@ -660,10 +660,10 @@ var require_codegen = __commonJS({
660
660
  render(opts) {
661
661
  return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
662
662
  }
663
- optimizeNames(names, constants3) {
664
- if (!super.optimizeNames(names, constants3))
663
+ optimizeNames(names, constants4) {
664
+ if (!super.optimizeNames(names, constants4))
665
665
  return;
666
- this.iterable = optimizeExpr(this.iterable, names, constants3);
666
+ this.iterable = optimizeExpr(this.iterable, names, constants4);
667
667
  return this;
668
668
  }
669
669
  get names() {
@@ -705,11 +705,11 @@ var require_codegen = __commonJS({
705
705
  (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
706
706
  return this;
707
707
  }
708
- optimizeNames(names, constants3) {
708
+ optimizeNames(names, constants4) {
709
709
  var _a3, _b;
710
- super.optimizeNames(names, constants3);
711
- (_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants3);
712
- (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants3);
710
+ super.optimizeNames(names, constants4);
711
+ (_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants4);
712
+ (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants4);
713
713
  return this;
714
714
  }
715
715
  get names() {
@@ -1010,7 +1010,7 @@ var require_codegen = __commonJS({
1010
1010
  function addExprNames(names, from) {
1011
1011
  return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
1012
1012
  }
1013
- function optimizeExpr(expr, names, constants3) {
1013
+ function optimizeExpr(expr, names, constants4) {
1014
1014
  if (expr instanceof code_1.Name)
1015
1015
  return replaceName(expr);
1016
1016
  if (!canOptimize(expr))
@@ -1025,14 +1025,14 @@ var require_codegen = __commonJS({
1025
1025
  return items;
1026
1026
  }, []));
1027
1027
  function replaceName(n) {
1028
- const c = constants3[n.str];
1028
+ const c = constants4[n.str];
1029
1029
  if (c === void 0 || names[n.str] !== 1)
1030
1030
  return n;
1031
1031
  delete names[n.str];
1032
1032
  return c;
1033
1033
  }
1034
1034
  function canOptimize(e) {
1035
- return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants3[c.str] !== void 0);
1035
+ return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants4[c.str] !== void 0);
1036
1036
  }
1037
1037
  }
1038
1038
  function subtractNames(names, from) {
@@ -2994,7 +2994,7 @@ var require_compile = __commonJS({
2994
2994
  const schOrFunc = root.refs[ref];
2995
2995
  if (schOrFunc)
2996
2996
  return schOrFunc;
2997
- let _sch = resolve32.call(this, root, ref);
2997
+ let _sch = resolve33.call(this, root, ref);
2998
2998
  if (_sch === void 0) {
2999
2999
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
3000
3000
  const { schemaId } = this.opts;
@@ -3021,7 +3021,7 @@ var require_compile = __commonJS({
3021
3021
  function sameSchemaEnv(s1, s2) {
3022
3022
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3023
3023
  }
3024
- function resolve32(root, ref) {
3024
+ function resolve33(root, ref) {
3025
3025
  let sch;
3026
3026
  while (typeof (sch = this.refs[ref]) == "string")
3027
3027
  ref = sch;
@@ -3239,8 +3239,8 @@ var require_utils = __commonJS({
3239
3239
  }
3240
3240
  return ind;
3241
3241
  }
3242
- function removeDotSegments(path7) {
3243
- let input = path7;
3242
+ function removeDotSegments(path8) {
3243
+ let input = path8;
3244
3244
  const output = [];
3245
3245
  let nextSlash = -1;
3246
3246
  let len = 0;
@@ -3492,8 +3492,8 @@ var require_schemes = __commonJS({
3492
3492
  wsComponent.secure = void 0;
3493
3493
  }
3494
3494
  if (wsComponent.resourceName) {
3495
- const [path7, query] = wsComponent.resourceName.split("?");
3496
- wsComponent.path = path7 && path7 !== "/" ? path7 : void 0;
3495
+ const [path8, query] = wsComponent.resourceName.split("?");
3496
+ wsComponent.path = path8 && path8 !== "/" ? path8 : void 0;
3497
3497
  wsComponent.query = query;
3498
3498
  wsComponent.resourceName = void 0;
3499
3499
  }
@@ -3652,7 +3652,7 @@ var require_fast_uri = __commonJS({
3652
3652
  }
3653
3653
  return uri;
3654
3654
  }
3655
- function resolve32(baseURI, relativeURI, options) {
3655
+ function resolve33(baseURI, relativeURI, options) {
3656
3656
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3657
3657
  const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
3658
3658
  schemelessOptions.skipEscape = true;
@@ -3910,7 +3910,7 @@ var require_fast_uri = __commonJS({
3910
3910
  var fastUri = {
3911
3911
  SCHEMES,
3912
3912
  normalize: normalize3,
3913
- resolve: resolve32,
3913
+ resolve: resolve33,
3914
3914
  resolveComponent,
3915
3915
  equal,
3916
3916
  serialize,
@@ -6886,12 +6886,12 @@ var require_dist = __commonJS({
6886
6886
  throw new Error(`Unknown format "${name}"`);
6887
6887
  return f;
6888
6888
  };
6889
- function addFormats(ajv, list, fs6, exportName) {
6889
+ function addFormats(ajv, list, fs7, exportName) {
6890
6890
  var _a3;
6891
6891
  var _b;
6892
6892
  (_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
6893
6893
  for (const f of list)
6894
- ajv.addFormat(f, fs6[f]);
6894
+ ajv.addFormat(f, fs7[f]);
6895
6895
  }
6896
6896
  module2.exports = exports2 = formatsPlugin;
6897
6897
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -6967,11 +6967,14 @@ var init_mcp_context = __esm({
6967
6967
  // packages/orchestrator/src/log.ts
6968
6968
  function ts() {
6969
6969
  const d = /* @__PURE__ */ new Date();
6970
+ const yyyy = d.getUTCFullYear();
6971
+ const mo = String(d.getUTCMonth() + 1).padStart(2, "0");
6972
+ const dd = String(d.getUTCDate()).padStart(2, "0");
6970
6973
  const hh = String(d.getUTCHours()).padStart(2, "0");
6971
6974
  const mm = String(d.getUTCMinutes()).padStart(2, "0");
6972
6975
  const ss = String(d.getUTCSeconds()).padStart(2, "0");
6973
6976
  const ms = String(d.getUTCMilliseconds()).padStart(3, "0");
6974
- return `${hh}:${mm}:${ss}.${ms}`;
6977
+ return `${yyyy}-${mo}-${dd} ${hh}:${mm}:${ss}.${ms}Z`;
6975
6978
  }
6976
6979
  function emojiFor(tag) {
6977
6980
  if (TAG_EMOJI[tag]) return TAG_EMOJI[tag];
@@ -7009,9 +7012,9 @@ var init_log = __esm({
7009
7012
  function statePath(projectRoot) {
7010
7013
  return (0, import_path4.join)(projectRoot, ".gossip", "auth-state.json");
7011
7014
  }
7012
- function readState(path7) {
7015
+ function readState(path8) {
7013
7016
  try {
7014
- return JSON.parse((0, import_fs5.readFileSync)(path7, "utf-8"));
7017
+ return JSON.parse((0, import_fs5.readFileSync)(path8, "utf-8"));
7015
7018
  } catch {
7016
7019
  return {};
7017
7020
  }
@@ -7020,33 +7023,33 @@ function recordAuthFailure(projectRoot, provider, status) {
7020
7023
  if (!projectRoot) return;
7021
7024
  if (!PROVIDER_RE.test(provider)) return;
7022
7025
  try {
7023
- const path7 = statePath(projectRoot);
7024
- const dir = (0, import_path4.join)(path7, "..");
7026
+ const path8 = statePath(projectRoot);
7027
+ const dir = (0, import_path4.join)(path8, "..");
7025
7028
  if (!(0, import_fs5.existsSync)(dir)) (0, import_fs5.mkdirSync)(dir, { recursive: true });
7026
- const existing = readState(path7);
7029
+ const existing = readState(path8);
7027
7030
  existing[provider] = { status, at: Date.now() };
7028
- (0, import_fs5.writeFileSync)(path7, JSON.stringify(existing, null, 2));
7031
+ (0, import_fs5.writeFileSync)(path8, JSON.stringify(existing, null, 2));
7029
7032
  } catch {
7030
7033
  }
7031
7034
  }
7032
7035
  function clearAuthFailure(projectRoot, provider) {
7033
7036
  if (!projectRoot) return;
7034
7037
  try {
7035
- const path7 = statePath(projectRoot);
7036
- if (!(0, import_fs5.existsSync)(path7)) return;
7037
- const existing = readState(path7);
7038
+ const path8 = statePath(projectRoot);
7039
+ if (!(0, import_fs5.existsSync)(path8)) return;
7040
+ const existing = readState(path8);
7038
7041
  if (!(provider in existing)) return;
7039
7042
  delete existing[provider];
7040
- (0, import_fs5.writeFileSync)(path7, JSON.stringify(existing, null, 2));
7043
+ (0, import_fs5.writeFileSync)(path8, JSON.stringify(existing, null, 2));
7041
7044
  } catch {
7042
7045
  }
7043
7046
  }
7044
7047
  function readRecentAuthFailures(projectRoot, ttlMs = 6 * 60 * 60 * 1e3) {
7045
7048
  if (!projectRoot) return [];
7046
7049
  try {
7047
- const path7 = statePath(projectRoot);
7048
- if (!(0, import_fs5.existsSync)(path7)) return [];
7049
- const state = readState(path7);
7050
+ const path8 = statePath(projectRoot);
7051
+ if (!(0, import_fs5.existsSync)(path8)) return [];
7052
+ const state = readState(path8);
7050
7053
  const now = Date.now();
7051
7054
  const out = [];
7052
7055
  for (const [provider, entry] of Object.entries(state)) {
@@ -13951,7 +13954,7 @@ var init_gossip_agent = __esm({
13951
13954
  }
13952
13955
  // ─── Public API ─────────────────────────────────────────────────────────────
13953
13956
  connect() {
13954
- return new Promise((resolve32, reject) => {
13957
+ return new Promise((resolve33, reject) => {
13955
13958
  const ws = new wrapper_default(this.config.relayUrl);
13956
13959
  const timeout = setTimeout(() => {
13957
13960
  ws.removeAllListeners();
@@ -13984,7 +13987,7 @@ var init_gossip_agent = __esm({
13984
13987
  ws.on("error", (err) => this.emit("error", err));
13985
13988
  this.startKeepAlive();
13986
13989
  this.emit("connect", msg.sessionId);
13987
- resolve32();
13990
+ resolve33();
13988
13991
  } else if (msg.type === "error") {
13989
13992
  clearTimeout(timeout);
13990
13993
  ws.removeAllListeners();
@@ -14010,7 +14013,7 @@ var init_gossip_agent = __esm({
14010
14013
  this.reconnectTimer = null;
14011
14014
  }
14012
14015
  if (!this.ws) return;
14013
- return new Promise((resolve32) => {
14016
+ return new Promise((resolve33) => {
14014
14017
  this.intentionalDisconnect = true;
14015
14018
  this._connected = false;
14016
14019
  const ws = this.ws;
@@ -14021,7 +14024,7 @@ var init_gossip_agent = __esm({
14021
14024
  settled = true;
14022
14025
  this.intentionalDisconnect = false;
14023
14026
  this.emit("disconnect", code);
14024
- resolve32();
14027
+ resolve33();
14025
14028
  };
14026
14029
  const timer = setTimeout(() => done(1e3), 2e3);
14027
14030
  ws.once("close", (code) => {
@@ -14060,8 +14063,8 @@ var init_gossip_agent = __esm({
14060
14063
  throw new Error("Not connected to relay");
14061
14064
  }
14062
14065
  const encoded = Buffer.from(this.codec.encode(envelope));
14063
- return new Promise((resolve32, reject) => {
14064
- this.ws.send(encoded, (err) => err ? reject(err) : resolve32());
14066
+ return new Promise((resolve33, reject) => {
14067
+ this.ws.send(encoded, (err) => err ? reject(err) : resolve33());
14065
14068
  });
14066
14069
  }
14067
14070
  // ─── Internal ────────────────────────────────────────────────────────────────
@@ -14541,7 +14544,7 @@ ${context}` : ""}
14541
14544
  this.memoryQueryCalled = true;
14542
14545
  }
14543
14546
  const requestId = (0, import_crypto6.randomUUID)();
14544
- const resultPromise = new Promise((resolve32, reject) => {
14547
+ const resultPromise = new Promise((resolve33, reject) => {
14545
14548
  const timer = setTimeout(() => {
14546
14549
  if (this.pendingToolCalls.has(requestId)) {
14547
14550
  this.pendingToolCalls.delete(requestId);
@@ -14552,7 +14555,7 @@ ${context}` : ""}
14552
14555
  this.pendingToolCalls.set(requestId, {
14553
14556
  resolve: (r) => {
14554
14557
  clearTimeout(timer);
14555
- resolve32(r);
14558
+ resolve33(r);
14556
14559
  },
14557
14560
  reject: (e) => {
14558
14561
  clearTimeout(timer);
@@ -14617,13 +14620,17 @@ ${context}` : ""}
14617
14620
  });
14618
14621
 
14619
14622
  // packages/tools/src/file-tools.ts
14620
- var import_promises, import_path6, import_fs7, FileTools;
14623
+ var import_promises, import_path6, import_fs7, import_re2, MAX_GREP_FILE_BYTES, MAX_GREP_MATCHES, MAX_GREP_FILES, FileTools;
14621
14624
  var init_file_tools = __esm({
14622
14625
  "packages/tools/src/file-tools.ts"() {
14623
14626
  "use strict";
14624
14627
  import_promises = require("fs/promises");
14625
14628
  import_path6 = require("path");
14626
14629
  import_fs7 = require("fs");
14630
+ import_re2 = __toESM(require("re2"));
14631
+ MAX_GREP_FILE_BYTES = 2 * 1024 * 1024;
14632
+ MAX_GREP_MATCHES = 2e3;
14633
+ MAX_GREP_FILES = 5e3;
14627
14634
  FileTools = class {
14628
14635
  constructor(sandbox) {
14629
14636
  this.sandbox = sandbox;
@@ -14709,13 +14716,17 @@ var init_file_tools = __esm({
14709
14716
  const searchRoot = args.path ? this.sandbox.validatePath(args.path, allowed) : agentRoot || this.sandbox.projectRoot;
14710
14717
  let regex;
14711
14718
  try {
14712
- regex = new RegExp(args.pattern);
14719
+ regex = new import_re2.default(args.pattern);
14713
14720
  } catch (error51) {
14714
14721
  return `Invalid regex pattern: ${error51 instanceof Error ? error51.message : "Unknown error"}`;
14715
14722
  }
14716
- const results = [];
14717
- await this.grepDir(searchRoot, regex, results, 0, 10);
14718
- return results.join("\n") || "No matches found";
14723
+ const state = { matches: [], filesScanned: 0, truncated: false };
14724
+ await this.grepDir(searchRoot, regex, state, 0, 10);
14725
+ let output = state.matches.join("\n") || "No matches found";
14726
+ if (state.truncated) {
14727
+ output += "\n... (truncated \u2014 result or scan limit reached; narrow your pattern/path)";
14728
+ }
14729
+ return output;
14719
14730
  }
14720
14731
  async fileTree(args, agentRoot) {
14721
14732
  const allowed = agentRoot ? [agentRoot] : [];
@@ -14735,7 +14746,7 @@ var init_file_tools = __esm({
14735
14746
  return;
14736
14747
  }
14737
14748
  const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
14738
- const regex = new RegExp(regexStr);
14749
+ const regex = new import_re2.default(regexStr);
14739
14750
  for (const entry of entries) {
14740
14751
  if (entry === "node_modules" || entry === ".git") continue;
14741
14752
  const fullPath = (0, import_path6.join)(dir, entry);
@@ -14755,8 +14766,9 @@ var init_file_tools = __esm({
14755
14766
  }
14756
14767
  }
14757
14768
  }
14758
- async grepDir(dir, regex, results, depth = 0, maxDepth = 10) {
14769
+ async grepDir(dir, regex, state, depth = 0, maxDepth = 10) {
14759
14770
  if (depth >= maxDepth) return;
14771
+ if (state.truncated) return;
14760
14772
  let entries;
14761
14773
  try {
14762
14774
  entries = await (0, import_promises.readdir)(dir);
@@ -14764,6 +14776,7 @@ var init_file_tools = __esm({
14764
14776
  return;
14765
14777
  }
14766
14778
  for (const entry of entries) {
14779
+ if (state.truncated) return;
14767
14780
  if (entry === "node_modules" || entry === ".git") continue;
14768
14781
  const fullPath = (0, import_path6.join)(dir, entry);
14769
14782
  let info;
@@ -14773,17 +14786,29 @@ var init_file_tools = __esm({
14773
14786
  continue;
14774
14787
  }
14775
14788
  if (info.isDirectory()) {
14776
- await this.grepDir(fullPath, regex, results, depth + 1, maxDepth);
14789
+ await this.grepDir(fullPath, regex, state, depth + 1, maxDepth);
14777
14790
  } else {
14791
+ if (info.size > MAX_GREP_FILE_BYTES) {
14792
+ continue;
14793
+ }
14794
+ state.filesScanned++;
14795
+ if (state.filesScanned > MAX_GREP_FILES) {
14796
+ state.truncated = true;
14797
+ return;
14798
+ }
14778
14799
  try {
14779
14800
  const content = await (0, import_promises.readFile)(fullPath, "utf-8");
14780
14801
  const lines = content.split("\n");
14781
14802
  const relPath = (0, import_path6.relative)(this.sandbox.projectRoot, fullPath);
14782
- lines.forEach((line, idx) => {
14783
- if (regex.test(line)) {
14784
- results.push(`${relPath}:${idx + 1}: ${line}`);
14803
+ for (let idx = 0; idx < lines.length; idx++) {
14804
+ if (state.matches.length >= MAX_GREP_MATCHES) {
14805
+ state.truncated = true;
14806
+ break;
14785
14807
  }
14786
- });
14808
+ if (regex.test(lines[idx])) {
14809
+ state.matches.push(`${relPath}:${idx + 1}: ${lines[idx]}`);
14810
+ }
14811
+ }
14787
14812
  } catch {
14788
14813
  }
14789
14814
  }
@@ -15566,8 +15591,8 @@ var init_parseUtil = __esm({
15566
15591
  init_errors2();
15567
15592
  init_en();
15568
15593
  makeIssue2 = (params) => {
15569
- const { data, path: path7, errorMaps, issueData } = params;
15570
- const fullPath = [...path7, ...issueData.path || []];
15594
+ const { data, path: path8, errorMaps, issueData } = params;
15595
+ const fullPath = [...path8, ...issueData.path || []];
15571
15596
  const fullIssue = {
15572
15597
  ...issueData,
15573
15598
  path: fullPath
@@ -15878,11 +15903,11 @@ var init_types = __esm({
15878
15903
  init_parseUtil();
15879
15904
  init_util();
15880
15905
  ParseInputLazyPath2 = class {
15881
- constructor(parent, value, path7, key) {
15906
+ constructor(parent, value, path8, key) {
15882
15907
  this._cachedPath = [];
15883
15908
  this.parent = parent;
15884
15909
  this.data = value;
15885
- this._path = path7;
15910
+ this._path = path8;
15886
15911
  this._key = key;
15887
15912
  }
15888
15913
  get path() {
@@ -19916,7 +19941,7 @@ ${truncateAtLine(fullDiff, 3e3)}`;
19916
19941
  }
19917
19942
  async requestPeerReview(callerId, diff, testResult) {
19918
19943
  const requestId = (0, import_crypto8.randomUUID)();
19919
- const reviewPromise = new Promise((resolve32, reject) => {
19944
+ const reviewPromise = new Promise((resolve33, reject) => {
19920
19945
  const timer = setTimeout(() => {
19921
19946
  this.pendingReviews.delete(requestId);
19922
19947
  reject(new Error("Review timed out"));
@@ -19925,7 +19950,7 @@ ${truncateAtLine(fullDiff, 3e3)}`;
19925
19950
  this.pendingReviews.set(requestId, {
19926
19951
  resolve: (r) => {
19927
19952
  clearTimeout(timer);
19928
- resolve32(r);
19953
+ resolve33(r);
19929
19954
  },
19930
19955
  reject: (e) => {
19931
19956
  clearTimeout(timer);
@@ -20216,6 +20241,9 @@ __export(src_exports2, {
20216
20241
  GIT_TOOLS: () => GIT_TOOLS,
20217
20242
  GitTools: () => GitTools,
20218
20243
  IDENTITY_TOOLS: () => IDENTITY_TOOLS,
20244
+ MAX_GREP_FILES: () => MAX_GREP_FILES,
20245
+ MAX_GREP_FILE_BYTES: () => MAX_GREP_FILE_BYTES,
20246
+ MAX_GREP_MATCHES: () => MAX_GREP_MATCHES,
20219
20247
  MAX_MEMORY_QUERY_LOG_BYTES: () => MAX_MEMORY_QUERY_LOG_BYTES,
20220
20248
  MEMORY_QUERY_LOG: () => MEMORY_QUERY_LOG,
20221
20249
  MEMORY_TOOLS: () => MEMORY_TOOLS,
@@ -20296,7 +20324,14 @@ var init_consensus_types = __esm({
20296
20324
  "transport_failure",
20297
20325
  "worktree_isolation_failed",
20298
20326
  "auto_verify_attempted",
20299
- "auto_verify_skipped_misconfigured"
20327
+ "auto_verify_skipped_misconfigured",
20328
+ /**
20329
+ * Orchestrator dispatch-hygiene signals (UNIT 1 — orchestrator signal pipeline).
20330
+ * Tallied as operational; never affect agent accuracy scoring.
20331
+ */
20332
+ "dispatched_stale_base",
20333
+ "referenced_unreadable_path",
20334
+ "mid_flight_fixup"
20300
20335
  ]);
20301
20336
  }
20302
20337
  });
@@ -20324,21 +20359,21 @@ function extractFrontmatterField(content, field) {
20324
20359
  return null;
20325
20360
  }
20326
20361
  function readSkillFreshness(agentId, category, skillRoot) {
20327
- const path7 = resolveSkillFilePath(agentId, category, skillRoot);
20328
- if (!(0, import_fs12.existsSync)(path7)) {
20329
- return { boundAt: null, status: null, path: path7, regressedFromPassedAt: null };
20362
+ const path8 = resolveSkillFilePath(agentId, category, skillRoot);
20363
+ if (!(0, import_fs12.existsSync)(path8)) {
20364
+ return { boundAt: null, status: null, path: path8, regressedFromPassedAt: null };
20330
20365
  }
20331
20366
  let content;
20332
20367
  try {
20333
- content = (0, import_fs12.readFileSync)(path7, "utf-8");
20368
+ content = (0, import_fs12.readFileSync)(path8, "utf-8");
20334
20369
  } catch {
20335
- return { boundAt: null, status: null, path: path7, regressedFromPassedAt: null };
20370
+ return { boundAt: null, status: null, path: path8, regressedFromPassedAt: null };
20336
20371
  }
20337
20372
  const boundAt = extractFrontmatterField(content, "bound_at");
20338
20373
  const rawStatus = extractFrontmatterField(content, "status");
20339
20374
  const status = rawStatus === null ? null : coerceStatus(rawStatus);
20340
20375
  const regressedFromPassedAt = extractFrontmatterField(content, "regressed_from_passed_at");
20341
- return { boundAt, status, path: path7, regressedFromPassedAt };
20376
+ return { boundAt, status, path: path8, regressedFromPassedAt };
20342
20377
  }
20343
20378
  function computeCooldown(input) {
20344
20379
  let status;
@@ -21928,15 +21963,15 @@ function classifyForAggregate(signal) {
21928
21963
  }
21929
21964
  }
21930
21965
  function readAggregateIndex(projectRoot) {
21931
- const path7 = (0, import_path14.join)(projectRoot, ".gossip", SIDECAR_FILENAME);
21932
- if (!(0, import_fs14.existsSync)(path7)) {
21966
+ const path8 = (0, import_path14.join)(projectRoot, ".gossip", SIDECAR_FILENAME);
21967
+ if (!(0, import_fs14.existsSync)(path8)) {
21933
21968
  cachedAggregateData = null;
21934
21969
  cachedAggregateMtimeMs = 0;
21935
21970
  return null;
21936
21971
  }
21937
21972
  let mtimeMs = 0;
21938
21973
  try {
21939
- mtimeMs = (0, import_fs14.statSync)(path7).mtimeMs;
21974
+ mtimeMs = (0, import_fs14.statSync)(path8).mtimeMs;
21940
21975
  } catch (err) {
21941
21976
  logSidecarError("stat", err);
21942
21977
  return null;
@@ -21946,7 +21981,7 @@ function readAggregateIndex(projectRoot) {
21946
21981
  }
21947
21982
  let raw;
21948
21983
  try {
21949
- raw = (0, import_fs14.readFileSync)(path7, "utf-8");
21984
+ raw = (0, import_fs14.readFileSync)(path8, "utf-8");
21950
21985
  } catch (err) {
21951
21986
  logSidecarError("read", err);
21952
21987
  return null;
@@ -21982,14 +22017,14 @@ function readAggregateIndex(projectRoot) {
21982
22017
  return result;
21983
22018
  }
21984
22019
  function writeAggregateIndex(projectRoot, data) {
21985
- const path7 = (0, import_path14.join)(projectRoot, ".gossip", SIDECAR_FILENAME);
22020
+ const path8 = (0, import_path14.join)(projectRoot, ".gossip", SIDECAR_FILENAME);
21986
22021
  try {
21987
- (0, import_fs14.mkdirSync)((0, import_path14.dirname)(path7), { recursive: true });
21988
- const tmp = path7 + ".tmp";
22022
+ (0, import_fs14.mkdirSync)((0, import_path14.dirname)(path8), { recursive: true });
22023
+ const tmp = path8 + ".tmp";
21989
22024
  (0, import_fs14.writeFileSync)(tmp, JSON.stringify(data, null, 2) + "\n");
21990
- (0, import_fs14.renameSync)(tmp, path7);
22025
+ (0, import_fs14.renameSync)(tmp, path8);
21991
22026
  cachedAggregateData = data;
21992
- cachedAggregateMtimeMs = (0, import_fs14.statSync)(path7).mtimeMs;
22027
+ cachedAggregateMtimeMs = (0, import_fs14.statSync)(path8).mtimeMs;
21993
22028
  } catch (err) {
21994
22029
  logSidecarError("write", err);
21995
22030
  }
@@ -22375,14 +22410,14 @@ var init_performance_reader = __esm({
22375
22410
  */
22376
22411
  getSkillIndexEnabledMap() {
22377
22412
  if (this.skillIndexCache !== void 0) return this.skillIndexCache;
22378
- const path7 = (0, import_path15.join)(this.projectRoot, ".gossip", "skill-index.json");
22413
+ const path8 = (0, import_path15.join)(this.projectRoot, ".gossip", "skill-index.json");
22379
22414
  let parsed;
22380
22415
  try {
22381
- if (!(0, import_fs15.existsSync)(path7)) {
22416
+ if (!(0, import_fs15.existsSync)(path8)) {
22382
22417
  this.skillIndexCache = null;
22383
22418
  return null;
22384
22419
  }
22385
- parsed = JSON.parse((0, import_fs15.readFileSync)(path7, "utf-8"));
22420
+ parsed = JSON.parse((0, import_fs15.readFileSync)(path8, "utf-8"));
22386
22421
  } catch {
22387
22422
  this.skillIndexCache = null;
22388
22423
  return null;
@@ -23776,7 +23811,14 @@ var init_performance_writer = __esm({
23776
23811
  "relay_findings_dropped",
23777
23812
  // Phase A self-telemetry: collect-end reconciliation detected fewer signals
23778
23813
  // written than findings in the consensus report. Observability-only.
23779
- "signal_loss_suspected"
23814
+ "signal_loss_suspected",
23815
+ // UNIT 1 orchestrator signal pipeline: dispatch-hygiene precondition signals.
23816
+ // Operational-only (tallied, never scored). Emitted by orchestrator-preconditions.ts
23817
+ // when a dispatch-hygiene failure is detected (stale base, unreadable reference
23818
+ // paths, mid-flight commits during a consensus round).
23819
+ "dispatched_stale_base",
23820
+ "referenced_unreadable_path",
23821
+ "mid_flight_fixup"
23780
23822
  ]);
23781
23823
  SYSTEM_SENTINEL_AGENT_ID = "_system";
23782
23824
  rowsWrittenSinceCheck = 0;
@@ -24489,13 +24531,13 @@ function resolveSkill(agentId, skill, projectRoot) {
24489
24531
  if ((0, import_fs19.existsSync)(candidate)) {
24490
24532
  try {
24491
24533
  const content = (0, import_fs19.readFileSync)(candidate, "utf-8");
24492
- let path7;
24534
+ let path8;
24493
24535
  try {
24494
- path7 = (0, import_fs19.realpathSync)(candidate);
24536
+ path8 = (0, import_fs19.realpathSync)(candidate);
24495
24537
  } catch {
24496
- path7 = candidate;
24538
+ path8 = candidate;
24497
24539
  }
24498
- return { content, path: path7 };
24540
+ return { content, path: path8 };
24499
24541
  } catch (err) {
24500
24542
  log("skill-loader", `Failed to read skill file ${candidate}: ${err?.message ?? err}`);
24501
24543
  continue;
@@ -25599,14 +25641,14 @@ ${cleanSummary}` : cleanSummary;
25599
25641
  const citations = [];
25600
25642
  let m;
25601
25643
  while ((m = fileRegex.exec(body)) !== null) {
25602
- const path7 = m[1];
25644
+ const path8 = m[1];
25603
25645
  const before = body.slice(Math.max(0, m.index - 8), m.index + 1);
25604
- if (/https?:\/\//.test(before) || /https?:\/\//.test(path7)) continue;
25646
+ if (/https?:\/\//.test(before) || /https?:\/\//.test(path8)) continue;
25605
25647
  const line = m[2] ? parseInt(m[2], 10) : void 0;
25606
- const key = line !== void 0 ? `${path7}:${line}` : path7;
25648
+ const key = line !== void 0 ? `${path8}:${line}` : path8;
25607
25649
  if (seen.has(key)) continue;
25608
25650
  seen.add(key);
25609
- citations.push({ path: path7, line, key });
25651
+ citations.push({ path: path8, line, key });
25610
25652
  }
25611
25653
  const roots = [this.projectRoot, ...resolutionRoots ?? []];
25612
25654
  const unverified = [];
@@ -29268,12 +29310,12 @@ async function getUncategorizedStatusLine(projectRoot, opts) {
29268
29310
  let mostRecentText = "";
29269
29311
  let mostRecentTs = 0;
29270
29312
  const uncatPath = (0, import_path31.join)(projectRoot, ".gossip", "uncategorized-findings.jsonl");
29271
- const scanFile = (filePath) => new Promise((resolve32) => {
29313
+ const scanFile = (filePath) => new Promise((resolve33) => {
29272
29314
  if (!(0, import_fs29.existsSync)(filePath)) {
29273
- return resolve32();
29315
+ return resolve33();
29274
29316
  }
29275
29317
  const stream = (0, import_fs29.createReadStream)(filePath, { encoding: "utf8" });
29276
- stream.on("error", () => resolve32());
29318
+ stream.on("error", () => resolve33());
29277
29319
  const rl = (0, import_readline.createInterface)({ input: stream, crlfDelay: Infinity });
29278
29320
  rl.on("line", (line) => {
29279
29321
  if (!line) return;
@@ -29290,8 +29332,8 @@ async function getUncategorizedStatusLine(projectRoot, opts) {
29290
29332
  } catch {
29291
29333
  }
29292
29334
  });
29293
- rl.on("close", resolve32);
29294
- rl.on("error", () => resolve32());
29335
+ rl.on("close", resolve33);
29336
+ rl.on("error", () => resolve33());
29295
29337
  });
29296
29338
  await scanFile(uncatPath);
29297
29339
  if ((0, import_fs29.existsSync)(uncatPath + ".1")) {
@@ -29480,6 +29522,26 @@ var init_consensus_engine = __esm({
29480
29522
  if (!report.warnings) report.warnings = [];
29481
29523
  report.warnings.push(entry);
29482
29524
  }
29525
+ /**
29526
+ * Idempotent helper: appends the UNSCORED ROUND banner to report.summary and
29527
+ * records a zero_tags warning when any agents emitted zero <agent_finding> tags.
29528
+ * Safe to call multiple times — skips if the banner is already present or if
29529
+ * zeroTagAgents is empty/absent.
29530
+ * Called at each finalization point: run(), runSelectedCrossReview(), and
29531
+ * synthesizeWithCrossReview() — so ALL synthesize paths surface the banner.
29532
+ */
29533
+ surfaceZeroTagBanner(report) {
29534
+ if (!report.zeroTagAgents?.length) return;
29535
+ if (report.summary.includes("UNSCORED ROUND")) return;
29536
+ const n = report.zeroTagAgents.length;
29537
+ const overflow = report.zeroTagOverflow ?? 0;
29538
+ const list = report.zeroTagAgents.join(", ");
29539
+ const evidence = `UNSCORED ROUND \u2014 ${n}${overflow > 0 ? "+" + overflow : ""} agent(s) emitted zero <agent_finding> tags; their output was bullet-parsed and CONFIRMED/DISPUTED scoring was NOT computed for them (agents: ${list})`;
29540
+ report.summary += `
29541
+ \u26A0\uFE0F ${evidence}
29542
+ `;
29543
+ this.appendReportWarning(report, "zero_tags", evidence);
29544
+ }
29483
29545
  /** True when a PerformanceReader is available for orchestrator-selected cross-review (Step 3). */
29484
29546
  get hasPerformanceReader() {
29485
29547
  return this.config.performanceReader !== void 0;
@@ -29730,6 +29792,7 @@ var init_consensus_engine = __esm({
29730
29792
  );
29731
29793
  report.unverified = enriched;
29732
29794
  report.summary = this.formatReport(report.confirmed, report.disputed, report.unverified, report.unique, report.newFindings, successful.length, report.rounds, timing, report.insights);
29795
+ this.surfaceZeroTagBanner(report);
29733
29796
  return report;
29734
29797
  }
29735
29798
  /**
@@ -30107,7 +30170,7 @@ Return only valid JSON.${skillsBlock}`;
30107
30170
  }
30108
30171
  log(
30109
30172
  "consensus",
30110
- `\u26A0 agent "${r.agentId}" emitted ZERO tags \u2014 falling back to bullet parsing. Check if skill Output Format conflicts with FINDING TAG SCHEMA.`
30173
+ `\u26A0 agent "${r.agentId}" emitted ZERO tags \u2014 falling back to bullet parsing. Common causes: the dispatch/cross-review prompt instructed plain prose (no <agent_finding> tags), a design/research task where the agent emitted none, or a skill Output Format conflicting with the FINDING TAG SCHEMA. Verify the dispatch prompt keeps the schema in force.`
30111
30174
  );
30112
30175
  } else {
30113
30176
  const offending = Object.entries(parseResult.droppedUnknownType).map(([t, n]) => `${t}:${n}`).join(",") || "(missing type attribute)";
@@ -31547,7 +31610,9 @@ ${safeSnippet}
31547
31610
  }
31548
31611
  if (findingSeq === 0) {
31549
31612
  log("consensus", "runSelectedCrossReview: no structured findings extracted; synthesizing without cross-review");
31550
- return this.synthesize(results, [], consensusId);
31613
+ const report2 = await this.synthesize(results, [], consensusId);
31614
+ this.surfaceZeroTagBanner(report2);
31615
+ return report2;
31551
31616
  }
31552
31617
  const agentCandidates = successful.map((r) => ({ agentId: r.agentId }));
31553
31618
  const assignments = selectCrossReviewers(findingsForSelection, agentCandidates, performanceReader);
@@ -31555,6 +31620,7 @@ ${safeSnippet}
31555
31620
  log("consensus", "runSelectedCrossReview: no reviewers selected; synthesizing without cross-review");
31556
31621
  const report2 = await this.synthesize(results, [], consensusId);
31557
31622
  this.appendReportWarning(report2, "partial_review", "no cross-reviewers selected \u2014 every finding is under-reviewed (0 of target K)");
31623
+ this.surfaceZeroTagBanner(report2);
31558
31624
  return report2;
31559
31625
  }
31560
31626
  const reviewerCountPerFinding = /* @__PURE__ */ new Map();
@@ -31609,6 +31675,7 @@ ${safeSnippet}
31609
31675
  assigned: reviewerCountPerFinding.get(f.id) ?? 0,
31610
31676
  targetK: findingKMap.get(f.id) ?? 2
31611
31677
  }));
31678
+ this.surfaceZeroTagBanner(report);
31612
31679
  return report;
31613
31680
  }
31614
31681
  /**
@@ -31654,6 +31721,7 @@ ${safeSnippet}
31654
31721
  `;
31655
31722
  this.appendReportWarning(report, "coverage_degraded", evidence);
31656
31723
  }
31724
+ this.surfaceZeroTagBanner(report);
31657
31725
  if (relayCrossReviewSkipped && relayCrossReviewSkipped.length > 0) {
31658
31726
  const lines = ["", "\u26A0\uFE0F Relay cross-review skipped:"];
31659
31727
  for (const s of relayCrossReviewSkipped) {
@@ -34212,11 +34280,11 @@ var init_archetype_catalog = __esm({
34212
34280
  ArchetypeCatalog = class {
34213
34281
  archetypes;
34214
34282
  constructor(catalogPath) {
34215
- const path7 = catalogPath ?? findArchetypeCatalog();
34216
- if (!path7) {
34283
+ const path8 = catalogPath ?? findArchetypeCatalog();
34284
+ if (!path8) {
34217
34285
  throw new Error("archetypes.json not found \u2014 tried bundled dist-mcp/data/, dev ts-node path, and cwd/data/. Reinstall gossipcat.");
34218
34286
  }
34219
- const raw = (0, import_fs34.readFileSync)(path7, "utf-8");
34287
+ const raw = (0, import_fs34.readFileSync)(path8, "utf-8");
34220
34288
  this.archetypes = JSON.parse(raw);
34221
34289
  }
34222
34290
  /** Return all archetype IDs */
@@ -34270,8 +34338,7 @@ function findBundledHook() {
34270
34338
  const candidates = [
34271
34339
  (0, import_path37.resolve)(__dirname, "assets", "hooks", HOOK_FILENAME),
34272
34340
  (0, import_path37.resolve)(__dirname, "..", "..", "..", "assets", "hooks", HOOK_FILENAME),
34273
- (0, import_path37.resolve)(__dirname, "..", "assets", "hooks", HOOK_FILENAME),
34274
- (0, import_path37.resolve)(process.cwd(), "assets", "hooks", HOOK_FILENAME)
34341
+ (0, import_path37.resolve)(__dirname, "..", "assets", "hooks", HOOK_FILENAME)
34275
34342
  ];
34276
34343
  for (const p of candidates) {
34277
34344
  if ((0, import_fs35.existsSync)(p)) return p;
@@ -34331,11 +34398,6 @@ function installWorktreeSandboxHook(projectRoot) {
34331
34398
  try {
34332
34399
  const bundled = findBundledHook();
34333
34400
  if (!bundled) return { installed: false, reason: "bundled hook asset not found" };
34334
- const targetDir = (0, import_path37.join)(projectRoot, ".claude", "hooks");
34335
- const target = (0, import_path37.join)(targetDir, HOOK_FILENAME);
34336
- (0, import_fs35.mkdirSync)(targetDir, { recursive: true });
34337
- (0, import_fs35.copyFileSync)(bundled, target);
34338
- (0, import_fs35.chmodSync)(target, 493);
34339
34401
  const settingsPath = (0, import_path37.join)(projectRoot, ".claude", "settings.json");
34340
34402
  (0, import_fs35.mkdirSync)((0, import_path37.dirname)(settingsPath), { recursive: true });
34341
34403
  let settings;
@@ -34348,6 +34410,11 @@ function installWorktreeSandboxHook(projectRoot) {
34348
34410
  );
34349
34411
  return { installed: false, reason: err.message };
34350
34412
  }
34413
+ const targetDir = (0, import_path37.join)(projectRoot, ".claude", "hooks");
34414
+ const target = (0, import_path37.join)(targetDir, HOOK_FILENAME);
34415
+ (0, import_fs35.mkdirSync)(targetDir, { recursive: true });
34416
+ (0, import_fs35.copyFileSync)(bundled, target);
34417
+ (0, import_fs35.chmodSync)(target, 493);
34351
34418
  const mutated = mergePreToolUseEntry(settings);
34352
34419
  if (mutated) {
34353
34420
  (0, import_fs35.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2) + "\n");
@@ -34381,8 +34448,7 @@ function findDisciplineHook(filename) {
34381
34448
  const candidates = [
34382
34449
  (0, import_path37.resolve)(__dirname, "assets", "hooks", DISCIPLINE_HOOK_DIR, filename),
34383
34450
  (0, import_path37.resolve)(__dirname, "..", "..", "..", "assets", "hooks", DISCIPLINE_HOOK_DIR, filename),
34384
- (0, import_path37.resolve)(__dirname, "..", "assets", "hooks", DISCIPLINE_HOOK_DIR, filename),
34385
- (0, import_path37.resolve)(process.cwd(), "assets", "hooks", DISCIPLINE_HOOK_DIR, filename)
34451
+ (0, import_path37.resolve)(__dirname, "..", "assets", "hooks", DISCIPLINE_HOOK_DIR, filename)
34386
34452
  ];
34387
34453
  for (const p of candidates) {
34388
34454
  if ((0, import_fs35.existsSync)(p)) return p;
@@ -34563,18 +34629,6 @@ function installDisciplineHooks(projectRoot) {
34563
34629
  const installed = [];
34564
34630
  const skipped = [];
34565
34631
  try {
34566
- const targetDir = (0, import_path37.join)(projectRoot, ".claude", "hooks", DISCIPLINE_HOOK_DIR);
34567
- (0, import_fs35.mkdirSync)(targetDir, { recursive: true });
34568
- for (const hook of DISCIPLINE_HOOKS) {
34569
- const bundled = findDisciplineHook(hook.filename);
34570
- if (!bundled) {
34571
- skipped.push(hook.name);
34572
- continue;
34573
- }
34574
- const target = (0, import_path37.join)(targetDir, hook.filename);
34575
- (0, import_fs35.copyFileSync)(bundled, target);
34576
- (0, import_fs35.chmodSync)(target, 493);
34577
- }
34578
34632
  const settingsPath = (0, import_path37.join)(projectRoot, ".claude", "settings.local.json");
34579
34633
  (0, import_fs35.mkdirSync)((0, import_path37.dirname)(settingsPath), { recursive: true });
34580
34634
  let settings;
@@ -34587,6 +34641,18 @@ function installDisciplineHooks(projectRoot) {
34587
34641
  );
34588
34642
  return { installed, skipped, reason: err.message };
34589
34643
  }
34644
+ const targetDir = (0, import_path37.join)(projectRoot, ".claude", "hooks", DISCIPLINE_HOOK_DIR);
34645
+ (0, import_fs35.mkdirSync)(targetDir, { recursive: true });
34646
+ for (const hook of DISCIPLINE_HOOKS) {
34647
+ const bundled = findDisciplineHook(hook.filename);
34648
+ if (!bundled) {
34649
+ skipped.push(hook.name);
34650
+ continue;
34651
+ }
34652
+ const target = (0, import_path37.join)(targetDir, hook.filename);
34653
+ (0, import_fs35.copyFileSync)(bundled, target);
34654
+ (0, import_fs35.chmodSync)(target, 493);
34655
+ }
34590
34656
  let anyMutated = false;
34591
34657
  for (const hook of DISCIPLINE_HOOKS) {
34592
34658
  const bundled = findDisciplineHook(hook.filename);
@@ -35274,8 +35340,8 @@ message: Your question?
35274
35340
  }
35275
35341
  /** Start all worker agents (connect to relay) */
35276
35342
  async start() {
35277
- const { existsSync: existsSync73, readFileSync: readFileSync69 } = await import("fs");
35278
- const { join: join91 } = await import("path");
35343
+ const { existsSync: existsSync74, readFileSync: readFileSync70 } = await import("fs");
35344
+ const { join: join93 } = await import("path");
35279
35345
  for (const config2 of this.registry.getAll()) {
35280
35346
  if (config2.native) continue;
35281
35347
  if (this.workers.has(config2.id)) continue;
@@ -35293,8 +35359,8 @@ message: Your question?
35293
35359
  void 0,
35294
35360
  config2.key_ref
35295
35361
  );
35296
- const instructionsPath = join91(this.projectRoot, ".gossip", "agents", config2.id, "instructions.md");
35297
- const instructions = existsSync73(instructionsPath) ? readFileSync69(instructionsPath, "utf-8") : void 0;
35362
+ const instructionsPath = join93(this.projectRoot, ".gossip", "agents", config2.id, "instructions.md");
35363
+ const instructions = existsSync74(instructionsPath) ? readFileSync70(instructionsPath, "utf-8") : void 0;
35298
35364
  const enableWebSearch = config2.preset === "researcher" || config2.skills.includes("research");
35299
35365
  const worker = new WorkerAgent(config2.id, llm, this.relayUrl, ALL_TOOLS, instructions, enableWebSearch, this.relayApiKey, config2.maxToolTurns);
35300
35366
  await worker.start();
@@ -35491,8 +35557,8 @@ message: Your question?
35491
35557
  this.registry.register(config2);
35492
35558
  }
35493
35559
  async syncWorkers(keyProvider) {
35494
- const { existsSync: existsSync73, readFileSync: readFileSync69 } = await import("fs");
35495
- const { join: join91 } = await import("path");
35560
+ const { existsSync: existsSync74, readFileSync: readFileSync70 } = await import("fs");
35561
+ const { join: join93 } = await import("path");
35496
35562
  let added = 0;
35497
35563
  for (const ac of this.registry.getAll()) {
35498
35564
  if (ac.native) continue;
@@ -35509,8 +35575,8 @@ message: Your question?
35509
35575
  this.workers.delete(ac.id);
35510
35576
  }
35511
35577
  const llm = createProviderForAgent(ac.id, ac.provider, ac.model, key ?? void 0, ac.base_url, void 0, ac.key_ref);
35512
- const instructionsPath = join91(this.projectRoot, ".gossip", "agents", ac.id, "instructions.md");
35513
- const instructions = existsSync73(instructionsPath) ? readFileSync69(instructionsPath, "utf-8") : void 0;
35578
+ const instructionsPath = join93(this.projectRoot, ".gossip", "agents", ac.id, "instructions.md");
35579
+ const instructions = existsSync74(instructionsPath) ? readFileSync70(instructionsPath, "utf-8") : void 0;
35514
35580
  const enableWebSearch = ac.preset === "researcher" || ac.skills.includes("research");
35515
35581
  const worker = new WorkerAgent(ac.id, llm, this.relayUrl, ALL_TOOLS, instructions, enableWebSearch, this.relayApiKey, ac.maxToolTurns);
35516
35582
  await worker.start();
@@ -36487,8 +36553,8 @@ function applyStatusTags(input, statusMap) {
36487
36553
  }
36488
36554
  return { output: lines.join("\n"), changed };
36489
36555
  }
36490
- function atomicWrite(path7, content) {
36491
- const tmp = `${path7}.tmp`;
36556
+ function atomicWrite(path8, content) {
36557
+ const tmp = `${path8}.tmp`;
36492
36558
  let fd;
36493
36559
  try {
36494
36560
  (0, import_fs40.writeFileSync)(tmp, content, "utf-8");
@@ -36496,7 +36562,7 @@ function atomicWrite(path7, content) {
36496
36562
  (0, import_fs40.fsyncSync)(fd);
36497
36563
  (0, import_fs40.closeSync)(fd);
36498
36564
  fd = void 0;
36499
- (0, import_fs40.renameSync)(tmp, path7);
36565
+ (0, import_fs40.renameSync)(tmp, path8);
36500
36566
  } catch (err) {
36501
36567
  if (fd !== void 0) {
36502
36568
  try {
@@ -36637,8 +36703,8 @@ function corpusDir(projectRoot) {
36637
36703
  const encoded = projectRoot.replace(/\//g, "-");
36638
36704
  return (0, import_path43.join)((0, import_os3.homedir)(), ".claude", "projects", encoded, "memory");
36639
36705
  }
36640
- function atomicWriteJson(path7, data) {
36641
- const tmp = `${path7}.tmp`;
36706
+ function atomicWriteJson(path8, data) {
36707
+ const tmp = `${path8}.tmp`;
36642
36708
  let fd;
36643
36709
  try {
36644
36710
  (0, import_fs41.writeFileSync)(tmp, JSON.stringify(data, null, 2), "utf-8");
@@ -36646,7 +36712,7 @@ function atomicWriteJson(path7, data) {
36646
36712
  (0, import_fs41.fsyncSync)(fd);
36647
36713
  (0, import_fs41.closeSync)(fd);
36648
36714
  fd = void 0;
36649
- (0, import_fs41.renameSync)(tmp, path7);
36715
+ (0, import_fs41.renameSync)(tmp, path8);
36650
36716
  } catch (err) {
36651
36717
  if (fd !== void 0) {
36652
36718
  try {
@@ -36856,8 +36922,8 @@ function rebuildIndex(projectRoot) {
36856
36922
  atomicWriteJson(idxPath, index);
36857
36923
  return index;
36858
36924
  }
36859
- function atomicWriteText(path7, content) {
36860
- const tmp = `${path7}.tmp`;
36925
+ function atomicWriteText(path8, content) {
36926
+ const tmp = `${path8}.tmp`;
36861
36927
  let fd;
36862
36928
  try {
36863
36929
  (0, import_fs41.writeFileSync)(tmp, content, "utf-8");
@@ -36865,7 +36931,7 @@ function atomicWriteText(path7, content) {
36865
36931
  (0, import_fs41.fsyncSync)(fd);
36866
36932
  (0, import_fs41.closeSync)(fd);
36867
36933
  fd = void 0;
36868
- (0, import_fs41.renameSync)(tmp, path7);
36934
+ (0, import_fs41.renameSync)(tmp, path8);
36869
36935
  } catch (err) {
36870
36936
  if (fd !== void 0) {
36871
36937
  try {
@@ -37259,29 +37325,29 @@ var init_task_graph_sync = __esm({
37259
37325
  );
37260
37326
  }
37261
37327
  }
37262
- async patch(path7, body) {
37263
- const res = await fetch(`${this.supabaseUrl}${path7}`, {
37328
+ async patch(path8, body) {
37329
+ const res = await fetch(`${this.supabaseUrl}${path8}`, {
37264
37330
  method: "PATCH",
37265
37331
  headers: this.headers(),
37266
37332
  body: JSON.stringify(body)
37267
37333
  });
37268
- if (!res.ok) throw new Error(`PATCH ${path7} failed: ${res.status} ${await res.text()}`);
37334
+ if (!res.ok) throw new Error(`PATCH ${path8} failed: ${res.status} ${await res.text()}`);
37269
37335
  }
37270
- async post(path7, body) {
37271
- const res = await fetch(`${this.supabaseUrl}${path7}`, {
37336
+ async post(path8, body) {
37337
+ const res = await fetch(`${this.supabaseUrl}${path8}`, {
37272
37338
  method: "POST",
37273
37339
  headers: { ...this.headers(), "Prefer": "return=representation" },
37274
37340
  body: JSON.stringify(body)
37275
37341
  });
37276
- if (!res.ok) throw new Error(`POST ${path7} failed: ${res.status} ${await res.text()}`);
37342
+ if (!res.ok) throw new Error(`POST ${path8} failed: ${res.status} ${await res.text()}`);
37277
37343
  }
37278
- async upsert(path7, body) {
37279
- const res = await fetch(`${this.supabaseUrl}${path7}`, {
37344
+ async upsert(path8, body) {
37345
+ const res = await fetch(`${this.supabaseUrl}${path8}`, {
37280
37346
  method: "POST",
37281
37347
  headers: { ...this.headers(), "Prefer": "resolution=merge-duplicates,return=representation" },
37282
37348
  body: JSON.stringify(body)
37283
37349
  });
37284
- if (!res.ok) throw new Error(`UPSERT ${path7} failed: ${res.status} ${await res.text()}`);
37350
+ if (!res.ok) throw new Error(`UPSERT ${path8} failed: ${res.status} ${await res.text()}`);
37285
37351
  }
37286
37352
  headers() {
37287
37353
  return {
@@ -37478,22 +37544,22 @@ async function readJsonBody(req, cap) {
37478
37544
  return { err: "invalid_json", msg: err instanceof Error ? err.message : "parse error" };
37479
37545
  }
37480
37546
  }
37481
- function replyBodyErr(ctx2, req, res, rec, started, path7, body) {
37547
+ function replyBodyErr(ctx2, req, res, rec, started, path8, body) {
37482
37548
  if (body.err === "too_large") {
37483
37549
  ctx2.sendJson(res, 413, ctx2.errBody("payload_too_large", "payload_too_large", body.msg));
37484
- ctx2.logEvent({ started, req, status: 413, path: path7, bytesRead: 0, bytesWritten: 0, token: rec.token });
37550
+ ctx2.logEvent({ started, req, status: 413, path: path8, bytesRead: 0, bytesWritten: 0, token: rec.token });
37485
37551
  } else {
37486
37552
  ctx2.sendJson(res, 400, ctx2.errBody("bad_request", "bad_request", body.msg));
37487
- ctx2.logEvent({ started, req, status: 400, path: path7, bytesRead: 0, bytesWritten: 0, token: rec.token });
37553
+ ctx2.logEvent({ started, req, status: 400, path: path8, bytesRead: 0, bytesWritten: 0, token: rec.token });
37488
37554
  }
37489
37555
  }
37490
- function reply403(ctx2, req, res, rec, started, path7, msg) {
37556
+ function reply403(ctx2, req, res, rec, started, path8, msg) {
37491
37557
  ctx2.sendJson(res, 403, ctx2.errBody("forbidden", "scope_violation", msg));
37492
- ctx2.logEvent({ started, req, status: 403, path: path7, bytesRead: 0, bytesWritten: 0, token: rec.token });
37558
+ ctx2.logEvent({ started, req, status: 403, path: path8, bytesRead: 0, bytesWritten: 0, token: rec.token });
37493
37559
  }
37494
- function reply429(ctx2, req, res, rec, started, path7) {
37560
+ function reply429(ctx2, req, res, rec, started, path8) {
37495
37561
  ctx2.send429(res);
37496
- ctx2.logEvent({ started, req, status: 429, path: path7, bytesRead: 0, bytesWritten: 0, token: rec.token });
37562
+ ctx2.logEvent({ started, req, status: 429, path: path8, bytesRead: 0, bytesWritten: 0, token: rec.token });
37497
37563
  }
37498
37564
  async function handleBridgeInfo(ctx2, req, res, started, ip) {
37499
37565
  if (!ctx2.limBridgeInfo.record(ip)) {
@@ -37532,12 +37598,12 @@ async function handleFileRead(ctx2, req, res, rec, started) {
37532
37598
  if (!ctx2.limRead.record(`read:${rec.token}`)) return reply429(ctx2, req, res, rec, started, "/file-read");
37533
37599
  const body = await readJsonBody(req, MAX_FILE_BYTES);
37534
37600
  if ("err" in body) return replyBodyErr(ctx2, req, res, rec, started, "/file-read", body);
37535
- const path7 = typeof body.value?.path === "string" ? body.value.path : "";
37536
- if (!path7) {
37601
+ const path8 = typeof body.value?.path === "string" ? body.value.path : "";
37602
+ if (!path8) {
37537
37603
  ctx2.sendJson(res, 400, ctx2.errBody("bad_request", "bad_request", "path is required"));
37538
37604
  return ctx2.logEvent({ started, req, status: 400, path: "/file-read", bytesRead: 0, bytesWritten: 0, token: rec.token });
37539
37605
  }
37540
- const abs = resolveInScope(rec, path7);
37606
+ const abs = resolveInScope(rec, path8);
37541
37607
  if (!abs.ok) return reply403(ctx2, req, res, rec, started, "/file-read", abs.msg);
37542
37608
  let fileSize;
37543
37609
  let mtime;
@@ -37578,14 +37644,14 @@ async function handleFileWrite(ctx2, req, res, rec, started) {
37578
37644
  if (!ctx2.limWrite.record(`write:${rec.token}`)) return reply429(ctx2, req, res, rec, started, "/file-write");
37579
37645
  const body = await readJsonBody(req, MAX_FILE_BYTES);
37580
37646
  if ("err" in body) return replyBodyErr(ctx2, req, res, rec, started, "/file-write", body);
37581
- const path7 = typeof body.value?.path === "string" ? body.value.path : "";
37647
+ const path8 = typeof body.value?.path === "string" ? body.value.path : "";
37582
37648
  const content = typeof body.value?.content === "string" ? body.value.content : "";
37583
37649
  const ifMatch = typeof body.value?.if_match === "string" ? body.value.if_match : void 0;
37584
- if (!path7) {
37650
+ if (!path8) {
37585
37651
  ctx2.sendJson(res, 400, ctx2.errBody("bad_request", "bad_request", "path is required"));
37586
37652
  return ctx2.logEvent({ started, req, status: 400, path: "/file-write", bytesRead: 0, bytesWritten: 0, token: rec.token });
37587
37653
  }
37588
- const abs = resolveInScope(rec, path7);
37654
+ const abs = resolveInScope(rec, path8);
37589
37655
  if (!abs.ok) return reply403(ctx2, req, res, rec, started, "/file-write", abs.msg);
37590
37656
  const buf = Buffer.from(content, "utf-8");
37591
37657
  if (buf.byteLength > MAX_FILE_BYTES) {
@@ -38234,12 +38300,12 @@ function buildIndexFromDisk(memoryDir, agentIds) {
38234
38300
  };
38235
38301
  }
38236
38302
  function readValidSidecar(projectRoot, memoryDir) {
38237
- const path7 = proseResolverPath(projectRoot);
38238
- if (!(0, import_fs44.existsSync)(path7)) return null;
38303
+ const path8 = proseResolverPath(projectRoot);
38304
+ if (!(0, import_fs44.existsSync)(path8)) return null;
38239
38305
  let parsed;
38240
38306
  try {
38241
- if ((0, import_fs44.statSync)(path7).size > SIDECAR_READ_LIMIT) return null;
38242
- parsed = JSON.parse((0, import_fs44.readFileSync)(path7, "utf-8"));
38307
+ if ((0, import_fs44.statSync)(path8).size > SIDECAR_READ_LIMIT) return null;
38308
+ parsed = JSON.parse((0, import_fs44.readFileSync)(path8, "utf-8"));
38243
38309
  } catch {
38244
38310
  return null;
38245
38311
  }
@@ -38259,10 +38325,10 @@ function readValidSidecar(projectRoot, memoryDir) {
38259
38325
  return idx;
38260
38326
  }
38261
38327
  function writeSidecar(projectRoot, idx) {
38262
- const path7 = proseResolverPath(projectRoot);
38328
+ const path8 = proseResolverPath(projectRoot);
38263
38329
  try {
38264
- (0, import_fs44.mkdirSync)((0, import_path48.dirname)(path7), { recursive: true });
38265
- (0, import_fs44.writeFileSync)(path7, JSON.stringify(idx));
38330
+ (0, import_fs44.mkdirSync)((0, import_path48.dirname)(path8), { recursive: true });
38331
+ (0, import_fs44.writeFileSync)(path8, JSON.stringify(idx));
38266
38332
  } catch {
38267
38333
  }
38268
38334
  }
@@ -38427,11 +38493,11 @@ function isLedgerIndex(x) {
38427
38493
  return typeof o.ledgerMtime === "number" && typeof o.ledgerContentHash === "string" && Array.isArray(o.entries) && o.entries.every((e) => e !== null && typeof e === "object" && typeof e.bulletHash === "string" && typeof e.verdict === "string" && typeof e.details === "string" && typeof e.checkedAt === "string");
38428
38494
  }
38429
38495
  function readLedgerIndex(projectRoot, liveLedgerContent, liveLedgerMtime) {
38430
- const path7 = ledgerIndexPath(projectRoot);
38431
- if (!(0, import_fs45.existsSync)(path7)) return null;
38496
+ const path8 = ledgerIndexPath(projectRoot);
38497
+ if (!(0, import_fs45.existsSync)(path8)) return null;
38432
38498
  let parsed;
38433
38499
  try {
38434
- parsed = JSON.parse((0, import_fs45.readFileSync)(path7, "utf-8"));
38500
+ parsed = JSON.parse((0, import_fs45.readFileSync)(path8, "utf-8"));
38435
38501
  } catch {
38436
38502
  return null;
38437
38503
  }
@@ -38441,10 +38507,10 @@ function readLedgerIndex(projectRoot, liveLedgerContent, liveLedgerMtime) {
38441
38507
  return parsed;
38442
38508
  }
38443
38509
  function writeLedgerIndex(projectRoot, index) {
38444
- const path7 = ledgerIndexPath(projectRoot);
38510
+ const path8 = ledgerIndexPath(projectRoot);
38445
38511
  try {
38446
- (0, import_fs45.mkdirSync)((0, import_path49.dirname)(path7), { recursive: true });
38447
- (0, import_fs45.writeFileSync)(path7, JSON.stringify(index, null, 2));
38512
+ (0, import_fs45.mkdirSync)((0, import_path49.dirname)(path8), { recursive: true });
38513
+ (0, import_fs45.writeFileSync)(path8, JSON.stringify(index, null, 2));
38448
38514
  } catch {
38449
38515
  }
38450
38516
  }
@@ -38552,9 +38618,9 @@ function annotateLedgerText(raw, bullets, entriesByHash) {
38552
38618
  }
38553
38619
  return lines.join("\n");
38554
38620
  }
38555
- function ledgerMtime(ledgerPath) {
38621
+ function ledgerMtime(ledgerPath2) {
38556
38622
  try {
38557
- return (0, import_fs45.statSync)(ledgerPath).mtimeMs;
38623
+ return (0, import_fs45.statSync)(ledgerPath2).mtimeMs;
38558
38624
  } catch {
38559
38625
  return 0;
38560
38626
  }
@@ -38616,10 +38682,10 @@ function checkDistMcpStaleness(bundlePath) {
38616
38682
  let newestMtime = 0;
38617
38683
  let newestPath;
38618
38684
  for (const root of SRC_ROOTS) {
38619
- walk((0, import_path50.join)(repoRoot, root), (path7, mtimeMs) => {
38685
+ walk((0, import_path50.join)(repoRoot, root), (path8, mtimeMs) => {
38620
38686
  if (mtimeMs > newestMtime) {
38621
38687
  newestMtime = mtimeMs;
38622
- newestPath = path7;
38688
+ newestPath = path8;
38623
38689
  }
38624
38690
  });
38625
38691
  }
@@ -39089,13 +39155,13 @@ Skills are auto-injected from agent config. Project-wide skills in .gossip/skill
39089
39155
  *
39090
39156
  * Bootstrap critical path stays synchronous and fast.
39091
39157
  */
39092
- applyLedgerAnnotations(content, ledgerPath) {
39158
+ applyLedgerAnnotations(content, ledgerPath2) {
39093
39159
  try {
39094
39160
  const bullets = parseNextSessionBullets(content);
39095
39161
  if (bullets.length === 0) return content;
39096
39162
  let mtime = 0;
39097
39163
  try {
39098
- mtime = (0, import_fs47.statSync)(ledgerPath).mtimeMs;
39164
+ mtime = (0, import_fs47.statSync)(ledgerPath2).mtimeMs;
39099
39165
  } catch {
39100
39166
  }
39101
39167
  const index = readLedgerIndex(this.projectRoot, content, mtime);
@@ -39241,19 +39307,19 @@ function hasControlChars(s) {
39241
39307
  }
39242
39308
  return false;
39243
39309
  }
39244
- async function gitCommonDir(path7) {
39310
+ async function gitCommonDir(path8) {
39245
39311
  try {
39246
39312
  const { stdout } = await execFileP(
39247
39313
  "git",
39248
- ["-C", path7, "rev-parse", "--git-common-dir"],
39314
+ ["-C", path8, "rev-parse", "--git-common-dir"],
39249
39315
  GIT_EXEC_OPTS
39250
39316
  );
39251
39317
  const out = stdout.trim();
39252
39318
  if (!out) return null;
39253
39319
  try {
39254
- return (0, import_fs48.realpathSync)((0, import_path52.resolve)(path7, out));
39320
+ return (0, import_fs48.realpathSync)((0, import_path52.resolve)(path8, out));
39255
39321
  } catch {
39256
- return (0, import_path52.resolve)(path7, out);
39322
+ return (0, import_path52.resolve)(path8, out);
39257
39323
  }
39258
39324
  } catch {
39259
39325
  return null;
@@ -39279,17 +39345,17 @@ function parseWorktreePorcelain(stdout, { includeLocked = false } = {}) {
39279
39345
  const fields = rec.split("\0").filter(Boolean);
39280
39346
  const worktreeField = fields.find((f) => f.startsWith("worktree "));
39281
39347
  if (!worktreeField) continue;
39282
- const path7 = worktreeField.slice("worktree ".length);
39348
+ const path8 = worktreeField.slice("worktree ".length);
39283
39349
  if (fields.some(
39284
39350
  (f) => f === "bare" || !includeLocked && f.startsWith("locked") || f.startsWith("prunable")
39285
39351
  )) {
39286
39352
  continue;
39287
39353
  }
39288
- let canonical = path7;
39354
+ let canonical = path8;
39289
39355
  try {
39290
- canonical = (0, import_fs48.realpathSync)((0, import_path52.resolve)(path7));
39356
+ canonical = (0, import_fs48.realpathSync)((0, import_path52.resolve)(path8));
39291
39357
  } catch {
39292
- canonical = (0, import_path52.resolve)(path7);
39358
+ canonical = (0, import_path52.resolve)(path8);
39293
39359
  }
39294
39360
  out.push(canonical);
39295
39361
  if (out.length >= 100) break;
@@ -40415,6 +40481,89 @@ var init_chatbot_agent = __esm({
40415
40481
  }
40416
40482
  });
40417
40483
 
40484
+ // packages/orchestrator/src/orchestrator-preconditions.ts
40485
+ function detectStaleBase(dispatchSha, originMasterSha, mergeBaseSha) {
40486
+ if (dispatchSha === originMasterSha) {
40487
+ return { stale: false, reason: null };
40488
+ }
40489
+ if (mergeBaseSha === dispatchSha) {
40490
+ return { stale: true, reason: "behind_origin" };
40491
+ }
40492
+ if (mergeBaseSha === originMasterSha) {
40493
+ return { stale: false, reason: "ahead_of_origin" };
40494
+ }
40495
+ return { stale: true, reason: "branched_pre_merge" };
40496
+ }
40497
+ function findUnreadablePaths(paths, canRead) {
40498
+ return paths.filter((p) => !canRead(p));
40499
+ }
40500
+ function extractReferencedPathsWithMeta(taskText) {
40501
+ if (!taskText) {
40502
+ return { paths: [], droppedOverCap: 0 };
40503
+ }
40504
+ const rawTokens = taskText.split(/[\s`]+/);
40505
+ const seen = /* @__PURE__ */ new Set();
40506
+ const out = [];
40507
+ let droppedOverCap = 0;
40508
+ for (const raw of rawTokens) {
40509
+ const trimmed = raw.replace(/^[([{<"']+/, "").replace(/[)\]}>"',.;:]+$/, "");
40510
+ const token = trimmed.replace(/:\d+(?::\d+)?$/, "");
40511
+ if (token.length === 0) {
40512
+ continue;
40513
+ }
40514
+ if (token.startsWith("/") || token.includes("..")) {
40515
+ continue;
40516
+ }
40517
+ if (!REPO_PATH_SHAPE.test(token)) {
40518
+ continue;
40519
+ }
40520
+ if (seen.has(token)) {
40521
+ continue;
40522
+ }
40523
+ seen.add(token);
40524
+ if (out.length >= MAX_REFERENCED_PATHS) {
40525
+ droppedOverCap += 1;
40526
+ continue;
40527
+ }
40528
+ out.push(token);
40529
+ }
40530
+ return { paths: out, droppedOverCap };
40531
+ }
40532
+ function extractReferencedPaths(taskText) {
40533
+ return extractReferencedPathsWithMeta(taskText).paths;
40534
+ }
40535
+ function findUnreadableReferencedPaths(taskText, opts) {
40536
+ return findUnreadableReferencedPathsWithMeta(taskText, opts).unreadable;
40537
+ }
40538
+ function findUnreadableReferencedPathsWithMeta(taskText, opts) {
40539
+ const { paths, droppedOverCap } = extractReferencedPathsWithMeta(taskText);
40540
+ const out = [];
40541
+ const isWorktree = opts.writeMode === "worktree";
40542
+ for (const path8 of paths) {
40543
+ const exists = opts.pathExists(path8);
40544
+ if (!exists) {
40545
+ out.push({ path: path8, reason: "missing" });
40546
+ continue;
40547
+ }
40548
+ if (isWorktree && opts.isGitignoredOrUntracked(path8)) {
40549
+ out.push({ path: path8, reason: "gitignored_in_worktree" });
40550
+ }
40551
+ }
40552
+ return { unreadable: out, droppedOverCap };
40553
+ }
40554
+ function detectMidFlightCommits(commitsBetween) {
40555
+ const count = commitsBetween.length;
40556
+ return { detected: count > 0, count };
40557
+ }
40558
+ var REPO_PATH_SHAPE, MAX_REFERENCED_PATHS;
40559
+ var init_orchestrator_preconditions = __esm({
40560
+ "packages/orchestrator/src/orchestrator-preconditions.ts"() {
40561
+ "use strict";
40562
+ REPO_PATH_SHAPE = /^(?:\.\/)?[\w./-]+\.(?:md|ts|tsx|js|json|txt|ya?ml)$/;
40563
+ MAX_REFERENCED_PATHS = 20;
40564
+ }
40565
+ });
40566
+
40418
40567
  // packages/orchestrator/src/index.ts
40419
40568
  var src_exports3 = {};
40420
40569
  __export(src_exports3, {
@@ -40540,6 +40689,8 @@ __export(src_exports3, {
40540
40689
  defaultVerifierFactory: () => defaultVerifierFactory,
40541
40690
  deriveConsensusId: () => deriveConsensusId,
40542
40691
  detectFormatCompliance: () => detectFormatCompliance,
40692
+ detectMidFlightCommits: () => detectMidFlightCommits,
40693
+ detectStaleBase: () => detectStaleBase,
40543
40694
  discoverAgentIdsForRoot: () => discoverAgentIdsForRoot,
40544
40695
  discoverGitWorktrees: () => discoverGitWorktrees,
40545
40696
  emitCitationFabricatedSignal: () => emitCitationFabricatedSignal,
@@ -40552,11 +40703,16 @@ __export(src_exports3, {
40552
40703
  ensureRulesFile: () => ensureRulesFile,
40553
40704
  extractCategories: () => extractCategories,
40554
40705
  extractConsensusId: () => extractConsensusId,
40706
+ extractReferencedPaths: () => extractReferencedPaths,
40707
+ extractReferencedPathsWithMeta: () => extractReferencedPathsWithMeta,
40555
40708
  extractSpecReferences: () => extractSpecReferences,
40556
40709
  extractTokens: () => extractTokens,
40557
40710
  findBundledHook: () => findBundledHook,
40558
40711
  findBundledRules: () => findBundledRules,
40559
40712
  findOpenSectionLine: () => findOpenSectionLine,
40713
+ findUnreadablePaths: () => findUnreadablePaths,
40714
+ findUnreadableReferencedPaths: () => findUnreadableReferencedPaths,
40715
+ findUnreadableReferencedPathsWithMeta: () => findUnreadableReferencedPathsWithMeta,
40560
40716
  formatCooldownMessage: () => formatCooldownMessage,
40561
40717
  formatStalenessWarning: () => formatStalenessWarning,
40562
40718
  getRoundCounter: () => get,
@@ -40739,6 +40895,7 @@ var init_src4 = __esm({
40739
40895
  init_runtime_config();
40740
40896
  init_runtime_config_schema();
40741
40897
  init_chatbot_agent();
40898
+ init_orchestrator_preconditions();
40742
40899
  }
40743
40900
  });
40744
40901
 
@@ -41958,10 +42115,10 @@ var init_auth = __esm({
41958
42115
  * left half-written by a crash. Validate the shape before trusting it and
41959
42116
  * fail closed (regenerate) on anything unexpected — never throw.
41960
42117
  */
41961
- loadPersisted(path7) {
42118
+ loadPersisted(path8) {
41962
42119
  try {
41963
- if (!(0, import_fs54.existsSync)(path7)) return false;
41964
- const parsed = JSON.parse((0, import_fs54.readFileSync)(path7, "utf8"));
42120
+ if (!(0, import_fs54.existsSync)(path8)) return false;
42121
+ const parsed = JSON.parse((0, import_fs54.readFileSync)(path8, "utf8"));
41965
42122
  if (!isPersistedAuth(parsed)) return false;
41966
42123
  this.key = parsed.key;
41967
42124
  this.sessions.clear();
@@ -42197,9 +42354,9 @@ var init_api_open_findings = __esm({
42197
42354
  });
42198
42355
 
42199
42356
  // packages/relay/src/dashboard/api-overview.ts
42200
- function readSkillStatus(path7) {
42357
+ function readSkillStatus(path8) {
42201
42358
  try {
42202
- const content = (0, import_fs56.readFileSync)(path7, "utf-8");
42359
+ const content = (0, import_fs56.readFileSync)(path8, "utf-8");
42203
42360
  const m = content.match(/^---\n([\s\S]*?)\n---/);
42204
42361
  if (!m) return null;
42205
42362
  const block = m[1];
@@ -42513,9 +42670,9 @@ var init_api_fleet_trend = __esm({
42513
42670
  // packages/relay/src/dashboard/api-agents.ts
42514
42671
  function readSkillFrontmatter(projectRoot, agentId, skillName) {
42515
42672
  try {
42516
- const path7 = (0, import_path62.join)(projectRoot, ".gossip", "agents", agentId, "skills", `${skillName}.md`);
42517
- if (!(0, import_fs58.existsSync)(path7)) return null;
42518
- const raw = (0, import_fs58.readFileSync)(path7, "utf-8");
42673
+ const path8 = (0, import_path62.join)(projectRoot, ".gossip", "agents", agentId, "skills", `${skillName}.md`);
42674
+ if (!(0, import_fs58.existsSync)(path8)) return null;
42675
+ const raw = (0, import_fs58.readFileSync)(path8, "utf-8");
42519
42676
  if (!raw.startsWith("---")) return null;
42520
42677
  const end = raw.indexOf("\n---", 3);
42521
42678
  if (end === -1) return null;
@@ -42553,9 +42710,9 @@ function normalizeCategory(s) {
42553
42710
  }
42554
42711
  function readForcedDevelops(projectRoot, agentId, category) {
42555
42712
  try {
42556
- const path7 = (0, import_path62.join)(projectRoot, ".gossip", "forced-skill-develops.jsonl");
42557
- if (!(0, import_fs58.existsSync)(path7)) return [];
42558
- const raw = (0, import_fs58.readFileSync)(path7, "utf-8");
42713
+ const path8 = (0, import_path62.join)(projectRoot, ".gossip", "forced-skill-develops.jsonl");
42714
+ if (!(0, import_fs58.existsSync)(path8)) return [];
42715
+ const raw = (0, import_fs58.readFileSync)(path8, "utf-8");
42559
42716
  const target = normalizeCategory(category);
42560
42717
  const out = [];
42561
42718
  for (const line of raw.split("\n")) {
@@ -43837,7 +43994,9 @@ async function tasksHandler(projectRoot, query) {
43837
43994
  });
43838
43995
  } else if (entry.type === "task.completed") {
43839
43996
  completed.set(entry.taskId, {
43840
- duration: entry.duration,
43997
+ // On-disk field is "durationMs"; "entry.duration" was previously
43998
+ // undefined, silently dropping all task durations from the response.
43999
+ duration: entry.durationMs ?? entry.duration,
43841
44000
  timestamp: entry.timestamp,
43842
44001
  failed: false,
43843
44002
  inputTokens: entry.inputTokens,
@@ -43873,7 +44032,11 @@ async function tasksHandler(projectRoot, query) {
43873
44032
  result: result?.result,
43874
44033
  status: result ? result.cancelled ? "cancelled" : result.failed ? "failed" : "completed" : "running",
43875
44034
  duration: result?.duration,
44035
+ // timestamp = completion time for terminal tasks (used as "Completed" node in timeline).
44036
+ // For running tasks, falls back to createdAt.
43876
44037
  timestamp: result?.timestamp || info.timestamp,
44038
+ // createdAt = always the dispatch time (task.created event timestamp).
44039
+ createdAt: info.timestamp,
43877
44040
  inputTokens: result?.inputTokens,
43878
44041
  outputTokens: result?.outputTokens
43879
44042
  });
@@ -43891,14 +44054,149 @@ var init_api_tasks = __esm({
43891
44054
  }
43892
44055
  });
43893
44056
 
44057
+ // packages/relay/src/dashboard/api-task-detail.ts
44058
+ function readJsonlLines(filePath) {
44059
+ const out = [];
44060
+ const archive = filePath + ".1";
44061
+ if ((0, import_fs67.existsSync)(archive)) {
44062
+ out.push(...(0, import_fs67.readFileSync)(archive, "utf-8").split("\n").filter(Boolean));
44063
+ }
44064
+ if ((0, import_fs67.existsSync)(filePath)) {
44065
+ out.push(...(0, import_fs67.readFileSync)(filePath, "utf-8").split("\n").filter(Boolean));
44066
+ }
44067
+ return out;
44068
+ }
44069
+ async function taskDetailHandler(projectRoot, taskId) {
44070
+ const graphPath = (0, import_path74.join)(projectRoot, ".gossip", "task-graph.jsonl");
44071
+ if (!(0, import_fs67.existsSync)(graphPath) && !(0, import_fs67.existsSync)(graphPath + ".1")) {
44072
+ return null;
44073
+ }
44074
+ const created = /* @__PURE__ */ new Map();
44075
+ const completed = /* @__PURE__ */ new Map();
44076
+ try {
44077
+ const lines = readJsonlLines(graphPath);
44078
+ for (const line of lines) {
44079
+ try {
44080
+ const entry = JSON.parse(line);
44081
+ if (entry.type === "task.created") {
44082
+ created.set(entry.taskId, {
44083
+ agentId: entry.agentId || "?",
44084
+ task: entry.task || "",
44085
+ timestamp: entry.timestamp
44086
+ });
44087
+ } else if (entry.type === "task.completed") {
44088
+ completed.set(entry.taskId, {
44089
+ duration: entry.durationMs ?? entry.duration,
44090
+ timestamp: entry.timestamp,
44091
+ failed: false,
44092
+ inputTokens: entry.inputTokens,
44093
+ outputTokens: entry.outputTokens,
44094
+ result: typeof entry.result === "string" ? entry.result : void 0
44095
+ });
44096
+ } else if (entry.type === "task.failed") {
44097
+ completed.set(entry.taskId, { timestamp: entry.timestamp, failed: true });
44098
+ } else if (entry.type === "task.cancelled") {
44099
+ completed.set(entry.taskId, { timestamp: entry.timestamp, failed: false, cancelled: true });
44100
+ }
44101
+ } catch {
44102
+ }
44103
+ }
44104
+ } catch {
44105
+ return null;
44106
+ }
44107
+ const info = created.get(taskId);
44108
+ if (!info) return null;
44109
+ const result = completed.get(taskId);
44110
+ const base = {
44111
+ taskId,
44112
+ agentId: info.agentId,
44113
+ task: info.task,
44114
+ result: result?.result,
44115
+ status: result ? result.cancelled ? "cancelled" : result.failed ? "failed" : "completed" : "running",
44116
+ duration: result?.duration,
44117
+ timestamp: result?.timestamp || info.timestamp,
44118
+ createdAt: info.timestamp,
44119
+ inputTokens: result?.inputTokens,
44120
+ outputTokens: result?.outputTokens
44121
+ };
44122
+ let consensusId;
44123
+ let signalCount = 0;
44124
+ const siblingSet = /* @__PURE__ */ new Set();
44125
+ const perfPath = (0, import_path74.join)(projectRoot, ".gossip", "agent-performance.jsonl");
44126
+ try {
44127
+ const lines = readJsonlLines(perfPath);
44128
+ const allEntries = [];
44129
+ for (const line of lines) {
44130
+ try {
44131
+ const entry = JSON.parse(line);
44132
+ if (typeof entry.taskId !== "string") continue;
44133
+ allEntries.push(entry);
44134
+ if (entry.taskId === taskId) {
44135
+ signalCount++;
44136
+ if (!consensusId && typeof entry.consensusId === "string" && entry.consensusId) {
44137
+ consensusId = entry.consensusId;
44138
+ }
44139
+ }
44140
+ } catch {
44141
+ }
44142
+ }
44143
+ if (consensusId) {
44144
+ for (const entry of allEntries) {
44145
+ if (siblingSet.size >= SIBLING_CAP) break;
44146
+ if (entry.consensusId === consensusId && typeof entry.taskId === "string" && entry.taskId && entry.taskId !== taskId) {
44147
+ siblingSet.add(entry.taskId);
44148
+ }
44149
+ }
44150
+ }
44151
+ } catch {
44152
+ }
44153
+ let findingCount = 0;
44154
+ if (consensusId) {
44155
+ const prefix = `${consensusId}:`;
44156
+ const findingsPath = (0, import_path74.join)(projectRoot, ".gossip", "implementation-findings.jsonl");
44157
+ try {
44158
+ const lines = readJsonlLines(findingsPath);
44159
+ for (const line of lines) {
44160
+ try {
44161
+ const entry = JSON.parse(line);
44162
+ if (typeof entry.taskId === "string" && entry.taskId.startsWith(prefix)) {
44163
+ findingCount++;
44164
+ }
44165
+ } catch {
44166
+ }
44167
+ }
44168
+ } catch {
44169
+ }
44170
+ }
44171
+ const siblingTaskIds = siblingSet.size > 0 ? [...siblingSet] : void 0;
44172
+ const siblingsTruncated = siblingSet.size >= SIBLING_CAP;
44173
+ return {
44174
+ ...base,
44175
+ ...consensusId !== void 0 && { consensusId },
44176
+ ...siblingTaskIds !== void 0 && { siblingTaskIds },
44177
+ ...siblingsTruncated && { siblingsTruncated },
44178
+ signalCount,
44179
+ findingCount
44180
+ };
44181
+ }
44182
+ var import_fs67, import_path74, SIBLING_CAP;
44183
+ var init_api_task_detail = __esm({
44184
+ "packages/relay/src/dashboard/api-task-detail.ts"() {
44185
+ "use strict";
44186
+ import_fs67 = require("fs");
44187
+ import_path74 = require("path");
44188
+ SIBLING_CAP = 25;
44189
+ }
44190
+ });
44191
+
43894
44192
  // packages/relay/src/dashboard/api-active-tasks.ts
43895
44193
  async function activeTasksHandler(projectRoot) {
43896
- const taskGraphPath = (0, import_path74.join)(projectRoot, ".gossip", "task-graph.jsonl");
43897
- if (!(0, import_fs67.existsSync)(taskGraphPath)) return { tasks: [] };
44194
+ const taskGraphPath = (0, import_path75.join)(projectRoot, ".gossip", "task-graph.jsonl");
44195
+ if (!(0, import_fs68.existsSync)(taskGraphPath)) return { tasks: [] };
43898
44196
  const created = /* @__PURE__ */ new Map();
43899
44197
  const finished = /* @__PURE__ */ new Set();
43900
44198
  try {
43901
- const lines = (0, import_fs67.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
44199
+ const lines = (0, import_fs68.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
43902
44200
  for (const line of lines) {
43903
44201
  try {
43904
44202
  const ev = JSON.parse(line);
@@ -43926,19 +44224,19 @@ async function activeTasksHandler(projectRoot) {
43926
44224
  active.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
43927
44225
  return { tasks: active.slice(0, 10) };
43928
44226
  }
43929
- var import_fs67, import_path74;
44227
+ var import_fs68, import_path75;
43930
44228
  var init_api_active_tasks = __esm({
43931
44229
  "packages/relay/src/dashboard/api-active-tasks.ts"() {
43932
44230
  "use strict";
43933
- import_fs67 = require("fs");
43934
- import_path74 = require("path");
44231
+ import_fs68 = require("fs");
44232
+ import_path75 = require("path");
43935
44233
  init_utility_agents();
43936
44234
  }
43937
44235
  });
43938
44236
 
43939
44237
  // packages/relay/src/dashboard/api-session.ts
43940
44238
  function resolveGitBranch(cwd) {
43941
- return new Promise((resolve32) => {
44239
+ return new Promise((resolve33) => {
43942
44240
  let done = false;
43943
44241
  const child = (0, import_node_child_process2.execFile)(
43944
44242
  "git",
@@ -43948,21 +44246,21 @@ function resolveGitBranch(cwd) {
43948
44246
  if (done) return;
43949
44247
  done = true;
43950
44248
  if (err) {
43951
- resolve32(null);
44249
+ resolve33(null);
43952
44250
  return;
43953
44251
  }
43954
44252
  const branch = stdout.trim();
43955
44253
  if (!branch || branch === "HEAD") {
43956
- resolve32(null);
44254
+ resolve33(null);
43957
44255
  return;
43958
44256
  }
43959
- resolve32(branch);
44257
+ resolve33(branch);
43960
44258
  }
43961
44259
  );
43962
44260
  child.on("error", () => {
43963
44261
  if (!done) {
43964
44262
  done = true;
43965
- resolve32(null);
44263
+ resolve33(null);
43966
44264
  }
43967
44265
  });
43968
44266
  });
@@ -43974,16 +44272,16 @@ async function sessionHandler(projectRoot) {
43974
44272
  ]);
43975
44273
  return {
43976
44274
  gitBranch,
43977
- projectName: (0, import_path75.basename)(projectRoot),
44275
+ projectName: (0, import_path76.basename)(projectRoot),
43978
44276
  activeTasks
43979
44277
  };
43980
44278
  }
43981
- var import_node_child_process2, import_path75;
44279
+ var import_node_child_process2, import_path76;
43982
44280
  var init_api_session = __esm({
43983
44281
  "packages/relay/src/dashboard/api-session.ts"() {
43984
44282
  "use strict";
43985
44283
  import_node_child_process2 = require("node:child_process");
43986
- import_path75 = require("path");
44284
+ import_path76 = require("path");
43987
44285
  init_api_active_tasks();
43988
44286
  }
43989
44287
  });
@@ -43997,25 +44295,25 @@ function categorize(text) {
43997
44295
  return "other";
43998
44296
  }
43999
44297
  function logsHandler(projectRoot, query) {
44000
- const logPath = (0, import_path76.join)(projectRoot, ".gossip", "mcp.log");
44001
- if (!(0, import_fs68.existsSync)(logPath)) {
44298
+ const logPath = (0, import_path77.join)(projectRoot, ".gossip", "mcp.log");
44299
+ if (!(0, import_fs69.existsSync)(logPath)) {
44002
44300
  return { entries: [], totalLines: 0, fileSize: 0 };
44003
44301
  }
44004
44302
  const filter = query?.get("filter") || void 0;
44005
44303
  const tail = parseInt(query?.get("tail") || "200", 10);
44006
44304
  const clampedTail = Math.min(Math.max(tail, 10), 2e3);
44007
- const fileSize = (0, import_fs68.statSync)(logPath).size;
44305
+ const fileSize = (0, import_fs69.statSync)(logPath).size;
44008
44306
  const MAX_READ = 512 * 1024;
44009
44307
  const readFrom = Math.max(0, fileSize - MAX_READ);
44010
44308
  const readLen = fileSize - readFrom;
44011
- const fd = (0, import_fs68.openSync)(logPath, "r");
44309
+ const fd = (0, import_fs69.openSync)(logPath, "r");
44012
44310
  let buf = Buffer.alloc(0);
44013
44311
  try {
44014
44312
  buf = Buffer.allocUnsafe(readLen);
44015
- const bytesRead = (0, import_fs68.readSync)(fd, buf, 0, readLen, readFrom);
44313
+ const bytesRead = (0, import_fs69.readSync)(fd, buf, 0, readLen, readFrom);
44016
44314
  buf = buf.subarray(0, bytesRead);
44017
44315
  } finally {
44018
- (0, import_fs68.closeSync)(fd);
44316
+ (0, import_fs69.closeSync)(fd);
44019
44317
  }
44020
44318
  let raw = buf.toString("utf-8");
44021
44319
  let lineOffset = 0;
@@ -44023,13 +44321,13 @@ function logsHandler(projectRoot, query) {
44023
44321
  const nl = raw.indexOf("\n");
44024
44322
  raw = nl >= 0 ? raw.slice(nl + 1) : raw;
44025
44323
  const SCAN_CHUNK = 64 * 1024;
44026
- const scanFd = (0, import_fs68.openSync)(logPath, "r");
44324
+ const scanFd = (0, import_fs69.openSync)(logPath, "r");
44027
44325
  try {
44028
44326
  let pos = 0;
44029
44327
  const chunk = Buffer.allocUnsafe(SCAN_CHUNK);
44030
44328
  while (pos < readFrom) {
44031
44329
  const len = Math.min(SCAN_CHUNK, readFrom - pos);
44032
- const n = (0, import_fs68.readSync)(scanFd, chunk, 0, len, pos);
44330
+ const n = (0, import_fs69.readSync)(scanFd, chunk, 0, len, pos);
44033
44331
  if (n === 0) break;
44034
44332
  for (let j = 0; j < n; j++) {
44035
44333
  if (chunk[j] === 10) lineOffset++;
@@ -44037,7 +44335,7 @@ function logsHandler(projectRoot, query) {
44037
44335
  pos += n;
44038
44336
  }
44039
44337
  } finally {
44040
- (0, import_fs68.closeSync)(scanFd);
44338
+ (0, import_fs69.closeSync)(scanFd);
44041
44339
  }
44042
44340
  }
44043
44341
  const allLines = raw.split("\n").filter(Boolean);
@@ -44055,12 +44353,12 @@ function logsHandler(projectRoot, query) {
44055
44353
  entries = entries.slice(-clampedTail);
44056
44354
  return { entries, totalLines, fileSize, filter };
44057
44355
  }
44058
- var import_fs68, import_path76, CATEGORY_PATTERNS2;
44356
+ var import_fs69, import_path77, CATEGORY_PATTERNS2;
44059
44357
  var init_api_logs = __esm({
44060
44358
  "packages/relay/src/dashboard/api-logs.ts"() {
44061
44359
  "use strict";
44062
- import_fs68 = require("fs");
44063
- import_path76 = require("path");
44360
+ import_fs69 = require("fs");
44361
+ import_path77 = require("path");
44064
44362
  CATEGORY_PATTERNS2 = [
44065
44363
  [/^\[worker:/, "worker"],
44066
44364
  [/^\[Gemini\]/, "gemini"],
@@ -44092,11 +44390,11 @@ function violationsHandler(projectRoot, query) {
44092
44390
  const page = Math.max(1, parseInt(query?.get("page") ?? "1", 10));
44093
44391
  const pageSize = Math.min(100, Math.max(1, parseInt(query?.get("pageSize") ?? "25", 10)));
44094
44392
  const agentFilter = query?.get("agentId") ?? null;
44095
- const filePath = (0, import_path77.join)(projectRoot, FILE);
44096
- if (!(0, import_fs69.existsSync)(filePath)) {
44393
+ const filePath = (0, import_path78.join)(projectRoot, FILE);
44394
+ if (!(0, import_fs70.existsSync)(filePath)) {
44097
44395
  return { items: [], total: 0, page, pageSize };
44098
44396
  }
44099
- const raw = (0, import_fs69.readFileSync)(filePath, "utf-8");
44397
+ const raw = (0, import_fs70.readFileSync)(filePath, "utf-8");
44100
44398
  const lines = raw.trim().split("\n").filter(Boolean);
44101
44399
  const entries = [];
44102
44400
  for (const line of lines) {
@@ -44116,12 +44414,12 @@ function violationsHandler(projectRoot, query) {
44116
44414
  const start = (page - 1) * pageSize;
44117
44415
  return { items: entries.slice(start, start + pageSize), total, page, pageSize };
44118
44416
  }
44119
- var import_fs69, import_path77, FILE;
44417
+ var import_fs70, import_path78, FILE;
44120
44418
  var init_api_violations = __esm({
44121
44419
  "packages/relay/src/dashboard/api-violations.ts"() {
44122
44420
  "use strict";
44123
- import_fs69 = require("fs");
44124
- import_path77 = require("path");
44421
+ import_fs70 = require("fs");
44422
+ import_path78 = require("path");
44125
44423
  FILE = ".gossip/process-violations.jsonl";
44126
44424
  }
44127
44425
  });
@@ -44217,12 +44515,12 @@ function isMirrorFrameShaped(obj) {
44217
44515
  const f = obj;
44218
44516
  return f.type === "mirror" && typeof f.chat_id === "string" && typeof f.role === "string" && typeof f.text === "string" && typeof f.ts === "string" && typeof f.id === "number";
44219
44517
  }
44220
- var import_fs70, import_path78, CHAT_ID_RE, PERSIST_CAP, MAX_LINE_BYTES, NullChatStore, FileChatStore;
44518
+ var import_fs71, import_path79, CHAT_ID_RE, PERSIST_CAP, MAX_LINE_BYTES, NullChatStore, FileChatStore;
44221
44519
  var init_chat_store = __esm({
44222
44520
  "packages/relay/src/dashboard/chat-store.ts"() {
44223
44521
  "use strict";
44224
- import_fs70 = require("fs");
44225
- import_path78 = require("path");
44522
+ import_fs71 = require("fs");
44523
+ import_path79 = require("path");
44226
44524
  CHAT_ID_RE = /^[a-zA-Z0-9_-]{1,128}$/;
44227
44525
  PERSIST_CAP = 1e3;
44228
44526
  MAX_LINE_BYTES = 256 * 1024;
@@ -44254,15 +44552,15 @@ var init_chat_store = __esm({
44254
44552
  return CHAT_ID_RE.test(chatId);
44255
44553
  }
44256
44554
  filePath(chatId) {
44257
- return (0, import_path78.join)(this.chatDir, `${chatId}.jsonl`);
44555
+ return (0, import_path79.join)(this.chatDir, `${chatId}.jsonl`);
44258
44556
  }
44259
44557
  append(chatId, frame) {
44260
44558
  if (!this.isValidChatId(chatId)) return;
44261
44559
  if (chatId.startsWith("_")) return;
44262
44560
  try {
44263
- (0, import_fs70.mkdirSync)(this.chatDir, { recursive: true });
44561
+ (0, import_fs71.mkdirSync)(this.chatDir, { recursive: true });
44264
44562
  const line = JSON.stringify(frame) + "\n";
44265
- (0, import_fs70.appendFileSync)(this.filePath(chatId), line, "utf8");
44563
+ (0, import_fs71.appendFileSync)(this.filePath(chatId), line, "utf8");
44266
44564
  const prev = this.appendCounters.get(chatId);
44267
44565
  const count = (prev ?? 0) + 1;
44268
44566
  this.appendCounters.set(chatId, count);
@@ -44278,13 +44576,13 @@ var init_chat_store = __esm({
44278
44576
  if (chatId.startsWith("_")) return;
44279
44577
  try {
44280
44578
  const fp = this.filePath(chatId);
44281
- const content = (0, import_fs70.readFileSync)(fp, "utf8");
44579
+ const content = (0, import_fs71.readFileSync)(fp, "utf8");
44282
44580
  const lines = content.split("\n").filter((l) => l.length > 0);
44283
44581
  if (lines.length < 2 * PERSIST_CAP) return;
44284
44582
  const kept = lines.slice(lines.length - PERSIST_CAP);
44285
44583
  const tmp = fp + ".tmp";
44286
- (0, import_fs70.writeFileSync)(tmp, kept.join("\n") + "\n", "utf8");
44287
- (0, import_fs70.renameSync)(tmp, fp);
44584
+ (0, import_fs71.writeFileSync)(tmp, kept.join("\n") + "\n", "utf8");
44585
+ (0, import_fs71.renameSync)(tmp, fp);
44288
44586
  } catch (err) {
44289
44587
  this.cleanupStaleTmp(chatId);
44290
44588
  console.warn(`[chat-store] retain failed for chatId=${chatId}`, err);
@@ -44299,7 +44597,7 @@ var init_chat_store = __esm({
44299
44597
  */
44300
44598
  cleanupStaleTmp(chatId) {
44301
44599
  try {
44302
- (0, import_fs70.unlinkSync)(this.filePath(chatId) + ".tmp");
44600
+ (0, import_fs71.unlinkSync)(this.filePath(chatId) + ".tmp");
44303
44601
  } catch (err) {
44304
44602
  if (err?.code !== "ENOENT") {
44305
44603
  console.warn(`[chat-store] stale .tmp cleanup failed for chatId=${chatId}:`, err);
@@ -44311,7 +44609,7 @@ var init_chat_store = __esm({
44311
44609
  this.cleanupStaleTmp(chatId);
44312
44610
  let content;
44313
44611
  try {
44314
- content = (0, import_fs70.readFileSync)(this.filePath(chatId), "utf8");
44612
+ content = (0, import_fs71.readFileSync)(this.filePath(chatId), "utf8");
44315
44613
  } catch (err) {
44316
44614
  if (err?.code === "ENOENT") return [];
44317
44615
  console.warn(`[chat-store] load failed for chatId=${chatId}:`, err);
@@ -44341,7 +44639,7 @@ var init_chat_store = __esm({
44341
44639
  drop(chatId) {
44342
44640
  if (!this.isValidChatId(chatId)) return;
44343
44641
  try {
44344
- (0, import_fs70.unlinkSync)(this.filePath(chatId));
44642
+ (0, import_fs71.unlinkSync)(this.filePath(chatId));
44345
44643
  } catch (err) {
44346
44644
  if (err?.code !== "ENOENT") {
44347
44645
  console.warn(`[chat-store] drop failed for chatId=${chatId}:`, err);
@@ -45552,20 +45850,20 @@ function normalizeLegacyDegradedFields(report) {
45552
45850
  }
45553
45851
  function resolveDashboardRoot(projectRoot) {
45554
45852
  const candidates = [
45555
- (0, import_path79.resolve)(__dirname, "..", "dist-dashboard"),
45853
+ (0, import_path80.resolve)(__dirname, "..", "dist-dashboard"),
45556
45854
  // bundled: dist-mcp/mcp-server.js → ../dist-dashboard
45557
- (0, import_path79.resolve)(__dirname, "..", "..", "..", "..", "dist-dashboard"),
45855
+ (0, import_path80.resolve)(__dirname, "..", "..", "..", "..", "dist-dashboard"),
45558
45856
  // tsc dev: packages/relay/dist/dashboard → repo-root
45559
- (0, import_path79.join)(projectRoot, "dist-dashboard")
45857
+ (0, import_path80.join)(projectRoot, "dist-dashboard")
45560
45858
  // legacy dev fallback (git-clone running from repo root)
45561
45859
  ];
45562
45860
  for (const p of candidates) {
45563
- if ((0, import_fs71.existsSync)(p)) return p;
45861
+ if ((0, import_fs72.existsSync)(p)) return p;
45564
45862
  }
45565
45863
  return null;
45566
45864
  }
45567
45865
  function readBody(req, maxBytes = MAX_BODY_SIZE) {
45568
- return new Promise((resolve32, reject) => {
45866
+ return new Promise((resolve33, reject) => {
45569
45867
  const chunks = [];
45570
45868
  let size = 0;
45571
45869
  let tooLarge = false;
@@ -45580,14 +45878,14 @@ function readBody(req, maxBytes = MAX_BODY_SIZE) {
45580
45878
  chunks.push(chunk);
45581
45879
  });
45582
45880
  req.on("end", () => {
45583
- if (!tooLarge) resolve32(Buffer.concat(chunks).toString("utf-8"));
45881
+ if (!tooLarge) resolve33(Buffer.concat(chunks).toString("utf-8"));
45584
45882
  });
45585
45883
  req.on("error", (err) => {
45586
45884
  if (!tooLarge) reject(err);
45587
45885
  });
45588
45886
  });
45589
45887
  }
45590
- var import_fs71, import_path79, import_crypto28, AUTH_MAX_ATTEMPTS, AUTH_LOCKOUT_MS, AUTH_ATTEMPT_TTL_MS, AUTH_ATTEMPTS_HARD_CAP, CHAT_MAX_BODY, BRIDGE_MAX_BODY, MIRROR_MAX_BODY, MIRROR_MIN_INTERVAL_MS, MIRROR_LAST_TURN_HARD_CAP, CHAT_MIN_INTERVAL_MS, DashboardRouter, MAX_BODY_SIZE;
45888
+ var import_fs72, import_path80, import_crypto28, AUTH_MAX_ATTEMPTS, AUTH_LOCKOUT_MS, AUTH_ATTEMPT_TTL_MS, AUTH_ATTEMPTS_HARD_CAP, CHAT_MAX_BODY, BRIDGE_MAX_BODY, MIRROR_MAX_BODY, MIRROR_MIN_INTERVAL_MS, MIRROR_LAST_TURN_HARD_CAP, CHAT_MIN_INTERVAL_MS, DashboardRouter, MAX_BODY_SIZE;
45591
45889
  var init_routes = __esm({
45592
45890
  "packages/relay/src/dashboard/routes.ts"() {
45593
45891
  "use strict";
@@ -45607,6 +45905,7 @@ var init_routes = __esm({
45607
45905
  init_api_open_findings();
45608
45906
  init_api_learnings();
45609
45907
  init_api_tasks();
45908
+ init_api_task_detail();
45610
45909
  init_api_active_tasks();
45611
45910
  init_api_session();
45612
45911
  init_api_logs();
@@ -45615,8 +45914,8 @@ var init_routes = __esm({
45615
45914
  init_api_bridge();
45616
45915
  init_chat_session_store();
45617
45916
  init_src4();
45618
- import_fs71 = require("fs");
45619
- import_path79 = require("path");
45917
+ import_fs72 = require("fs");
45918
+ import_path80 = require("path");
45620
45919
  import_crypto28 = require("crypto");
45621
45920
  AUTH_MAX_ATTEMPTS = 10;
45622
45921
  AUTH_LOCKOUT_MS = 6e4;
@@ -45634,7 +45933,7 @@ var init_routes = __esm({
45634
45933
  this.projectRoot = projectRoot;
45635
45934
  this.ctx = ctx2;
45636
45935
  this.dashboardRoot = resolveDashboardRoot(projectRoot);
45637
- this.bridge = new BridgeHub({ chatDir: (0, import_path79.join)(projectRoot, ".gossip", "chat") });
45936
+ this.bridge = new BridgeHub({ chatDir: (0, import_path80.join)(projectRoot, ".gossip", "chat") });
45638
45937
  }
45639
45938
  auth;
45640
45939
  projectRoot;
@@ -45935,6 +46234,19 @@ var init_routes = __esm({
45935
46234
  this.json(res, 200, data);
45936
46235
  return true;
45937
46236
  }
46237
+ {
46238
+ const m = url2.match(/^\/dashboard\/api\/tasks\/([^/]+)$/);
46239
+ if (m && req.method === "GET") {
46240
+ const taskId = decodeURIComponent(m[1]);
46241
+ const data = await taskDetailHandler(this.projectRoot, taskId);
46242
+ if (data === null) {
46243
+ this.json(res, 404, { error: `Task not found: ${taskId}` });
46244
+ } else {
46245
+ this.json(res, 200, data);
46246
+ }
46247
+ return true;
46248
+ }
46249
+ }
45938
46250
  if (url2 === "/dashboard/api/active-tasks" && req.method === "GET") {
45939
46251
  const data = await activeTasksHandler(this.projectRoot);
45940
46252
  this.json(res, 200, data);
@@ -46147,13 +46459,13 @@ var init_routes = __esm({
46147
46459
  res.end("Dashboard assets not found. Reinstall gossipcat or rebuild from source.");
46148
46460
  return true;
46149
46461
  }
46150
- const htmlPath = (0, import_path79.join)(this.dashboardRoot, "index.html");
46151
- if (!(0, import_fs71.existsSync)(htmlPath)) {
46462
+ const htmlPath = (0, import_path80.join)(this.dashboardRoot, "index.html");
46463
+ if (!(0, import_fs72.existsSync)(htmlPath)) {
46152
46464
  res.writeHead(503, { "Content-Type": "text/plain" });
46153
46465
  res.end(`Dashboard index.html missing at ${this.dashboardRoot}. Reinstall gossipcat.`);
46154
46466
  return true;
46155
46467
  }
46156
- const html = (0, import_fs71.readFileSync)(htmlPath, "utf-8");
46468
+ const html = (0, import_fs72.readFileSync)(htmlPath, "utf-8");
46157
46469
  res.writeHead(200, {
46158
46470
  "Content-Type": "text/html; charset=utf-8",
46159
46471
  "Cache-Control": "no-cache"
@@ -46182,16 +46494,16 @@ var init_routes = __esm({
46182
46494
  const ext = "." + (relativePath.split(".").pop() || "");
46183
46495
  const mime = MIME[ext];
46184
46496
  if (!mime) return false;
46185
- const filePath = (0, import_path79.join)(this.dashboardRoot, relativePath);
46497
+ const filePath = (0, import_path80.join)(this.dashboardRoot, relativePath);
46186
46498
  try {
46187
- const realFile = (0, import_fs71.realpathSync)(filePath);
46188
- const realBase = (0, import_fs71.realpathSync)(this.dashboardRoot);
46499
+ const realFile = (0, import_fs72.realpathSync)(filePath);
46500
+ const realBase = (0, import_fs72.realpathSync)(this.dashboardRoot);
46189
46501
  if (!realFile.startsWith(realBase + "/")) {
46190
46502
  res.writeHead(404);
46191
46503
  res.end();
46192
46504
  return true;
46193
46505
  }
46194
- const data = (0, import_fs71.readFileSync)(realFile);
46506
+ const data = (0, import_fs72.readFileSync)(realFile);
46195
46507
  res.writeHead(200, { "Content-Type": mime, "Cache-Control": "public, max-age=86400" });
46196
46508
  res.end(data);
46197
46509
  return true;
@@ -46206,8 +46518,8 @@ var init_routes = __esm({
46206
46518
  return match ? match[1] : null;
46207
46519
  }
46208
46520
  getConsensusReports(page = 1, pageSize = 5) {
46209
- const { readdirSync: readdirSync22, readFileSync: readFileSync69, existsSync: existsSync73 } = require("fs");
46210
- const reportsDir = (0, import_path79.join)(this.projectRoot, ".gossip", "consensus-reports");
46521
+ const { readdirSync: readdirSync22, readFileSync: readFileSync70, existsSync: existsSync74 } = require("fs");
46522
+ const reportsDir = (0, import_path80.join)(this.projectRoot, ".gossip", "consensus-reports");
46211
46523
  let retractedConsensusIds = [];
46212
46524
  let roundRetractions = [];
46213
46525
  try {
@@ -46217,13 +46529,13 @@ var init_routes = __esm({
46217
46529
  roundRetractions = reader.getRoundRetractions();
46218
46530
  } catch {
46219
46531
  }
46220
- if (!existsSync73(reportsDir)) return { reports: [], totalReports: 0, page, pageSize, retractedConsensusIds, roundRetractions };
46532
+ if (!existsSync74(reportsDir)) return { reports: [], totalReports: 0, page, pageSize, retractedConsensusIds, roundRetractions };
46221
46533
  try {
46222
46534
  const { statSync: statSync36 } = require("fs");
46223
46535
  const allFiles = readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).sort((a, b) => {
46224
46536
  try {
46225
- const aTime = statSync36((0, import_path79.join)(reportsDir, a)).mtimeMs;
46226
- const bTime = statSync36((0, import_path79.join)(reportsDir, b)).mtimeMs;
46537
+ const aTime = statSync36((0, import_path80.join)(reportsDir, a)).mtimeMs;
46538
+ const bTime = statSync36((0, import_path80.join)(reportsDir, b)).mtimeMs;
46227
46539
  return bTime - aTime;
46228
46540
  } catch {
46229
46541
  return 0;
@@ -46234,13 +46546,13 @@ var init_routes = __esm({
46234
46546
  const clampedPage = Math.max(page, 1);
46235
46547
  const start = (clampedPage - 1) * clampedPageSize;
46236
46548
  const files = allFiles.slice(start, start + clampedPageSize);
46237
- const realReportsDir = (0, import_fs71.realpathSync)(reportsDir);
46549
+ const realReportsDir = (0, import_fs72.realpathSync)(reportsDir);
46238
46550
  const reports = files.map((f) => {
46239
46551
  try {
46240
- const filePath = (0, import_path79.join)(reportsDir, f);
46241
- const realFile = (0, import_fs71.realpathSync)(filePath);
46552
+ const filePath = (0, import_path80.join)(reportsDir, f);
46553
+ const realFile = (0, import_fs72.realpathSync)(filePath);
46242
46554
  if (!realFile.startsWith(realReportsDir + "/")) return null;
46243
- return normalizeLegacyDegradedFields(JSON.parse(readFileSync69(realFile, "utf-8")));
46555
+ return normalizeLegacyDegradedFields(JSON.parse(readFileSync70(realFile, "utf-8")));
46244
46556
  } catch {
46245
46557
  return null;
46246
46558
  }
@@ -46251,29 +46563,29 @@ var init_routes = __esm({
46251
46563
  }
46252
46564
  }
46253
46565
  archiveFindings() {
46254
- const { readdirSync: readdirSync22, readFileSync: readFileSync69, renameSync: renameSync18, writeFileSync: writeFileSync38, mkdirSync: mkdirSync45, existsSync: existsSync73 } = require("fs");
46255
- const reportsDir = (0, import_path79.join)(this.projectRoot, ".gossip", "consensus-reports");
46256
- const archiveDir = (0, import_path79.join)(this.projectRoot, ".gossip", "consensus-reports-archive");
46566
+ const { readdirSync: readdirSync22, readFileSync: readFileSync70, renameSync: renameSync18, writeFileSync: writeFileSync38, mkdirSync: mkdirSync45, existsSync: existsSync74 } = require("fs");
46567
+ const reportsDir = (0, import_path80.join)(this.projectRoot, ".gossip", "consensus-reports");
46568
+ const archiveDir = (0, import_path80.join)(this.projectRoot, ".gossip", "consensus-reports-archive");
46257
46569
  let archived = 0;
46258
- if (existsSync73(reportsDir)) {
46570
+ if (existsSync74(reportsDir)) {
46259
46571
  const files = readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).sort().reverse();
46260
46572
  if (files.length > 5) {
46261
46573
  mkdirSync45(archiveDir, { recursive: true });
46262
46574
  const toArchive = files.slice(5);
46263
46575
  for (const f of toArchive) {
46264
46576
  try {
46265
- renameSync18((0, import_path79.join)(reportsDir, f), (0, import_path79.join)(archiveDir, f));
46577
+ renameSync18((0, import_path80.join)(reportsDir, f), (0, import_path80.join)(archiveDir, f));
46266
46578
  archived++;
46267
46579
  } catch {
46268
46580
  }
46269
46581
  }
46270
46582
  }
46271
46583
  }
46272
- const findingsPath = (0, import_path79.join)(this.projectRoot, ".gossip", "implementation-findings.jsonl");
46584
+ const findingsPath = (0, import_path80.join)(this.projectRoot, ".gossip", "implementation-findings.jsonl");
46273
46585
  let findingsCleared = 0;
46274
- if (existsSync73(findingsPath)) {
46586
+ if (existsSync74(findingsPath)) {
46275
46587
  try {
46276
- const lines = readFileSync69(findingsPath, "utf-8").trim().split("\n").filter(Boolean);
46588
+ const lines = readFileSync70(findingsPath, "utf-8").trim().split("\n").filter(Boolean);
46277
46589
  const kept = lines.filter((line) => {
46278
46590
  try {
46279
46591
  const entry = JSON.parse(line);
@@ -46290,7 +46602,7 @@ var init_routes = __esm({
46290
46602
  } catch {
46291
46603
  }
46292
46604
  }
46293
- const remaining = existsSync73(reportsDir) ? readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).length : 0;
46605
+ const remaining = existsSync74(reportsDir) ? readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).length : 0;
46294
46606
  return { archived, remaining, findingsCleared };
46295
46607
  }
46296
46608
  json(res, status, data) {
@@ -46303,14 +46615,14 @@ var init_routes = __esm({
46303
46615
  });
46304
46616
 
46305
46617
  // packages/relay/src/dashboard/ws.ts
46306
- var import_fs72, import_fs73, import_path80, DashboardWs;
46618
+ var import_fs73, import_fs74, import_path81, DashboardWs;
46307
46619
  var init_ws = __esm({
46308
46620
  "packages/relay/src/dashboard/ws.ts"() {
46309
46621
  "use strict";
46310
46622
  init_wrapper();
46311
- import_fs72 = require("fs");
46312
46623
  import_fs73 = require("fs");
46313
- import_path80 = require("path");
46624
+ import_fs74 = require("fs");
46625
+ import_path81 = require("path");
46314
46626
  DashboardWs = class {
46315
46627
  clients = /* @__PURE__ */ new Set();
46316
46628
  logWatcher = null;
@@ -46335,15 +46647,15 @@ var init_ws = __esm({
46335
46647
  /** Start watching mcp.log for new lines and broadcasting them to connected clients. */
46336
46648
  startLogWatcher(projectRoot) {
46337
46649
  this.stopLogWatcher();
46338
- this.logPath = (0, import_path80.join)(projectRoot, ".gossip", "mcp.log");
46339
- if (!(0, import_fs72.existsSync)(this.logPath)) return;
46650
+ this.logPath = (0, import_path81.join)(projectRoot, ".gossip", "mcp.log");
46651
+ if (!(0, import_fs73.existsSync)(this.logPath)) return;
46340
46652
  try {
46341
- this.logOffset = (0, import_fs72.statSync)(this.logPath).size;
46653
+ this.logOffset = (0, import_fs73.statSync)(this.logPath).size;
46342
46654
  } catch {
46343
46655
  this.logOffset = 0;
46344
46656
  }
46345
46657
  try {
46346
- this.logWatcher = (0, import_fs73.watch)(this.logPath, () => {
46658
+ this.logWatcher = (0, import_fs74.watch)(this.logPath, () => {
46347
46659
  if (this.clients.size === 0) return;
46348
46660
  this.readNewLines();
46349
46661
  });
@@ -46360,7 +46672,7 @@ var init_ws = __esm({
46360
46672
  if (this.logReading) return;
46361
46673
  this.logReading = true;
46362
46674
  try {
46363
- const currentSize = (0, import_fs72.statSync)(this.logPath).size;
46675
+ const currentSize = (0, import_fs73.statSync)(this.logPath).size;
46364
46676
  if (currentSize < this.logOffset) {
46365
46677
  this.logOffset = 0;
46366
46678
  this.logCarry = "";
@@ -46373,7 +46685,7 @@ var init_ws = __esm({
46373
46685
  const readFrom = capped ? (this.logCarry = "", this.logCapped = true, currentSize - 65536) : (this.logCapped = false, this.logOffset);
46374
46686
  let stream;
46375
46687
  try {
46376
- stream = (0, import_fs72.createReadStream)(this.logPath, { start: readFrom, end: currentSize - 1 });
46688
+ stream = (0, import_fs73.createReadStream)(this.logPath, { start: readFrom, end: currentSize - 1 });
46377
46689
  } catch {
46378
46690
  this.logReading = false;
46379
46691
  return;
@@ -46487,7 +46799,7 @@ var init_server = __esm({
46487
46799
  return this.heartbeatRunning;
46488
46800
  }
46489
46801
  async start() {
46490
- return new Promise((resolve32) => {
46802
+ return new Promise((resolve33) => {
46491
46803
  this.httpServer = (0, import_http.createServer)(this.handleHttp.bind(this));
46492
46804
  if (this.config.dashboard) {
46493
46805
  this.dashboardAuth = new DashboardAuth();
@@ -46533,7 +46845,7 @@ var init_server = __esm({
46533
46845
  this.httpServer.listen(this.config.port, this.config.host ?? "127.0.0.1", () => {
46534
46846
  const addr = this.httpServer.address();
46535
46847
  this._port = addr.port;
46536
- resolve32();
46848
+ resolve33();
46537
46849
  });
46538
46850
  });
46539
46851
  }
@@ -46553,9 +46865,9 @@ var init_server = __esm({
46553
46865
  for (const client of this.wss.clients) {
46554
46866
  client.close(1001, "Server shutting down");
46555
46867
  }
46556
- return new Promise((resolve32) => {
46868
+ return new Promise((resolve33) => {
46557
46869
  this.wss.close(() => {
46558
- this.httpServer.close(() => resolve32());
46870
+ this.httpServer.close(() => resolve33());
46559
46871
  });
46560
46872
  });
46561
46873
  }
@@ -46969,8 +47281,8 @@ function parsePorcelain(output) {
46969
47281
  const paths = [];
46970
47282
  for (const line of lines) {
46971
47283
  if (line.length < 4) continue;
46972
- const path7 = line.slice(3);
46973
- if (path7) paths.push(path7);
47284
+ const path8 = line.slice(3);
47285
+ if (path8) paths.push(path8);
46974
47286
  }
46975
47287
  return paths.sort();
46976
47288
  }
@@ -46993,12 +47305,12 @@ function revertLeakedPaths(cwd, paths) {
46993
47305
  if (!paths || paths.length === 0) return result;
46994
47306
  const { safe: safePaths, rejected } = filterSafePaths(paths);
46995
47307
  result.rejected = rejected;
46996
- const fs6 = require("fs");
46997
- const path7 = require("path");
47308
+ const fs7 = require("fs");
47309
+ const path8 = require("path");
46998
47310
  const present = [];
46999
47311
  for (const p of safePaths) {
47000
- const abs = path7.join(cwd, p);
47001
- if (fs6.existsSync(abs)) {
47312
+ const abs = path8.join(cwd, p);
47313
+ if (fs7.existsSync(abs)) {
47002
47314
  present.push(p);
47003
47315
  } else {
47004
47316
  result.skipped.push(p);
@@ -47028,12 +47340,12 @@ function preserveLeakedPaths(cwd, paths, taskId) {
47028
47340
  }
47029
47341
  const { safe: safePaths, rejected } = filterSafePaths(paths);
47030
47342
  result.rejected = rejected;
47031
- const fs6 = require("fs");
47032
- const path7 = require("path");
47343
+ const fs7 = require("fs");
47344
+ const path8 = require("path");
47033
47345
  const crypto3 = require("crypto");
47034
47346
  const present = [];
47035
47347
  for (const p of safePaths) {
47036
- if (fs6.existsSync(path7.join(cwd, p))) {
47348
+ if (fs7.existsSync(path8.join(cwd, p))) {
47037
47349
  present.push(p);
47038
47350
  } else {
47039
47351
  result.skipped.push(p);
@@ -47068,16 +47380,16 @@ function preserveLeakedPaths(cwd, paths, taskId) {
47068
47380
  result.emptyDiff = true;
47069
47381
  return result;
47070
47382
  }
47071
- const recoveryDir = path7.join(cwd, ".gossip", "recovery");
47072
- fs6.mkdirSync(recoveryDir, { recursive: true });
47073
- const finalPath = path7.join(recoveryDir, `${taskId}.patch`);
47074
- const tmpPath = path7.join(recoveryDir, `${taskId}.patch.${crypto3.randomUUID().slice(0, 8)}.tmp`);
47383
+ const recoveryDir = path8.join(cwd, ".gossip", "recovery");
47384
+ fs7.mkdirSync(recoveryDir, { recursive: true });
47385
+ const finalPath = path8.join(recoveryDir, `${taskId}.patch`);
47386
+ const tmpPath = path8.join(recoveryDir, `${taskId}.patch.${crypto3.randomUUID().slice(0, 8)}.tmp`);
47075
47387
  try {
47076
- fs6.writeFileSync(tmpPath, diff);
47077
- fs6.renameSync(tmpPath, finalPath);
47388
+ fs7.writeFileSync(tmpPath, diff);
47389
+ fs7.renameSync(tmpPath, finalPath);
47078
47390
  } catch (err) {
47079
47391
  try {
47080
- fs6.unlinkSync(tmpPath);
47392
+ fs7.unlinkSync(tmpPath);
47081
47393
  } catch {
47082
47394
  }
47083
47395
  throw err;
@@ -47221,14 +47533,14 @@ __export(sandbox_exports, {
47221
47533
  });
47222
47534
  function rotateIfNeeded2(filePath, maxBytes) {
47223
47535
  try {
47224
- const st = (0, import_fs74.statSync)(filePath);
47536
+ const st = (0, import_fs75.statSync)(filePath);
47225
47537
  if (st.size < maxBytes) return;
47226
47538
  const rotated = filePath + ".1";
47227
47539
  try {
47228
- if ((0, import_fs74.existsSync)(rotated)) (0, import_fs74.unlinkSync)(rotated);
47540
+ if ((0, import_fs75.existsSync)(rotated)) (0, import_fs75.unlinkSync)(rotated);
47229
47541
  } catch {
47230
47542
  }
47231
- (0, import_fs74.renameSync)(filePath, rotated);
47543
+ (0, import_fs75.renameSync)(filePath, rotated);
47232
47544
  } catch {
47233
47545
  }
47234
47546
  }
@@ -47301,9 +47613,9 @@ Tests passing is NOT sufficient verification \u2014 the 2026-04-22 incident had
47301
47613
  }
47302
47614
  function readSandboxMode(projectRoot) {
47303
47615
  try {
47304
- const p = (0, import_path81.join)(projectRoot, ".gossip", "config.json");
47305
- if (!(0, import_fs74.existsSync)(p)) return "warn";
47306
- const raw = JSON.parse((0, import_fs74.readFileSync)(p, "utf-8"));
47616
+ const p = (0, import_path82.join)(projectRoot, ".gossip", "config.json");
47617
+ if (!(0, import_fs75.existsSync)(p)) return "warn";
47618
+ const raw = JSON.parse((0, import_fs75.readFileSync)(p, "utf-8"));
47307
47619
  const mode = raw?.sandboxEnforcement;
47308
47620
  if (mode === "off" || mode === "warn" || mode === "block") return mode;
47309
47621
  return "warn";
@@ -47313,8 +47625,8 @@ function readSandboxMode(projectRoot) {
47313
47625
  }
47314
47626
  function recordDispatchMetadata(projectRoot, meta3) {
47315
47627
  try {
47316
- const dir = (0, import_path81.join)(projectRoot, ".gossip");
47317
- (0, import_fs74.mkdirSync)(dir, { recursive: true });
47628
+ const dir = (0, import_path82.join)(projectRoot, ".gossip");
47629
+ (0, import_fs75.mkdirSync)(dir, { recursive: true });
47318
47630
  const snapshotted = { ...meta3 };
47319
47631
  if (meta3.writeMode === "scoped" || meta3.writeMode === "worktree") {
47320
47632
  try {
@@ -47332,15 +47644,15 @@ function recordDispatchMetadata(projectRoot, meta3) {
47332
47644
  } catch {
47333
47645
  }
47334
47646
  }
47335
- (0, import_fs74.appendFileSync)((0, import_path81.join)(dir, METADATA_FILE), JSON.stringify(snapshotted) + "\n");
47647
+ (0, import_fs75.appendFileSync)((0, import_path82.join)(dir, METADATA_FILE), JSON.stringify(snapshotted) + "\n");
47336
47648
  } catch {
47337
47649
  }
47338
47650
  }
47339
47651
  function updateDispatchMetadata(projectRoot, taskId, patch) {
47340
47652
  try {
47341
- const p = (0, import_path81.join)(projectRoot, ".gossip", METADATA_FILE);
47342
- if (!(0, import_fs74.existsSync)(p)) return false;
47343
- const raw = (0, import_fs74.readFileSync)(p, "utf-8");
47653
+ const p = (0, import_path82.join)(projectRoot, ".gossip", METADATA_FILE);
47654
+ if (!(0, import_fs75.existsSync)(p)) return false;
47655
+ const raw = (0, import_fs75.readFileSync)(p, "utf-8");
47344
47656
  const lines = raw.split("\n");
47345
47657
  let patched = false;
47346
47658
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -47358,7 +47670,7 @@ function updateDispatchMetadata(projectRoot, taskId, patch) {
47358
47670
  }
47359
47671
  }
47360
47672
  if (!patched) return false;
47361
- (0, import_fs74.writeFileSync)(p, lines.join("\n"));
47673
+ (0, import_fs75.writeFileSync)(p, lines.join("\n"));
47362
47674
  return true;
47363
47675
  } catch {
47364
47676
  return false;
@@ -47367,15 +47679,15 @@ function updateDispatchMetadata(projectRoot, taskId, patch) {
47367
47679
  function stampTaskSentinel(projectRoot, taskId) {
47368
47680
  if (!taskId) return null;
47369
47681
  try {
47370
- const dir = (0, import_path81.join)(projectRoot, ".gossip", SENTINEL_DIR);
47371
- (0, import_fs74.mkdirSync)(dir, { recursive: true });
47682
+ const dir = (0, import_path82.join)(projectRoot, ".gossip", SENTINEL_DIR);
47683
+ (0, import_fs75.mkdirSync)(dir, { recursive: true });
47372
47684
  const slug = taskId.replace(/[^a-zA-Z0-9_-]/g, "_");
47373
- const path7 = (0, import_path81.join)(dir, `${slug}.sentinel`);
47374
- const fd = (0, import_fs74.openSync)(path7, "w");
47375
- (0, import_fs74.closeSync)(fd);
47685
+ const path8 = (0, import_path82.join)(dir, `${slug}.sentinel`);
47686
+ const fd = (0, import_fs75.openSync)(path8, "w");
47687
+ (0, import_fs75.closeSync)(fd);
47376
47688
  const stampTime = new Date(Date.now() - 2e3);
47377
- (0, import_fs74.utimesSync)(path7, stampTime, stampTime);
47378
- return path7;
47689
+ (0, import_fs75.utimesSync)(path8, stampTime, stampTime);
47690
+ return path8;
47379
47691
  } catch {
47380
47692
  return null;
47381
47693
  }
@@ -47383,15 +47695,15 @@ function stampTaskSentinel(projectRoot, taskId) {
47383
47695
  function cleanupTaskSentinel(sentinelPath) {
47384
47696
  if (!sentinelPath) return;
47385
47697
  try {
47386
- (0, import_fs74.unlinkSync)(sentinelPath);
47698
+ (0, import_fs75.unlinkSync)(sentinelPath);
47387
47699
  } catch {
47388
47700
  }
47389
47701
  }
47390
47702
  function lookupDispatchMetadata(projectRoot, taskId) {
47391
47703
  try {
47392
- const p = (0, import_path81.join)(projectRoot, ".gossip", METADATA_FILE);
47393
- if (!(0, import_fs74.existsSync)(p)) return null;
47394
- const raw = (0, import_fs74.readFileSync)(p, "utf-8");
47704
+ const p = (0, import_path82.join)(projectRoot, ".gossip", METADATA_FILE);
47705
+ if (!(0, import_fs75.existsSync)(p)) return null;
47706
+ const raw = (0, import_fs75.readFileSync)(p, "utf-8");
47395
47707
  const lines = raw.split("\n").filter(Boolean);
47396
47708
  for (let i = lines.length - 1; i >= 0; i--) {
47397
47709
  try {
@@ -47423,21 +47735,21 @@ function parseGitStatus(porcelain) {
47423
47735
  function normalizeScope(scope, projectRoot) {
47424
47736
  let s = scope.trim();
47425
47737
  if (!s) return "";
47426
- if ((0, import_path81.isAbsolute)(s)) {
47427
- s = (0, import_path81.relative)(projectRoot, s);
47738
+ if ((0, import_path82.isAbsolute)(s)) {
47739
+ s = (0, import_path82.relative)(projectRoot, s);
47428
47740
  } else if (s.startsWith("./")) {
47429
47741
  s = s.slice(2);
47430
47742
  }
47431
- s = (0, import_path81.normalize)(s).replace(/\/+$/, "");
47743
+ s = (0, import_path82.normalize)(s).replace(/\/+$/, "");
47432
47744
  if (s === "." || s === "") return "";
47433
47745
  return s;
47434
47746
  }
47435
47747
  function isInsideScope(filePath, scope) {
47436
47748
  if (!scope) return true;
47437
- const f = (0, import_path81.normalize)(filePath).replace(/^\.\//, "");
47749
+ const f = (0, import_path82.normalize)(filePath).replace(/^\.\//, "");
47438
47750
  const s = scope.replace(/^\.\//, "").replace(/\/+$/, "");
47439
47751
  if (f === s) return true;
47440
- return f.startsWith(s + "/") || f.startsWith(s + import_path81.sep);
47752
+ return f.startsWith(s + "/") || f.startsWith(s + import_path82.sep);
47441
47753
  }
47442
47754
  function detectBoundaryEscapes(meta3, modifiedFiles, projectRoot) {
47443
47755
  const mode = meta3.writeMode;
@@ -47498,8 +47810,8 @@ function recordBoundaryEscape(projectRoot, meta3, violations, mode) {
47498
47810
  } catch {
47499
47811
  }
47500
47812
  try {
47501
- const dir = (0, import_path81.join)(projectRoot, ".gossip");
47502
- (0, import_fs74.mkdirSync)(dir, { recursive: true });
47813
+ const dir = (0, import_path82.join)(projectRoot, ".gossip");
47814
+ (0, import_fs75.mkdirSync)(dir, { recursive: true });
47503
47815
  const line = {
47504
47816
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
47505
47817
  taskId: meta3.taskId,
@@ -47510,15 +47822,15 @@ function recordBoundaryEscape(projectRoot, meta3, violations, mode) {
47510
47822
  action: mode
47511
47823
  // "warn" or "block"
47512
47824
  };
47513
- const escapeFile = (0, import_path81.join)(dir, BOUNDARY_ESCAPE_FILE);
47825
+ const escapeFile = (0, import_path82.join)(dir, BOUNDARY_ESCAPE_FILE);
47514
47826
  rotateIfNeeded2(escapeFile, MAX_BOUNDARY_ESCAPE_BYTES);
47515
- (0, import_fs74.appendFileSync)(escapeFile, JSON.stringify(line) + "\n");
47827
+ (0, import_fs75.appendFileSync)(escapeFile, JSON.stringify(line) + "\n");
47516
47828
  } catch {
47517
47829
  }
47518
47830
  }
47519
47831
  function canonicalize(p) {
47520
47832
  try {
47521
- return (0, import_path81.resolve)(p).replace(/\/+$/, "") || "/";
47833
+ return (0, import_path82.resolve)(p).replace(/\/+$/, "") || "/";
47522
47834
  } catch {
47523
47835
  return p.replace(/\/+$/, "") || "/";
47524
47836
  }
@@ -47544,8 +47856,8 @@ function defaultScanRoots(writeMode, projectRoot) {
47544
47856
  out.add("/private/tmp");
47545
47857
  return Array.from(out);
47546
47858
  }
47547
- function expandTmpVariants(path7) {
47548
- const p = path7.replace(/\/+$/, "") || "/";
47859
+ function expandTmpVariants(path8) {
47860
+ const p = path8.replace(/\/+$/, "") || "/";
47549
47861
  for (const root of ["/tmp", "/etc", "/var"]) {
47550
47862
  if (p === root || p.startsWith(root + "/")) {
47551
47863
  return [p, "/private" + p];
@@ -47629,7 +47941,7 @@ function buildAuditExclusions(projectRoot, ownWorktree, scope) {
47629
47941
  for (const v of expandTmpVariants(wt)) excl.add(v);
47630
47942
  }
47631
47943
  if (scope) {
47632
- const s = canonicalize((0, import_path81.join)(projectRoot, scope));
47944
+ const s = canonicalize((0, import_path82.join)(projectRoot, scope));
47633
47945
  for (const v of expandTmpVariants(s)) excl.add(v);
47634
47946
  }
47635
47947
  return Array.from(excl);
@@ -47718,12 +48030,12 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
47718
48030
  return { violations: [], skipped: "win32" };
47719
48031
  }
47720
48032
  const sentinel = meta3.sentinelPath;
47721
- if (!sentinel || !(0, import_fs74.existsSync)(sentinel)) {
48033
+ if (!sentinel || !(0, import_fs75.existsSync)(sentinel)) {
47722
48034
  return { violations: [], skipped: "sentinel missing" };
47723
48035
  }
47724
48036
  let sentinelMtimeMs = 0;
47725
48037
  try {
47726
- sentinelMtimeMs = (0, import_fs74.statSync)(sentinel).mtimeMs;
48038
+ sentinelMtimeMs = (0, import_fs75.statSync)(sentinel).mtimeMs;
47727
48039
  } catch {
47728
48040
  }
47729
48041
  if (sentinelMtimeMs === 0) {
@@ -47735,11 +48047,11 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
47735
48047
  );
47736
48048
  const exclusions = buildAuditExclusions(projectRoot, meta3.worktreePath, options.scope);
47737
48049
  const findBin = options.findBinary ?? "find";
47738
- const sentinelDir = canonicalize((0, import_path81.join)(projectRoot, ".gossip", SENTINEL_DIR));
48050
+ const sentinelDir = canonicalize((0, import_path82.join)(projectRoot, ".gossip", SENTINEL_DIR));
47739
48051
  const mainSet = /* @__PURE__ */ new Set();
47740
48052
  const sensitiveSet = /* @__PURE__ */ new Set();
47741
48053
  for (const root of scanRoots) {
47742
- if (!(0, import_fs74.existsSync)(root)) continue;
48054
+ if (!(0, import_fs75.existsSync)(root)) continue;
47743
48055
  const canonRoot = canonicalize(root);
47744
48056
  const allExcl = [...exclusions, ...expandTmpVariants(sentinelDir)];
47745
48057
  const args = buildFindPruneArgs(canonRoot, allExcl, sentinel);
@@ -47775,7 +48087,7 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
47775
48087
  }
47776
48088
  const sensitiveTargets = buildSensitiveTargets(platform2);
47777
48089
  for (const target of sensitiveTargets) {
47778
- if (!(0, import_fs74.existsSync)(target.path)) continue;
48090
+ if (!(0, import_fs75.existsSync)(target.path)) continue;
47779
48091
  const canonTarget = canonicalize(target.path);
47780
48092
  const args = buildSensitiveFindArgs(
47781
48093
  canonTarget,
@@ -47849,21 +48161,21 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
47849
48161
  }
47850
48162
  function recordLayer3Violations(projectRoot, meta3, violations, source) {
47851
48163
  try {
47852
- const dir = (0, import_path81.join)(projectRoot, ".gossip");
47853
- (0, import_fs74.mkdirSync)(dir, { recursive: true });
48164
+ const dir = (0, import_path82.join)(projectRoot, ".gossip");
48165
+ (0, import_fs75.mkdirSync)(dir, { recursive: true });
47854
48166
  const ts2 = (/* @__PURE__ */ new Date()).toISOString();
47855
48167
  const lines = violations.map(
47856
- (path7) => JSON.stringify({
48168
+ (path8) => JSON.stringify({
47857
48169
  timestamp: ts2,
47858
48170
  taskId: meta3.taskId,
47859
48171
  agentId: meta3.agentId,
47860
- violatingPaths: [path7],
48172
+ violatingPaths: [path8],
47861
48173
  source
47862
48174
  })
47863
48175
  );
47864
- const escapeFile = (0, import_path81.join)(dir, BOUNDARY_ESCAPE_FILE);
48176
+ const escapeFile = (0, import_path82.join)(dir, BOUNDARY_ESCAPE_FILE);
47865
48177
  rotateIfNeeded2(escapeFile, MAX_BOUNDARY_ESCAPE_BYTES);
47866
- (0, import_fs74.appendFileSync)(escapeFile, lines.join("\n") + "\n");
48178
+ (0, import_fs75.appendFileSync)(escapeFile, lines.join("\n") + "\n");
47867
48179
  } catch {
47868
48180
  }
47869
48181
  if (source === "layer3-sensitive" && violations.length > 0) {
@@ -47920,14 +48232,14 @@ function runLayer3Audit(projectRoot, taskId) {
47920
48232
  }
47921
48233
  return { blockError, warnPrefix };
47922
48234
  }
47923
- var import_child_process12, import_fs74, import_os5, import_path81, METADATA_FILE, BOUNDARY_ESCAPE_FILE, SENTINEL_DIR, MAX_BOUNDARY_ESCAPE_BYTES, MAX_PREMISE_VERIFICATION_BYTES, BOUNDARY_ALLOWLIST, SYSTEM_PREFIXES, SCOPE_NOTE, NUMERAL, TARGETS, MODIFIER, CLAIM_PATTERNS, UNVERIFIED_NOTE_SENTINEL, LAYER3_KEEP_TMPDIR_PREFIXES, __test__;
48235
+ var import_child_process12, import_fs75, import_os5, import_path82, METADATA_FILE, BOUNDARY_ESCAPE_FILE, SENTINEL_DIR, MAX_BOUNDARY_ESCAPE_BYTES, MAX_PREMISE_VERIFICATION_BYTES, BOUNDARY_ALLOWLIST, SYSTEM_PREFIXES, SCOPE_NOTE, NUMERAL, TARGETS, MODIFIER, CLAIM_PATTERNS, UNVERIFIED_NOTE_SENTINEL, LAYER3_KEEP_TMPDIR_PREFIXES, __test__;
47924
48236
  var init_sandbox2 = __esm({
47925
48237
  "apps/cli/src/sandbox.ts"() {
47926
48238
  "use strict";
47927
48239
  import_child_process12 = require("child_process");
47928
- import_fs74 = require("fs");
48240
+ import_fs75 = require("fs");
47929
48241
  import_os5 = require("os");
47930
- import_path81 = require("path");
48242
+ import_path82 = require("path");
47931
48243
  METADATA_FILE = "dispatch-metadata.jsonl";
47932
48244
  BOUNDARY_ESCAPE_FILE = "boundary-escapes.jsonl";
47933
48245
  SENTINEL_DIR = "sentinels";
@@ -47999,7 +48311,7 @@ __export(dispatch_prompt_storage_exports, {
47999
48311
  writeDispatchPrompt: () => writeDispatchPrompt
48000
48312
  });
48001
48313
  function dispatchPromptsDir(projectRoot) {
48002
- return (0, import_path82.join)(projectRoot, ".gossip", DISPATCH_PROMPTS_SUBDIR);
48314
+ return (0, import_path83.join)(projectRoot, ".gossip", DISPATCH_PROMPTS_SUBDIR);
48003
48315
  }
48004
48316
  function assertSafeTaskId(taskId) {
48005
48317
  if (typeof taskId !== "string" || taskId.length === 0) {
@@ -48012,35 +48324,35 @@ function assertSafeTaskId(taskId) {
48012
48324
  function writeDispatchPrompt(projectRoot, taskId, body) {
48013
48325
  assertSafeTaskId(taskId);
48014
48326
  const dir = dispatchPromptsDir(projectRoot);
48015
- (0, import_fs75.mkdirSync)(dir, { recursive: true });
48016
- const finalPath = (0, import_path82.join)(dir, `${taskId}.txt`);
48017
- const tmpPath = (0, import_path82.join)(dir, `${taskId}.txt.${(0, import_crypto30.randomUUID)().slice(0, 8)}.tmp`);
48327
+ (0, import_fs76.mkdirSync)(dir, { recursive: true });
48328
+ const finalPath = (0, import_path83.join)(dir, `${taskId}.txt`);
48329
+ const tmpPath = (0, import_path83.join)(dir, `${taskId}.txt.${(0, import_crypto30.randomUUID)().slice(0, 8)}.tmp`);
48018
48330
  try {
48019
- (0, import_fs75.writeFileSync)(tmpPath, body, "utf8");
48020
- (0, import_fs75.renameSync)(tmpPath, finalPath);
48331
+ (0, import_fs76.writeFileSync)(tmpPath, body, "utf8");
48332
+ (0, import_fs76.renameSync)(tmpPath, finalPath);
48021
48333
  } catch (err) {
48022
48334
  try {
48023
- (0, import_fs75.unlinkSync)(tmpPath);
48335
+ (0, import_fs76.unlinkSync)(tmpPath);
48024
48336
  } catch {
48025
48337
  }
48026
48338
  throw err;
48027
48339
  }
48028
- return (0, import_path82.resolve)(finalPath);
48340
+ return (0, import_path83.resolve)(finalPath);
48029
48341
  }
48030
48342
  function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TTL_MS, capBytes = DISPATCH_PROMPT_CAP_BYTES) {
48031
48343
  const dir = dispatchPromptsDir(projectRoot);
48032
- if (!(0, import_fs75.existsSync)(dir)) return { evictedAge: 0, evictedCap: 0 };
48344
+ if (!(0, import_fs76.existsSync)(dir)) return { evictedAge: 0, evictedCap: 0 };
48033
48345
  const now = Date.now();
48034
48346
  let entries = [];
48035
48347
  try {
48036
- for (const name of (0, import_fs75.readdirSync)(dir)) {
48037
- const path7 = (0, import_path82.join)(dir, name);
48348
+ for (const name of (0, import_fs76.readdirSync)(dir)) {
48349
+ const path8 = (0, import_path83.join)(dir, name);
48038
48350
  try {
48039
- const st = (0, import_fs75.statSync)(path7);
48351
+ const st = (0, import_fs76.statSync)(path8);
48040
48352
  if (!st.isFile()) continue;
48041
- entries.push({ name, path: path7, mtimeMs: st.mtimeMs, size: st.size });
48353
+ entries.push({ name, path: path8, mtimeMs: st.mtimeMs, size: st.size });
48042
48354
  } catch (err) {
48043
- process.stderr.write(`[gossipcat] dispatch-prompt stat failed for ${(0, import_path82.basename)(path7)}: ${err.message}
48355
+ process.stderr.write(`[gossipcat] dispatch-prompt stat failed for ${(0, import_path83.basename)(path8)}: ${err.message}
48044
48356
  `);
48045
48357
  }
48046
48358
  }
@@ -48054,7 +48366,7 @@ function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TT
48054
48366
  for (const e of entries) {
48055
48367
  if (now - e.mtimeMs > maxAgeMs) {
48056
48368
  try {
48057
- (0, import_fs75.unlinkSync)(e.path);
48369
+ (0, import_fs76.unlinkSync)(e.path);
48058
48370
  evictedAge++;
48059
48371
  } catch (err) {
48060
48372
  process.stderr.write(`[gossipcat] dispatch-prompt unlink failed for ${e.name}: ${err.message}
@@ -48071,7 +48383,7 @@ function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TT
48071
48383
  for (const e of survivors) {
48072
48384
  if (totalBytes <= capBytes) break;
48073
48385
  try {
48074
- (0, import_fs75.unlinkSync)(e.path);
48386
+ (0, import_fs76.unlinkSync)(e.path);
48075
48387
  totalBytes -= e.size;
48076
48388
  evictedCap++;
48077
48389
  } catch (err) {
@@ -48084,18 +48396,18 @@ function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TT
48084
48396
  }
48085
48397
  function pruneOrphanDispatchPrompts(projectRoot, knownTaskIds, maxAgeMs = DEFAULT_PROMPT_TTL_MS) {
48086
48398
  const dir = dispatchPromptsDir(projectRoot);
48087
- if (!(0, import_fs75.existsSync)(dir)) return { orphans: 0, aged: 0 };
48399
+ if (!(0, import_fs76.existsSync)(dir)) return { orphans: 0, aged: 0 };
48088
48400
  const now = Date.now();
48089
48401
  let orphans = 0;
48090
48402
  let aged = 0;
48091
48403
  try {
48092
- for (const name of (0, import_fs75.readdirSync)(dir)) {
48404
+ for (const name of (0, import_fs76.readdirSync)(dir)) {
48093
48405
  if (!name.endsWith(".txt")) continue;
48094
48406
  const taskId = name.slice(0, -4);
48095
- const path7 = (0, import_path82.join)(dir, name);
48407
+ const path8 = (0, import_path83.join)(dir, name);
48096
48408
  let mtimeMs = 0;
48097
48409
  try {
48098
- mtimeMs = (0, import_fs75.statSync)(path7).mtimeMs;
48410
+ mtimeMs = (0, import_fs76.statSync)(path8).mtimeMs;
48099
48411
  } catch {
48100
48412
  continue;
48101
48413
  }
@@ -48103,7 +48415,7 @@ function pruneOrphanDispatchPrompts(projectRoot, knownTaskIds, maxAgeMs = DEFAUL
48103
48415
  const orphaned = !knownTaskIds.has(taskId);
48104
48416
  if (tooOld || orphaned) {
48105
48417
  try {
48106
- (0, import_fs75.unlinkSync)(path7);
48418
+ (0, import_fs76.unlinkSync)(path8);
48107
48419
  if (orphaned) orphans++;
48108
48420
  if (tooOld) aged++;
48109
48421
  } catch (err) {
@@ -48120,14 +48432,14 @@ function pruneOrphanDispatchPrompts(projectRoot, knownTaskIds, maxAgeMs = DEFAUL
48120
48432
  }
48121
48433
  function dispatchPromptPath(projectRoot, taskId) {
48122
48434
  assertSafeTaskId(taskId);
48123
- return (0, import_path82.resolve)((0, import_path82.join)(dispatchPromptsDir(projectRoot), `${taskId}.txt`));
48435
+ return (0, import_path83.resolve)((0, import_path83.join)(dispatchPromptsDir(projectRoot), `${taskId}.txt`));
48124
48436
  }
48125
- var import_fs75, import_path82, import_crypto30, SAFE_TASK_ID2, DISPATCH_PROMPT_CAP_BYTES, DEFAULT_PROMPT_TTL_MS, DISPATCH_PROMPTS_SUBDIR;
48437
+ var import_fs76, import_path83, import_crypto30, SAFE_TASK_ID2, DISPATCH_PROMPT_CAP_BYTES, DEFAULT_PROMPT_TTL_MS, DISPATCH_PROMPTS_SUBDIR;
48126
48438
  var init_dispatch_prompt_storage = __esm({
48127
48439
  "apps/cli/src/handlers/dispatch-prompt-storage.ts"() {
48128
48440
  "use strict";
48129
- import_fs75 = require("fs");
48130
- import_path82 = require("path");
48441
+ import_fs76 = require("fs");
48442
+ import_path83 = require("path");
48131
48443
  import_crypto30 = require("crypto");
48132
48444
  SAFE_TASK_ID2 = /^(?!.*\.\.)[A-Za-z0-9._-]{1,64}$/;
48133
48445
  DISPATCH_PROMPT_CAP_BYTES = 100 * 1024 * 1024;
@@ -48181,9 +48493,9 @@ function getCommitRange(preSha, postSha) {
48181
48493
  function appendViolationRecord(record2) {
48182
48494
  try {
48183
48495
  const projectRoot = process.cwd();
48184
- (0, import_fs76.mkdirSync)((0, import_path83.join)(projectRoot, ".gossip"), { recursive: true });
48185
- const logPath = (0, import_path83.join)(projectRoot, PROCESS_VIOLATIONS_FILE);
48186
- (0, import_fs76.appendFileSync)(logPath, JSON.stringify(record2) + "\n", "utf8");
48496
+ (0, import_fs77.mkdirSync)((0, import_path84.join)(projectRoot, ".gossip"), { recursive: true });
48497
+ const logPath = (0, import_path84.join)(projectRoot, PROCESS_VIOLATIONS_FILE);
48498
+ (0, import_fs77.appendFileSync)(logPath, JSON.stringify(record2) + "\n", "utf8");
48187
48499
  } catch (err) {
48188
48500
  process.stderr.write(`[gossipcat] ref-allowlist: failed to append violation record: ${err.message}
48189
48501
  `);
@@ -48233,17 +48545,289 @@ Full audit trail at .gossip/process-violations.jsonl
48233
48545
  `
48234
48546
  );
48235
48547
  }
48236
- var import_fs76, import_path83, import_child_process13, PROCESS_VIOLATIONS_FILE;
48548
+ var import_fs77, import_path84, import_child_process13, PROCESS_VIOLATIONS_FILE;
48237
48549
  var init_ref_allowlist_detection = __esm({
48238
48550
  "apps/cli/src/handlers/ref-allowlist-detection.ts"() {
48239
48551
  "use strict";
48240
- import_fs76 = require("fs");
48241
- import_path83 = require("path");
48552
+ import_fs77 = require("fs");
48553
+ import_path84 = require("path");
48242
48554
  import_child_process13 = require("child_process");
48243
48555
  PROCESS_VIOLATIONS_FILE = ".gossip/process-violations.jsonl";
48244
48556
  }
48245
48557
  });
48246
48558
 
48559
+ // apps/cli/src/handlers/orchestrator-precondition-runner.ts
48560
+ function captureHeadSha(projectRoot, execFile6 = defaultExecFile) {
48561
+ try {
48562
+ const cwd = projectRoot || process.cwd();
48563
+ const sha = execFile6("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" }).trim();
48564
+ return sha || void 0;
48565
+ } catch {
48566
+ return void 0;
48567
+ }
48568
+ }
48569
+ function getCommitsSince(sinceSha, projectRoot, execFile6 = defaultExecFile) {
48570
+ try {
48571
+ const output = execFile6("git", ["log", `${sinceSha}..HEAD`, "--format=%H"], {
48572
+ cwd: projectRoot,
48573
+ encoding: "utf8"
48574
+ });
48575
+ return output.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
48576
+ } catch {
48577
+ return [];
48578
+ }
48579
+ }
48580
+ async function runMidFlightCheck(input, deps = {}) {
48581
+ const warnings = [];
48582
+ if (!input.roundStartSha) {
48583
+ return { warnings };
48584
+ }
48585
+ const execFile6 = deps.execFile ?? defaultExecFile;
48586
+ const emitSignals = deps.emitSignals ?? defaultEmitSignals;
48587
+ try {
48588
+ const { projectRoot, consensusId, roundStartSha } = input;
48589
+ const commits = getCommitsSince(roundStartSha, projectRoot, execFile6);
48590
+ const { detected, count } = detectMidFlightCommits(commits);
48591
+ if (!detected) {
48592
+ return { warnings };
48593
+ }
48594
+ warnings.push(
48595
+ `[mid-flight-fixup] ${count} commit(s) landed during Phase 2 cross-review (since ${roundStartSha.slice(0, 8)}). Reviewers may have seen post-fix code and marked legitimate Phase 1 findings DISAGREE. Consensus round: ${consensusId}.`
48596
+ );
48597
+ try {
48598
+ emitSignals(projectRoot, [{
48599
+ type: "pipeline",
48600
+ signal: "mid_flight_fixup",
48601
+ agentId: "orchestrator",
48602
+ taskId: consensusId,
48603
+ consensusId,
48604
+ metadata: {
48605
+ count,
48606
+ roundStartSha,
48607
+ commits
48608
+ },
48609
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
48610
+ }]);
48611
+ } catch {
48612
+ }
48613
+ } catch {
48614
+ }
48615
+ return { warnings };
48616
+ }
48617
+ function defaultExecFile(cmd, args, opts) {
48618
+ return (0, import_child_process14.execFileSync)(cmd, args, opts);
48619
+ }
48620
+ function defaultCanRead(p) {
48621
+ try {
48622
+ fs6.accessSync(p, fs6.constants.R_OK);
48623
+ return true;
48624
+ } catch {
48625
+ return false;
48626
+ }
48627
+ }
48628
+ function defaultPathExists(projectRoot, p) {
48629
+ try {
48630
+ const resolved = path7.resolve(projectRoot, p);
48631
+ fs6.accessSync(resolved, fs6.constants.R_OK);
48632
+ return true;
48633
+ } catch {
48634
+ return false;
48635
+ }
48636
+ }
48637
+ function defaultIsGitignoredOrUntracked(projectRoot, p, execFile6) {
48638
+ try {
48639
+ execFile6("git", ["check-ignore", "-q", p], { cwd: projectRoot, encoding: "utf8" });
48640
+ return true;
48641
+ } catch {
48642
+ }
48643
+ try {
48644
+ execFile6("git", ["ls-files", "--error-unmatch", p], { cwd: projectRoot, encoding: "utf8" });
48645
+ return false;
48646
+ } catch {
48647
+ return true;
48648
+ }
48649
+ }
48650
+ function defaultEmitSignals(projectRoot, signals) {
48651
+ try {
48652
+ emitPipelineSignals(projectRoot, signals);
48653
+ } catch {
48654
+ }
48655
+ }
48656
+ async function gatherStaleBaseInputs(projectRoot, execFile6 = defaultExecFile) {
48657
+ try {
48658
+ const dispatchSha = execFile6("git", ["rev-parse", "HEAD"], {
48659
+ cwd: projectRoot,
48660
+ encoding: "utf8"
48661
+ }).trim();
48662
+ const originMasterSha = execFile6("git", ["rev-parse", "origin/master"], {
48663
+ cwd: projectRoot,
48664
+ encoding: "utf8"
48665
+ }).trim();
48666
+ const mergeBaseSha = execFile6("git", ["merge-base", "HEAD", "origin/master"], {
48667
+ cwd: projectRoot,
48668
+ encoding: "utf8"
48669
+ }).trim();
48670
+ return { dispatchSha, originMasterSha, mergeBaseSha };
48671
+ } catch {
48672
+ return null;
48673
+ }
48674
+ }
48675
+ async function runDispatchPreconditionGuard(input, deps = {}) {
48676
+ const warnings = [];
48677
+ const execFile6 = deps.execFile ?? defaultExecFile;
48678
+ const canRead = deps.canRead ?? defaultCanRead;
48679
+ const pathExists = deps.pathExists ?? defaultPathExists;
48680
+ const isGitignoredOrUntracked = deps.isGitignoredOrUntracked ?? defaultIsGitignoredOrUntracked;
48681
+ const emitSignals = deps.emitSignals ?? defaultEmitSignals;
48682
+ const { projectRoot, taskId, resolutionRoots, taskText, writeMode, additionalTasks } = input;
48683
+ try {
48684
+ const gitInputs = await gatherStaleBaseInputs(projectRoot, execFile6);
48685
+ if (gitInputs !== null) {
48686
+ const staleResult = detectStaleBase(
48687
+ gitInputs.dispatchSha,
48688
+ gitInputs.originMasterSha,
48689
+ gitInputs.mergeBaseSha
48690
+ );
48691
+ if (staleResult.stale && staleResult.reason !== null) {
48692
+ const reason = staleResult.reason;
48693
+ warnings.push(
48694
+ `[dispatch-hygiene] stale base detected (${reason}): dispatch SHA ${gitInputs.dispatchSha} is behind origin/master ${gitInputs.originMasterSha}. Pull and rebase before dispatching.`
48695
+ );
48696
+ try {
48697
+ emitSignals(projectRoot, [{
48698
+ type: "pipeline",
48699
+ signal: "dispatched_stale_base",
48700
+ agentId: "orchestrator",
48701
+ taskId,
48702
+ metadata: {
48703
+ reason,
48704
+ dispatchSha: gitInputs.dispatchSha
48705
+ },
48706
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
48707
+ }]);
48708
+ } catch {
48709
+ }
48710
+ }
48711
+ }
48712
+ const roots = resolutionRoots ?? [];
48713
+ if (roots.length > 0) {
48714
+ let unreadable;
48715
+ try {
48716
+ unreadable = findUnreadablePaths(roots, canRead);
48717
+ } catch {
48718
+ unreadable = [];
48719
+ }
48720
+ if (unreadable.length > 0) {
48721
+ warnings.push(
48722
+ `[dispatch-hygiene] ${unreadable.length} resolutionRoot(s) are unreadable: ${unreadable.join(", ")}. Cross-reviewers will fall back to project root.`
48723
+ );
48724
+ try {
48725
+ emitSignals(projectRoot, [{
48726
+ type: "pipeline",
48727
+ signal: "referenced_unreadable_path",
48728
+ agentId: "orchestrator",
48729
+ taskId,
48730
+ metadata: {
48731
+ unreadable
48732
+ },
48733
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
48734
+ }]);
48735
+ } catch {
48736
+ }
48737
+ }
48738
+ }
48739
+ const scanTasks = [];
48740
+ if (taskText) {
48741
+ scanTasks.push({ taskText, writeMode });
48742
+ }
48743
+ if (additionalTasks) {
48744
+ for (const t of additionalTasks) {
48745
+ if (t && t.taskText) {
48746
+ scanTasks.push({ taskText: t.taskText, writeMode: t.writeMode });
48747
+ }
48748
+ }
48749
+ }
48750
+ if (scanTasks.length > 0) {
48751
+ const byPath = /* @__PURE__ */ new Map();
48752
+ let droppedOverCap = 0;
48753
+ for (const t of scanTasks) {
48754
+ let result = {
48755
+ unreadable: [],
48756
+ droppedOverCap: 0
48757
+ };
48758
+ try {
48759
+ result = findUnreadableReferencedPathsWithMeta(t.taskText, {
48760
+ writeMode: t.writeMode,
48761
+ pathExists: (p) => {
48762
+ try {
48763
+ return pathExists(projectRoot, p);
48764
+ } catch {
48765
+ return true;
48766
+ }
48767
+ },
48768
+ isGitignoredOrUntracked: (p) => {
48769
+ try {
48770
+ return isGitignoredOrUntracked(projectRoot, p, execFile6);
48771
+ } catch {
48772
+ return false;
48773
+ }
48774
+ }
48775
+ });
48776
+ } catch {
48777
+ result = { unreadable: [], droppedOverCap: 0 };
48778
+ }
48779
+ droppedOverCap += result.droppedOverCap;
48780
+ for (const entry of result.unreadable) {
48781
+ const existing = byPath.get(entry.path);
48782
+ if (!existing) {
48783
+ byPath.set(entry.path, entry);
48784
+ } else if (existing.reason !== "gitignored_in_worktree" && entry.reason === "gitignored_in_worktree") {
48785
+ byPath.set(entry.path, entry);
48786
+ }
48787
+ }
48788
+ }
48789
+ const referenced = [...byPath.values()];
48790
+ if (referenced.length > 0) {
48791
+ const detail = referenced.map((r) => `${r.path} (${r.reason})`).join(", ");
48792
+ warnings.push(
48793
+ `[dispatch-hygiene] ${referenced.length} referenced path(s) the dispatched agent cannot read: ${detail}. The agent may fail mid-task \u2014 inline the file contents or copy it into the worktree.`
48794
+ );
48795
+ try {
48796
+ emitSignals(projectRoot, [{
48797
+ type: "pipeline",
48798
+ signal: "referenced_unreadable_path",
48799
+ agentId: "orchestrator",
48800
+ taskId,
48801
+ metadata: {
48802
+ referenced
48803
+ },
48804
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
48805
+ }]);
48806
+ } catch {
48807
+ }
48808
+ }
48809
+ if (droppedOverCap > 0) {
48810
+ warnings.push(
48811
+ `[dispatch-hygiene] ${droppedOverCap} referenced path(s) beyond the 20-path cap were not checked.`
48812
+ );
48813
+ }
48814
+ }
48815
+ } catch {
48816
+ }
48817
+ return { warnings };
48818
+ }
48819
+ var fs6, path7, import_child_process14;
48820
+ var init_orchestrator_precondition_runner = __esm({
48821
+ "apps/cli/src/handlers/orchestrator-precondition-runner.ts"() {
48822
+ "use strict";
48823
+ fs6 = __toESM(require("fs"));
48824
+ path7 = __toESM(require("path"));
48825
+ import_child_process14 = require("child_process");
48826
+ init_src4();
48827
+ init_src4();
48828
+ }
48829
+ });
48830
+
48247
48831
  // apps/cli/src/handlers/relay-cross-review.ts
48248
48832
  var relay_cross_review_exports = {};
48249
48833
  __export(relay_cross_review_exports, {
@@ -48274,11 +48858,11 @@ async function synthesizeTimeoutRound(snapshot, consensusId, missingAgents, llm,
48274
48858
  );
48275
48859
  try {
48276
48860
  const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45 } = require("fs");
48277
- const { join: join91 } = require("path");
48278
- const reportsDir = join91(projectRoot, ".gossip", "consensus-reports");
48861
+ const { join: join93 } = require("path");
48862
+ const reportsDir = join93(projectRoot, ".gossip", "consensus-reports");
48279
48863
  mkdirSync45(reportsDir, { recursive: true });
48280
48864
  const topic = snapshot.allResults?.find((r) => r.task)?.task?.slice(0, 500) || "";
48281
- writeFileSync38(join91(reportsDir, `${consensusId}.json`), JSON.stringify({
48865
+ writeFileSync38(join93(reportsDir, `${consensusId}.json`), JSON.stringify({
48282
48866
  id: consensusId,
48283
48867
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
48284
48868
  topic,
@@ -48313,6 +48897,7 @@ function startConsensusTimeout(consensusId) {
48313
48897
  return;
48314
48898
  }
48315
48899
  const missingAgents = [...current.pendingNativeAgents];
48900
+ const roundStartShaForMidFlight = current.roundStartSha;
48316
48901
  const snapshot = { allResults: current.allResults, relayCrossReviewEntries: current.relayCrossReviewEntries, relayCrossReviewSkipped: current.relayCrossReviewSkipped, nativeCrossReviewEntries: [...current.nativeCrossReviewEntries], resolutionRoots: current.resolutionRoots, roundContext: current.roundContext };
48317
48902
  seedRecentConsensusAgentIds(Array.from(current.participatingNativeAgents), RECENT_CONSENSUS_TASK_TTL_MS);
48318
48903
  ctx.pendingConsensusRounds.delete(consensusId);
@@ -48342,6 +48927,18 @@ function startConsensusTimeout(consensusId) {
48342
48927
  const { report } = await synthesizeTimeoutRound(snapshot, consensusId, missingAgents, timeoutLlm);
48343
48928
  process.stderr.write(`[gossipcat] \u{1F52E} Timeout synthesis complete: ${report.confirmed.length} confirmed, ${report.disputed.length} disputed
48344
48929
  `);
48930
+ try {
48931
+ const midFlightResult = await runMidFlightCheck({
48932
+ projectRoot: process.cwd(),
48933
+ consensusId,
48934
+ roundStartSha: roundStartShaForMidFlight
48935
+ });
48936
+ for (const warn of midFlightResult.warnings) {
48937
+ process.stderr.write(`[gossipcat] ${warn}
48938
+ `);
48939
+ }
48940
+ } catch {
48941
+ }
48345
48942
  } catch (err) {
48346
48943
  process.stderr.write(`[gossipcat] \u274C Timeout synthesis failed: ${err.message}
48347
48944
  `);
@@ -48452,6 +49049,7 @@ async function handleRelayCrossReview(consensus_id, agent_id, result) {
48452
49049
  }]
48453
49050
  };
48454
49051
  }
49052
+ const completionRoundStartSha = round.roundStartSha;
48455
49053
  const synthSnapshot = {
48456
49054
  allResults: round.allResults,
48457
49055
  relayCrossReviewEntries: round.relayCrossReviewEntries,
@@ -48497,10 +49095,10 @@ async function handleRelayCrossReview(consensus_id, agent_id, result) {
48497
49095
  );
48498
49096
  try {
48499
49097
  const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45 } = require("fs");
48500
- const { join: join91 } = require("path");
48501
- const reportsDir = join91(process.cwd(), ".gossip", "consensus-reports");
49098
+ const { join: join93 } = require("path");
49099
+ const reportsDir = join93(process.cwd(), ".gossip", "consensus-reports");
48502
49100
  mkdirSync45(reportsDir, { recursive: true });
48503
- const reportPath = join91(reportsDir, `${consensus_id}.json`);
49101
+ const reportPath = join93(reportsDir, `${consensus_id}.json`);
48504
49102
  const topic = synthSnapshot.allResults?.find((r) => r.task)?.task?.slice(0, 500) || "";
48505
49103
  writeFileSync38(reportPath, JSON.stringify({
48506
49104
  id: consensus_id,
@@ -48527,6 +49125,18 @@ async function handleRelayCrossReview(consensus_id, agent_id, result) {
48527
49125
  }
48528
49126
  } catch {
48529
49127
  }
49128
+ try {
49129
+ const midFlightResult = await runMidFlightCheck({
49130
+ projectRoot: process.cwd(),
49131
+ consensusId: synthSnapshot.consensusId,
49132
+ roundStartSha: completionRoundStartSha
49133
+ });
49134
+ for (const warn of midFlightResult.warnings) {
49135
+ process.stderr.write(`[gossipcat] ${warn}
49136
+ `);
49137
+ }
49138
+ } catch {
49139
+ }
48530
49140
  return {
48531
49141
  content: [{
48532
49142
  type: "text",
@@ -48600,8 +49210,8 @@ function persistPendingConsensus() {
48600
49210
  const projectRoot = ctx.mainAgent?.projectRoot;
48601
49211
  if (!projectRoot) return;
48602
49212
  const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45 } = require("fs");
48603
- const { join: join91 } = require("path");
48604
- const dir = join91(projectRoot, ".gossip");
49213
+ const { join: join93 } = require("path");
49214
+ const dir = join93(projectRoot, ".gossip");
48605
49215
  mkdirSync45(dir, { recursive: true });
48606
49216
  const rounds = {};
48607
49217
  for (const [id, round] of ctx.pendingConsensusRounds) {
@@ -48636,7 +49246,7 @@ function persistPendingConsensus() {
48636
49246
  } : void 0
48637
49247
  };
48638
49248
  }
48639
- writeFileSync38(join91(dir, CONSENSUS_FILE), JSON.stringify(rounds));
49249
+ writeFileSync38(join93(dir, CONSENSUS_FILE), JSON.stringify(rounds));
48640
49250
  } catch (err) {
48641
49251
  process.stderr.write(`[gossipcat] persistPendingConsensus failed: ${err.message}
48642
49252
  `);
@@ -48644,11 +49254,11 @@ function persistPendingConsensus() {
48644
49254
  }
48645
49255
  function restorePendingConsensus(projectRoot) {
48646
49256
  try {
48647
- const { existsSync: existsSync73, readFileSync: readFileSync69, unlinkSync: unlinkSync16 } = require("fs");
48648
- const { join: join91 } = require("path");
48649
- const filePath = join91(projectRoot, ".gossip", CONSENSUS_FILE);
48650
- if (!existsSync73(filePath)) return;
48651
- const raw = JSON.parse(readFileSync69(filePath, "utf-8"));
49257
+ const { existsSync: existsSync74, readFileSync: readFileSync70, unlinkSync: unlinkSync16 } = require("fs");
49258
+ const { join: join93 } = require("path");
49259
+ const filePath = join93(projectRoot, ".gossip", CONSENSUS_FILE);
49260
+ if (!existsSync74(filePath)) return;
49261
+ const raw = JSON.parse(readFileSync70(filePath, "utf-8"));
48652
49262
  const now = Date.now();
48653
49263
  for (const [id, data] of Object.entries(raw)) {
48654
49264
  if (now > data.deadline + 3e5) {
@@ -48674,6 +49284,8 @@ function restorePendingConsensus(projectRoot) {
48674
49284
  createdAt: data.createdAt,
48675
49285
  nativePrompts: data.nativePrompts || [],
48676
49286
  resolutionRoots: Array.isArray(data.resolutionRoots) && data.resolutionRoots.length > 0 ? data.resolutionRoots : void 0,
49287
+ // UNIT 3: restore roundStartSha from persisted data (back-compat: undefined for old rounds).
49288
+ roundStartSha: typeof data.roundStartSha === "string" ? data.roundStartSha : void 0,
48677
49289
  // Spec §3.2 disk back-compat: prefer the embedded roundContext; fall
48678
49290
  // back per-field to the old flat shape (mirrors the
48679
49291
  // participatingNativeAgents back-compat pattern above). Old pre-PR-A
@@ -48695,6 +49307,7 @@ var init_relay_cross_review = __esm({
48695
49307
  "use strict";
48696
49308
  init_mcp_context();
48697
49309
  init_native_tasks();
49310
+ init_orchestrator_precondition_runner();
48698
49311
  CONSENSUS_FILE = "pending-consensus.json";
48699
49312
  }
48700
49313
  });
@@ -48779,10 +49392,10 @@ function taskWasInConsensusRound(taskId, agentId, rounds, recentTaskIds, recentA
48779
49392
  function appendRelayWarning(projectRoot, entry) {
48780
49393
  try {
48781
49394
  const { appendFileSync: appendFileSync22, mkdirSync: mkdirSync45 } = require("fs");
48782
- const { join: join91 } = require("path");
48783
- const dir = join91(projectRoot, ".gossip");
49395
+ const { join: join93 } = require("path");
49396
+ const dir = join93(projectRoot, ".gossip");
48784
49397
  mkdirSync45(dir, { recursive: true });
48785
- appendFileSync22(join91(dir, RELAY_WARNINGS_FILE), JSON.stringify(entry) + "\n", "utf8");
49398
+ appendFileSync22(join93(dir, RELAY_WARNINGS_FILE), JSON.stringify(entry) + "\n", "utf8");
48786
49399
  } catch (err) {
48787
49400
  process.stderr.write(`[gossipcat] append relay-warning failed: ${err.message}
48788
49401
  `);
@@ -48791,8 +49404,8 @@ function appendRelayWarning(projectRoot, entry) {
48791
49404
  function checkWorktreeEngaged(startedAt, projectRoot = process.cwd()) {
48792
49405
  try {
48793
49406
  const { readdirSync: readdirSync22, statSync: statSync36 } = require("fs");
48794
- const { join: join91 } = require("path");
48795
- const wtDir = join91(projectRoot, ".claude", "worktrees");
49407
+ const { join: join93 } = require("path");
49408
+ const wtDir = join93(projectRoot, ".claude", "worktrees");
48796
49409
  let entries;
48797
49410
  try {
48798
49411
  entries = readdirSync22(wtDir);
@@ -48803,7 +49416,7 @@ function checkWorktreeEngaged(startedAt, projectRoot = process.cwd()) {
48803
49416
  for (const entry of entries) {
48804
49417
  if (!entry.startsWith("agent-")) continue;
48805
49418
  try {
48806
- const st = statSync36(join91(wtDir, entry));
49419
+ const st = statSync36(join93(wtDir, entry));
48807
49420
  if (st.isDirectory() && st.mtimeMs >= startedAt - 2e3) return true;
48808
49421
  } catch {
48809
49422
  }
@@ -49684,7 +50297,7 @@ function computeSkillFingerprint(paths) {
49684
50297
  const pairs = [];
49685
50298
  for (const p of paths) {
49686
50299
  try {
49687
- const st = (0, import_fs77.statSync)(p);
50300
+ const st = (0, import_fs78.statSync)(p);
49688
50301
  pairs.push(`${p}:${st.mtimeMs}`);
49689
50302
  } catch {
49690
50303
  }
@@ -49719,7 +50332,7 @@ function setCachedPrompt(k, e) {
49719
50332
  const evicted = promptCache.get(oldestKey);
49720
50333
  promptCache.delete(oldestKey);
49721
50334
  try {
49722
- (0, import_fs77.unlinkSync)(evicted.skillsSectionPath);
50335
+ (0, import_fs78.unlinkSync)(evicted.skillsSectionPath);
49723
50336
  } catch {
49724
50337
  }
49725
50338
  const evictedAgentId = oldestKey.split("|")[0] ?? "_system";
@@ -49733,7 +50346,7 @@ function invalidateAgent(agentId) {
49733
50346
  if (k.startsWith(`${agentId}|`)) {
49734
50347
  promptCache.delete(k);
49735
50348
  try {
49736
- (0, import_fs77.unlinkSync)(v.skillsSectionPath);
50349
+ (0, import_fs78.unlinkSync)(v.skillsSectionPath);
49737
50350
  } catch {
49738
50351
  }
49739
50352
  emitCacheEvictedSignal(agentId, "invalidation");
@@ -49746,7 +50359,7 @@ function invalidateAll() {
49746
50359
  const n = promptCache.size;
49747
50360
  for (const v of promptCache.values()) {
49748
50361
  try {
49749
- (0, import_fs77.unlinkSync)(v.skillsSectionPath);
50362
+ (0, import_fs78.unlinkSync)(v.skillsSectionPath);
49750
50363
  } catch {
49751
50364
  }
49752
50365
  }
@@ -49793,29 +50406,29 @@ function writeCachedSkillsSection(projectRoot, fingerprint2, skillsSection) {
49793
50406
  if (!/^[a-f0-9]{64}$/.test(fingerprint2)) {
49794
50407
  throw new Error(`writeCachedSkillsSection: invalid fingerprint ${JSON.stringify(fingerprint2).slice(0, 32)}`);
49795
50408
  }
49796
- const dir = (0, import_path84.join)(projectRoot, ".gossip", "dispatch-prompts", "cache");
49797
- (0, import_fs77.mkdirSync)(dir, { recursive: true });
49798
- const finalPath = (0, import_path84.join)(dir, `skills-${fingerprint2}.txt`);
49799
- const tmpPath = (0, import_path84.join)(dir, `skills-${fingerprint2}.txt.${(0, import_crypto33.randomUUID)().slice(0, 8)}.tmp`);
50409
+ const dir = (0, import_path85.join)(projectRoot, ".gossip", "dispatch-prompts", "cache");
50410
+ (0, import_fs78.mkdirSync)(dir, { recursive: true });
50411
+ const finalPath = (0, import_path85.join)(dir, `skills-${fingerprint2}.txt`);
50412
+ const tmpPath = (0, import_path85.join)(dir, `skills-${fingerprint2}.txt.${(0, import_crypto33.randomUUID)().slice(0, 8)}.tmp`);
49800
50413
  try {
49801
- (0, import_fs77.writeFileSync)(tmpPath, skillsSection, "utf8");
49802
- (0, import_fs77.renameSync)(tmpPath, finalPath);
50414
+ (0, import_fs78.writeFileSync)(tmpPath, skillsSection, "utf8");
50415
+ (0, import_fs78.renameSync)(tmpPath, finalPath);
49803
50416
  } catch (err) {
49804
50417
  try {
49805
- (0, import_fs77.unlinkSync)(tmpPath);
50418
+ (0, import_fs78.unlinkSync)(tmpPath);
49806
50419
  } catch {
49807
50420
  }
49808
50421
  throw err;
49809
50422
  }
49810
- return (0, import_path84.resolve)(finalPath);
50423
+ return (0, import_path85.resolve)(finalPath);
49811
50424
  }
49812
- var import_crypto32, import_fs77, import_path84, import_crypto33, DISPATCH_PROMPT_CACHE_MAX_ENTRIES, promptCache;
50425
+ var import_crypto32, import_fs78, import_path85, import_crypto33, DISPATCH_PROMPT_CACHE_MAX_ENTRIES, promptCache;
49813
50426
  var init_dispatch_prompt_cache = __esm({
49814
50427
  "apps/cli/src/handlers/dispatch-prompt-cache.ts"() {
49815
50428
  "use strict";
49816
50429
  import_crypto32 = require("crypto");
49817
- import_fs77 = require("fs");
49818
- import_path84 = require("path");
50430
+ import_fs78 = require("fs");
50431
+ import_path85 = require("path");
49819
50432
  import_crypto33 = require("crypto");
49820
50433
  DISPATCH_PROMPT_CACHE_MAX_ENTRIES = 64;
49821
50434
  promptCache = /* @__PURE__ */ new Map();
@@ -49842,7 +50455,7 @@ function drainLifecycleTasks(maxMs = 8e3) {
49842
50455
  const snapshot = [...inFlight];
49843
50456
  return Promise.race([
49844
50457
  Promise.allSettled(snapshot).then(() => void 0),
49845
- new Promise((resolve32) => setTimeout(resolve32, maxMs).unref?.())
50458
+ new Promise((resolve33) => setTimeout(resolve33, maxMs).unref?.())
49846
50459
  ]).then(() => void 0);
49847
50460
  }
49848
50461
  function installLifecycleDrainHandlers() {
@@ -49885,31 +50498,31 @@ __export(check_effectiveness_runner_exports, {
49885
50498
  runCheckEffectivenessForAllSkills: () => runCheckEffectivenessForAllSkills
49886
50499
  });
49887
50500
  function writeHealthAtomic(projectRoot, record2) {
49888
- const dir = (0, import_path86.join)(projectRoot, ".gossip");
49889
- const finalPath = (0, import_path86.join)(dir, "skill-runner-health.json");
50501
+ const dir = (0, import_path88.join)(projectRoot, ".gossip");
50502
+ const finalPath = (0, import_path88.join)(dir, "skill-runner-health.json");
49890
50503
  const tmpPath = finalPath + ".tmp";
49891
50504
  try {
49892
- (0, import_fs80.mkdirSync)(dir, { recursive: true });
49893
- (0, import_fs80.writeFileSync)(tmpPath, JSON.stringify(record2, null, 2));
49894
- (0, import_fs80.renameSync)(tmpPath, finalPath);
50505
+ (0, import_fs82.mkdirSync)(dir, { recursive: true });
50506
+ (0, import_fs82.writeFileSync)(tmpPath, JSON.stringify(record2, null, 2));
50507
+ (0, import_fs82.renameSync)(tmpPath, finalPath);
49895
50508
  } catch (e) {
49896
50509
  process.stderr.write(`[gossipcat] checkEffectiveness: health write failed: ${e.message}
49897
50510
  `);
49898
50511
  try {
49899
- if ((0, import_fs80.existsSync)(tmpPath)) (0, import_fs80.unlinkSync)(tmpPath);
50512
+ if ((0, import_fs82.existsSync)(tmpPath)) (0, import_fs82.unlinkSync)(tmpPath);
49900
50513
  } catch {
49901
50514
  }
49902
50515
  }
49903
50516
  }
49904
50517
  async function runCheckEffectivenessForAllSkills(opts) {
49905
50518
  const startedAt = Date.now();
49906
- const baseDir = (0, import_path86.join)(opts.projectRoot, ".gossip", "agents");
50519
+ const baseDir = (0, import_path88.join)(opts.projectRoot, ".gossip", "agents");
49907
50520
  let agentDirs = [];
49908
50521
  let canonicalBaseDir;
49909
- if ((0, import_fs80.existsSync)(baseDir)) {
50522
+ if ((0, import_fs82.existsSync)(baseDir)) {
49910
50523
  try {
49911
- canonicalBaseDir = (0, import_fs80.realpathSync)(baseDir);
49912
- agentDirs = (0, import_fs80.readdirSync)(canonicalBaseDir);
50524
+ canonicalBaseDir = (0, import_fs82.realpathSync)(baseDir);
50525
+ agentDirs = (0, import_fs82.readdirSync)(canonicalBaseDir);
49913
50526
  } catch {
49914
50527
  }
49915
50528
  }
@@ -49928,11 +50541,11 @@ async function runCheckEffectivenessForAllSkills(opts) {
49928
50541
  for (const agentId of agentDirs) {
49929
50542
  if (agentId.startsWith("_")) continue;
49930
50543
  if (!SAFE_NAME2.test(agentId)) continue;
49931
- const skillsDir = (0, import_path86.join)(canonicalBaseDir, agentId, "skills");
49932
- if (!(0, import_fs80.existsSync)(skillsDir)) continue;
50544
+ const skillsDir = (0, import_path88.join)(canonicalBaseDir, agentId, "skills");
50545
+ if (!(0, import_fs82.existsSync)(skillsDir)) continue;
49933
50546
  let canonicalSkillsDir;
49934
50547
  try {
49935
- canonicalSkillsDir = (0, import_fs80.realpathSync)(skillsDir);
50548
+ canonicalSkillsDir = (0, import_fs82.realpathSync)(skillsDir);
49936
50549
  } catch {
49937
50550
  continue;
49938
50551
  }
@@ -49943,7 +50556,7 @@ async function runCheckEffectivenessForAllSkills(opts) {
49943
50556
  }
49944
50557
  const role = opts.registryGet(agentId)?.role;
49945
50558
  if (role === "implementer") continue;
49946
- const files = (0, import_fs80.readdirSync)(canonicalSkillsDir).filter((f) => f.endsWith(".md"));
50559
+ const files = (0, import_fs82.readdirSync)(canonicalSkillsDir).filter((f) => f.endsWith(".md"));
49947
50560
  for (const file2 of files) {
49948
50561
  const category = file2.replace(/\.md$/, "");
49949
50562
  if (!SAFE_NAME2.test(category)) continue;
@@ -49990,12 +50603,12 @@ async function runCheckEffectivenessForAllSkills(opts) {
49990
50603
  last_error: lastError
49991
50604
  });
49992
50605
  }
49993
- var import_fs80, import_path86, SAFE_NAME2;
50606
+ var import_fs82, import_path88, SAFE_NAME2;
49994
50607
  var init_check_effectiveness_runner = __esm({
49995
50608
  "apps/cli/src/handlers/check-effectiveness-runner.ts"() {
49996
50609
  "use strict";
49997
- import_fs80 = require("fs");
49998
- import_path86 = require("path");
50610
+ import_fs82 = require("fs");
50611
+ import_path88 = require("path");
49999
50612
  init_dispatch_prompt_cache();
50000
50613
  SAFE_NAME2 = /^(?!.*\.\.)[a-zA-Z0-9._-]+$/;
50001
50614
  }
@@ -50008,20 +50621,20 @@ __export(skill_develop_audit_exports, {
50008
50621
  });
50009
50622
  function appendSkillDevelopAudit(entry) {
50010
50623
  try {
50011
- const gossipDir = (0, import_path87.join)(process.cwd(), ".gossip");
50012
- (0, import_fs81.mkdirSync)(gossipDir, { recursive: true });
50624
+ const gossipDir = (0, import_path89.join)(process.cwd(), ".gossip");
50625
+ (0, import_fs83.mkdirSync)(gossipDir, { recursive: true });
50013
50626
  const line = JSON.stringify(entry) + "\n";
50014
- (0, import_fs81.appendFileSync)((0, import_path87.join)(gossipDir, AUDIT_FILE2), line);
50015
- (0, import_fs81.appendFileSync)((0, import_path87.join)(gossipDir, LEGACY_FILE), line);
50627
+ (0, import_fs83.appendFileSync)((0, import_path89.join)(gossipDir, AUDIT_FILE2), line);
50628
+ (0, import_fs83.appendFileSync)((0, import_path89.join)(gossipDir, LEGACY_FILE), line);
50016
50629
  } catch {
50017
50630
  }
50018
50631
  }
50019
- var import_fs81, import_path87, AUDIT_FILE2, LEGACY_FILE;
50632
+ var import_fs83, import_path89, AUDIT_FILE2, LEGACY_FILE;
50020
50633
  var init_skill_develop_audit = __esm({
50021
50634
  "apps/cli/src/handlers/skill-develop-audit.ts"() {
50022
50635
  "use strict";
50023
- import_fs81 = require("fs");
50024
- import_path87 = require("path");
50636
+ import_fs83 = require("fs");
50637
+ import_path89 = require("path");
50025
50638
  AUDIT_FILE2 = "skill-develop-audit.jsonl";
50026
50639
  LEGACY_FILE = "forced-skill-develops.jsonl";
50027
50640
  }
@@ -50079,14 +50692,14 @@ var keychain_exports = {};
50079
50692
  __export(keychain_exports, {
50080
50693
  Keychain: () => Keychain
50081
50694
  });
50082
- var import_child_process14, import_os6, import_fs85, import_path91, import_crypto35, DEFAULT_SERVICE_NAME, VALID_PROVIDERS3, ENCRYPTED_FILE, ALGO, Keychain;
50695
+ var import_child_process15, import_os6, import_fs87, import_path93, import_crypto35, DEFAULT_SERVICE_NAME, VALID_PROVIDERS3, ENCRYPTED_FILE, ALGO, Keychain;
50083
50696
  var init_keychain = __esm({
50084
50697
  "apps/cli/src/keychain.ts"() {
50085
50698
  "use strict";
50086
- import_child_process14 = require("child_process");
50699
+ import_child_process15 = require("child_process");
50087
50700
  import_os6 = require("os");
50088
- import_fs85 = require("fs");
50089
- import_path91 = require("path");
50701
+ import_fs87 = require("fs");
50702
+ import_path93 = require("path");
50090
50703
  import_crypto35 = require("crypto");
50091
50704
  DEFAULT_SERVICE_NAME = "gossip-mesh";
50092
50705
  VALID_PROVIDERS3 = /^[a-zA-Z0-9_-]{1,32}$/;
@@ -50130,10 +50743,10 @@ var init_keychain = __esm({
50130
50743
  return (0, import_crypto35.pbkdf2Sync)(seed, salt, 6e5, 32, "sha256");
50131
50744
  }
50132
50745
  loadEncryptedFile() {
50133
- const filePath = (0, import_path91.join)(process.cwd(), ENCRYPTED_FILE);
50134
- if (!(0, import_fs85.existsSync)(filePath)) return;
50746
+ const filePath = (0, import_path93.join)(process.cwd(), ENCRYPTED_FILE);
50747
+ if (!(0, import_fs87.existsSync)(filePath)) return;
50135
50748
  try {
50136
- const raw = (0, import_fs85.readFileSync)(filePath);
50749
+ const raw = (0, import_fs87.readFileSync)(filePath);
50137
50750
  if (raw.length < 61) return;
50138
50751
  const salt = raw.subarray(0, 32);
50139
50752
  const iv = raw.subarray(32, 44);
@@ -50151,9 +50764,9 @@ var init_keychain = __esm({
50151
50764
  }
50152
50765
  }
50153
50766
  saveEncryptedFile() {
50154
- const filePath = (0, import_path91.join)(process.cwd(), ENCRYPTED_FILE);
50155
- const dir = (0, import_path91.join)(process.cwd(), ".gossip");
50156
- if (!(0, import_fs85.existsSync)(dir)) (0, import_fs85.mkdirSync)(dir, { recursive: true });
50767
+ const filePath = (0, import_path93.join)(process.cwd(), ENCRYPTED_FILE);
50768
+ const dir = (0, import_path93.join)(process.cwd(), ".gossip");
50769
+ if (!(0, import_fs87.existsSync)(dir)) (0, import_fs87.mkdirSync)(dir, { recursive: true });
50157
50770
  const data = JSON.stringify(Object.fromEntries(this.inMemoryStore));
50158
50771
  const salt = (0, import_crypto35.randomBytes)(32);
50159
50772
  const iv = (0, import_crypto35.randomBytes)(12);
@@ -50161,12 +50774,12 @@ var init_keychain = __esm({
50161
50774
  const cipher = (0, import_crypto35.createCipheriv)(ALGO, key, iv);
50162
50775
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
50163
50776
  const tag = cipher.getAuthTag();
50164
- (0, import_fs85.writeFileSync)(filePath, Buffer.concat([salt, iv, tag, encrypted]), { mode: 384 });
50777
+ (0, import_fs87.writeFileSync)(filePath, Buffer.concat([salt, iv, tag, encrypted]), { mode: 384 });
50165
50778
  }
50166
50779
  isKeychainAvailable() {
50167
50780
  if ((0, import_os6.platform)() === "darwin") {
50168
50781
  try {
50169
- (0, import_child_process14.execFileSync)("security", ["help"], { stdio: "pipe" });
50782
+ (0, import_child_process15.execFileSync)("security", ["help"], { stdio: "pipe" });
50170
50783
  return true;
50171
50784
  } catch {
50172
50785
  return false;
@@ -50174,7 +50787,7 @@ var init_keychain = __esm({
50174
50787
  }
50175
50788
  if ((0, import_os6.platform)() === "linux") {
50176
50789
  try {
50177
- (0, import_child_process14.execFileSync)("which", ["secret-tool"], { stdio: "pipe" });
50790
+ (0, import_child_process15.execFileSync)("which", ["secret-tool"], { stdio: "pipe" });
50178
50791
  return true;
50179
50792
  } catch {
50180
50793
  return false;
@@ -50190,7 +50803,7 @@ var init_keychain = __esm({
50190
50803
  readFromKeychain(provider) {
50191
50804
  this.validateProvider(provider);
50192
50805
  if ((0, import_os6.platform)() === "darwin") {
50193
- return (0, import_child_process14.execFileSync)("security", [
50806
+ return (0, import_child_process15.execFileSync)("security", [
50194
50807
  "find-generic-password",
50195
50808
  "-s",
50196
50809
  this.serviceName,
@@ -50200,7 +50813,7 @@ var init_keychain = __esm({
50200
50813
  ], { stdio: "pipe" }).toString().trim();
50201
50814
  }
50202
50815
  if ((0, import_os6.platform)() === "linux") {
50203
- return (0, import_child_process14.execFileSync)("secret-tool", [
50816
+ return (0, import_child_process15.execFileSync)("secret-tool", [
50204
50817
  "lookup",
50205
50818
  "service",
50206
50819
  this.serviceName,
@@ -50214,7 +50827,7 @@ var init_keychain = __esm({
50214
50827
  this.validateProvider(provider);
50215
50828
  if ((0, import_os6.platform)() === "darwin") {
50216
50829
  try {
50217
- (0, import_child_process14.execFileSync)("security", [
50830
+ (0, import_child_process15.execFileSync)("security", [
50218
50831
  "delete-generic-password",
50219
50832
  "-s",
50220
50833
  this.serviceName,
@@ -50223,7 +50836,7 @@ var init_keychain = __esm({
50223
50836
  ], { stdio: "pipe" });
50224
50837
  } catch {
50225
50838
  }
50226
- (0, import_child_process14.execFileSync)("security", [
50839
+ (0, import_child_process15.execFileSync)("security", [
50227
50840
  "add-generic-password",
50228
50841
  "-s",
50229
50842
  this.serviceName,
@@ -50235,7 +50848,7 @@ var init_keychain = __esm({
50235
50848
  return;
50236
50849
  }
50237
50850
  if ((0, import_os6.platform)() === "linux") {
50238
- (0, import_child_process14.execFileSync)("secret-tool", [
50851
+ (0, import_child_process15.execFileSync)("secret-tool", [
50239
50852
  "store",
50240
50853
  "--label",
50241
50854
  `Gossip Mesh ${provider}`,
@@ -50254,12 +50867,13 @@ var init_keychain = __esm({
50254
50867
  // apps/cli/src/code-launch.ts
50255
50868
  var code_launch_exports = {};
50256
50869
  __export(code_launch_exports, {
50870
+ detectServerName: () => detectServerName,
50257
50871
  runCodeCommand: () => runCodeCommand
50258
50872
  });
50259
50873
  function safeReadJson(filePath) {
50260
50874
  try {
50261
- if (!(0, import_fs86.existsSync)(filePath)) return null;
50262
- const raw = (0, import_fs86.readFileSync)(filePath, "utf-8");
50875
+ if (!(0, import_fs88.existsSync)(filePath)) return null;
50876
+ const raw = (0, import_fs88.readFileSync)(filePath, "utf-8");
50263
50877
  return JSON.parse(raw);
50264
50878
  } catch {
50265
50879
  return null;
@@ -50276,21 +50890,23 @@ function isGossipMcpEntry(entry) {
50276
50890
  return false;
50277
50891
  }
50278
50892
  function detectServerName(cwd) {
50893
+ const cwdPath = (0, import_path94.join)(cwd, ".mcp.json");
50894
+ const homePath = (0, import_path94.join)((0, import_os7.homedir)(), ".claude.json");
50279
50895
  const candidates = [
50280
- [(0, import_path92.join)(cwd, ".mcp.json"), safeReadJson((0, import_path92.join)(cwd, ".mcp.json"))],
50281
- [(0, import_path92.join)((0, import_os7.homedir)(), ".claude.json"), safeReadJson((0, import_path92.join)((0, import_os7.homedir)(), ".claude.json"))]
50896
+ [cwdPath, safeReadJson(cwdPath)],
50897
+ [homePath, safeReadJson(homePath)]
50282
50898
  ];
50283
- for (const [filePath, data] of candidates) {
50284
- if (!data || typeof data !== "object") continue;
50899
+ function extractName(data, filePath) {
50900
+ if (!data || typeof data !== "object") return null;
50285
50901
  const root = data;
50286
50902
  const mcpServers = root["mcpServers"];
50287
- if (!mcpServers || typeof mcpServers !== "object") continue;
50903
+ if (!mcpServers || typeof mcpServers !== "object") return null;
50288
50904
  const servers = mcpServers;
50289
50905
  for (const [name, entry] of Object.entries(servers)) {
50290
50906
  if (!entry || typeof entry !== "object") continue;
50291
50907
  if (isGossipMcpEntry(entry)) {
50292
50908
  if (SAFE_SERVER_NAME_RE.test(name)) {
50293
- return [name, false];
50909
+ return name;
50294
50910
  }
50295
50911
  process.stderr.write(
50296
50912
  `[gossipcat code] Warning: found gossipcat MCP entry in ${filePath} but server name "${name}" contains unsafe characters; falling back to "gossipcat".
@@ -50298,11 +50914,30 @@ function detectServerName(cwd) {
50298
50914
  );
50299
50915
  }
50300
50916
  }
50917
+ return null;
50918
+ }
50919
+ const cwdName = extractName(candidates[0][1], cwdPath);
50920
+ const homeName = extractName(candidates[1][1], homePath);
50921
+ if (cwdName !== null) {
50922
+ process.stderr.write(
50923
+ `[gossipcat code] Using channel server "${cwdName}" from ${cwdPath} (cwd-local config \u2014 only run this in repos you trust).
50924
+ `
50925
+ );
50926
+ if (homeName !== null && homeName !== cwdName) {
50927
+ process.stderr.write(
50928
+ `[gossipcat code] Warning: gossipcat server name differs between ${cwdPath} ("${cwdName}") and ${homePath} ("${homeName}"); using "${cwdName}" (cwd takes precedence).
50929
+ `
50930
+ );
50931
+ }
50932
+ return [cwdName, false];
50933
+ }
50934
+ if (homeName !== null) {
50935
+ return [homeName, false];
50301
50936
  }
50302
50937
  return ["gossipcat", true];
50303
50938
  }
50304
50939
  function isChannelAllowlisted(cwd) {
50305
- const configPath = (0, import_path92.join)(cwd, ".gossip", "config.json");
50940
+ const configPath = (0, import_path94.join)(cwd, ".gossip", "config.json");
50306
50941
  try {
50307
50942
  const data = safeReadJson(configPath);
50308
50943
  if (!data || typeof data !== "object") return false;
@@ -50334,7 +50969,7 @@ function runCodeCommand(argv) {
50334
50969
  );
50335
50970
  claudeArgs = ["--dangerously-load-development-channels", `server:${serverName}`, ...argv];
50336
50971
  }
50337
- const child = (0, import_child_process15.spawn)("claude", claudeArgs, { stdio: "inherit" });
50972
+ const child = (0, import_child_process16.spawn)("claude", claudeArgs, { stdio: "inherit" });
50338
50973
  child.on("error", (err) => {
50339
50974
  if (err.code === "ENOENT") {
50340
50975
  process.stderr.write(
@@ -50355,14 +50990,14 @@ function runCodeCommand(argv) {
50355
50990
  }
50356
50991
  });
50357
50992
  }
50358
- var import_fs86, import_path92, import_os7, import_child_process15, SAFE_SERVER_NAME_RE;
50993
+ var import_fs88, import_path94, import_os7, import_child_process16, SAFE_SERVER_NAME_RE;
50359
50994
  var init_code_launch = __esm({
50360
50995
  "apps/cli/src/code-launch.ts"() {
50361
50996
  "use strict";
50362
- import_fs86 = require("fs");
50363
- import_path92 = require("path");
50997
+ import_fs88 = require("fs");
50998
+ import_path94 = require("path");
50364
50999
  import_os7 = require("os");
50365
- import_child_process15 = require("child_process");
51000
+ import_child_process16 = require("child_process");
50366
51001
  SAFE_SERVER_NAME_RE = /^[a-zA-Z0-9._-]{1,64}$/;
50367
51002
  }
50368
51003
  });
@@ -50377,23 +51012,23 @@ __export(identity_exports, {
50377
51012
  normalizeGitUrl: () => normalizeGitUrl
50378
51013
  });
50379
51014
  function getOrCreateSalt(projectRoot) {
50380
- const saltPath = (0, import_path93.join)(projectRoot, ".gossip", "local-salt");
51015
+ const saltPath = (0, import_path95.join)(projectRoot, ".gossip", "local-salt");
50381
51016
  try {
50382
- return (0, import_fs87.readFileSync)(saltPath, "utf-8").trim();
51017
+ return (0, import_fs89.readFileSync)(saltPath, "utf-8").trim();
50383
51018
  } catch {
50384
51019
  const salt = (0, import_crypto36.randomBytes)(16).toString("hex");
50385
- (0, import_fs87.mkdirSync)((0, import_path93.join)(projectRoot, ".gossip"), { recursive: true });
51020
+ (0, import_fs89.mkdirSync)((0, import_path95.join)(projectRoot, ".gossip"), { recursive: true });
50386
51021
  try {
50387
- (0, import_fs87.writeFileSync)(saltPath, salt, { flag: "wx" });
51022
+ (0, import_fs89.writeFileSync)(saltPath, salt, { flag: "wx" });
50388
51023
  return salt;
50389
51024
  } catch {
50390
- return (0, import_fs87.readFileSync)(saltPath, "utf-8").trim();
51025
+ return (0, import_fs89.readFileSync)(saltPath, "utf-8").trim();
50391
51026
  }
50392
51027
  }
50393
51028
  }
50394
51029
  function getUserId(projectRoot) {
50395
51030
  try {
50396
- const email3 = (0, import_child_process16.execFileSync)("git", ["config", "user.email"], { stdio: "pipe" }).toString().trim();
51031
+ const email3 = (0, import_child_process17.execFileSync)("git", ["config", "user.email"], { stdio: "pipe" }).toString().trim();
50397
51032
  const salt = getOrCreateSalt(projectRoot);
50398
51033
  return (0, import_crypto36.createHash)("sha256").update(email3 + projectRoot + salt).digest("hex").slice(0, 16);
50399
51034
  } catch {
@@ -50416,7 +51051,7 @@ function getTeamUserId(email3, teamSalt) {
50416
51051
  }
50417
51052
  function getGitEmail() {
50418
51053
  try {
50419
- const email3 = (0, import_child_process16.execFileSync)("git", ["config", "user.email"], { stdio: "pipe" }).toString().trim();
51054
+ const email3 = (0, import_child_process17.execFileSync)("git", ["config", "user.email"], { stdio: "pipe" }).toString().trim();
50420
51055
  return email3 || null;
50421
51056
  } catch {
50422
51057
  return null;
@@ -50424,7 +51059,7 @@ function getGitEmail() {
50424
51059
  }
50425
51060
  function getProjectId(projectRoot) {
50426
51061
  try {
50427
- const remoteUrl = (0, import_child_process16.execFileSync)(
51062
+ const remoteUrl = (0, import_child_process17.execFileSync)(
50428
51063
  "git",
50429
51064
  ["config", "--get", "remote.origin.url"],
50430
51065
  { cwd: projectRoot, stdio: "pipe" }
@@ -50437,14 +51072,14 @@ function getProjectId(projectRoot) {
50437
51072
  }
50438
51073
  return (0, import_crypto36.createHash)("sha256").update(projectRoot).digest("hex").slice(0, 16);
50439
51074
  }
50440
- var import_fs87, import_path93, import_crypto36, import_child_process16;
51075
+ var import_fs89, import_path95, import_crypto36, import_child_process17;
50441
51076
  var init_identity = __esm({
50442
51077
  "apps/cli/src/identity.ts"() {
50443
51078
  "use strict";
50444
- import_fs87 = require("fs");
50445
- import_path93 = require("path");
51079
+ import_fs89 = require("fs");
51080
+ import_path95 = require("path");
50446
51081
  import_crypto36 = require("crypto");
50447
- import_child_process16 = require("child_process");
51082
+ import_child_process17 = require("child_process");
50448
51083
  }
50449
51084
  });
50450
51085
 
@@ -50511,9 +51146,9 @@ async function getLatestVersion() {
50511
51146
  return data.version;
50512
51147
  }
50513
51148
  function detectInstallMethod() {
50514
- const packageRoot = (0, import_path94.resolve)(__dirname, "..", "..", "..", "..");
51149
+ const packageRoot = (0, import_path96.resolve)(__dirname, "..", "..", "..", "..");
50515
51150
  if (process.env.npm_config_global === "true") return "global";
50516
- if ((0, import_fs88.existsSync)((0, import_path94.join)(packageRoot, ".git"))) return "git-clone";
51151
+ if ((0, import_fs90.existsSync)((0, import_path96.join)(packageRoot, ".git"))) return "git-clone";
50517
51152
  return "local";
50518
51153
  }
50519
51154
  function updateCommand(method, version2) {
@@ -50566,9 +51201,9 @@ Check your internet connection or visit https://www.npmjs.com/package/gossipcat
50566
51201
  if (/^GOSSIPCAT_/i.test(key)) delete scrubbedEnv[key];
50567
51202
  }
50568
51203
  try {
50569
- (0, import_child_process17.execSync)(command, {
51204
+ (0, import_child_process18.execSync)(command, {
50570
51205
  stdio: "inherit",
50571
- cwd: method === "git-clone" ? (0, import_path94.resolve)(__dirname, "..", "..", "..", "..") : process.cwd(),
51206
+ cwd: method === "git-clone" ? (0, import_path96.resolve)(__dirname, "..", "..", "..", "..") : process.cwd(),
50572
51207
  env: scrubbedEnv
50573
51208
  });
50574
51209
  } catch (err) {
@@ -50591,13 +51226,13 @@ Run /mcp reconnect in Claude Code to load the new version.`
50591
51226
  }]
50592
51227
  };
50593
51228
  }
50594
- var import_child_process17, import_fs88, import_path94;
51229
+ var import_child_process18, import_fs90, import_path96;
50595
51230
  var init_gossip_update = __esm({
50596
51231
  "apps/cli/src/handlers/gossip-update.ts"() {
50597
51232
  "use strict";
50598
- import_child_process17 = require("child_process");
50599
- import_fs88 = require("fs");
50600
- import_path94 = require("path");
51233
+ import_child_process18 = require("child_process");
51234
+ import_fs90 = require("fs");
51235
+ import_path96 = require("path");
50601
51236
  init_version();
50602
51237
  }
50603
51238
  });
@@ -50810,8 +51445,8 @@ __export(mcp_server_sdk_exports, {
50810
51445
  resolveHookAction: () => resolveHookAction
50811
51446
  });
50812
51447
  module.exports = __toCommonJS(mcp_server_sdk_exports);
50813
- var import_fs89 = require("fs");
50814
- var import_path95 = require("path");
51448
+ var import_fs91 = require("fs");
51449
+ var import_path97 = require("path");
50815
51450
 
50816
51451
  // apps/cli/src/hook-run.ts
50817
51452
  var import_fs = require("fs");
@@ -50894,10 +51529,10 @@ var RELAY_PORT_FILE = "relay.port";
50894
51529
  var AUTH_MAX_READ = 64 * 1024;
50895
51530
  var CURL_MAX_TIME = "2";
50896
51531
  function readDashboardKey(cwd) {
50897
- const path7 = (0, import_path2.join)(cwd, ".gossip", AUTH_FILE_NAME);
51532
+ const path8 = (0, import_path2.join)(cwd, ".gossip", AUTH_FILE_NAME);
50898
51533
  let fd = null;
50899
51534
  try {
50900
- fd = (0, import_fs2.openSync)(path7, "r");
51535
+ fd = (0, import_fs2.openSync)(path8, "r");
50901
51536
  const st = (0, import_fs2.fstatSync)(fd);
50902
51537
  if (!st.isFile()) return null;
50903
51538
  if ((st.mode & 63) !== 0) return null;
@@ -50994,7 +51629,7 @@ function resolveCwd(payloadCwd) {
50994
51629
  return process.cwd();
50995
51630
  }
50996
51631
  function readStdin() {
50997
- return new Promise((resolve32) => {
51632
+ return new Promise((resolve33) => {
50998
51633
  let data = "";
50999
51634
  try {
51000
51635
  const stdin = process.stdin;
@@ -51002,11 +51637,11 @@ function readStdin() {
51002
51637
  stdin.on("data", (chunk) => {
51003
51638
  data += chunk;
51004
51639
  });
51005
- stdin.on("end", () => resolve32(data));
51006
- stdin.on("error", () => resolve32(data));
51007
- if (stdin.isTTY) resolve32("");
51640
+ stdin.on("end", () => resolve33(data));
51641
+ stdin.on("error", () => resolve33(data));
51642
+ if (stdin.isTTY) resolve33("");
51008
51643
  } catch {
51009
- resolve32("");
51644
+ resolve33("");
51010
51645
  }
51011
51646
  });
51012
51647
  }
@@ -51243,9 +51878,9 @@ function getLastKnownLatest(cwd = process.cwd()) {
51243
51878
  async function checkForUpgrade(cwd = process.cwd()) {
51244
51879
  try {
51245
51880
  if (process.env.GOSSIP_DISABLE_UPGRADE_CHECK === "1") return;
51246
- const path7 = cachePath(cwd);
51881
+ const path8 = cachePath(cwd);
51247
51882
  try {
51248
- const raw = (0, import_fs4.readFileSync)(path7, "utf8");
51883
+ const raw = (0, import_fs4.readFileSync)(path8, "utf8");
51249
51884
  const data = JSON.parse(raw);
51250
51885
  if (typeof data.checkedAt === "string") {
51251
51886
  const checkedMs = new Date(data.checkedAt).getTime();
@@ -51262,13 +51897,13 @@ async function checkForUpgrade(cwd = process.cwd()) {
51262
51897
  latestVersion: json2.version
51263
51898
  };
51264
51899
  try {
51265
- (0, import_fs4.mkdirSync)((0, import_path3.dirname)(path7), { recursive: true });
51900
+ (0, import_fs4.mkdirSync)((0, import_path3.dirname)(path8), { recursive: true });
51266
51901
  } catch {
51267
51902
  }
51268
- const tmp = `${path7}.${process.pid}.tmp`;
51903
+ const tmp = `${path8}.${process.pid}.tmp`;
51269
51904
  (0, import_fs4.writeFileSync)(tmp, JSON.stringify(cache3), "utf8");
51270
51905
  try {
51271
- (0, import_fs4.renameSync)(tmp, path7);
51906
+ (0, import_fs4.renameSync)(tmp, path8);
51272
51907
  } catch (err) {
51273
51908
  try {
51274
51909
  (0, import_fs4.unlinkSync)(tmp);
@@ -51659,8 +52294,8 @@ function getErrorMap() {
51659
52294
 
51660
52295
  // node_modules/zod/v3/helpers/parseUtil.js
51661
52296
  var makeIssue = (params) => {
51662
- const { data, path: path7, errorMaps, issueData } = params;
51663
- const fullPath = [...path7, ...issueData.path || []];
52297
+ const { data, path: path8, errorMaps, issueData } = params;
52298
+ const fullPath = [...path8, ...issueData.path || []];
51664
52299
  const fullIssue = {
51665
52300
  ...issueData,
51666
52301
  path: fullPath
@@ -51775,11 +52410,11 @@ var errorUtil;
51775
52410
 
51776
52411
  // node_modules/zod/v3/types.js
51777
52412
  var ParseInputLazyPath = class {
51778
- constructor(parent, value, path7, key) {
52413
+ constructor(parent, value, path8, key) {
51779
52414
  this._cachedPath = [];
51780
52415
  this.parent = parent;
51781
52416
  this.data = value;
51782
- this._path = path7;
52417
+ this._path = path8;
51783
52418
  this._key = key;
51784
52419
  }
51785
52420
  get path() {
@@ -55699,10 +56334,10 @@ function mergeDefs(...defs) {
55699
56334
  function cloneDef(schema) {
55700
56335
  return mergeDefs(schema._zod.def);
55701
56336
  }
55702
- function getElementAtPath(obj, path7) {
55703
- if (!path7)
56337
+ function getElementAtPath(obj, path8) {
56338
+ if (!path8)
55704
56339
  return obj;
55705
- return path7.reduce((acc, key) => acc?.[key], obj);
56340
+ return path8.reduce((acc, key) => acc?.[key], obj);
55706
56341
  }
55707
56342
  function promiseAllObject(promisesObj) {
55708
56343
  const keys = Object.keys(promisesObj);
@@ -56111,11 +56746,11 @@ function explicitlyAborted(x, startIndex = 0) {
56111
56746
  }
56112
56747
  return false;
56113
56748
  }
56114
- function prefixIssues(path7, issues) {
56749
+ function prefixIssues(path8, issues) {
56115
56750
  return issues.map((iss) => {
56116
56751
  var _a3;
56117
56752
  (_a3 = iss).path ?? (_a3.path = []);
56118
- iss.path.unshift(path7);
56753
+ iss.path.unshift(path8);
56119
56754
  return iss;
56120
56755
  });
56121
56756
  }
@@ -56262,16 +56897,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
56262
56897
  }
56263
56898
  function formatError(error51, mapper = (issue2) => issue2.message) {
56264
56899
  const fieldErrors = { _errors: [] };
56265
- const processError = (error52, path7 = []) => {
56900
+ const processError = (error52, path8 = []) => {
56266
56901
  for (const issue2 of error52.issues) {
56267
56902
  if (issue2.code === "invalid_union" && issue2.errors.length) {
56268
- issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
56903
+ issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
56269
56904
  } else if (issue2.code === "invalid_key") {
56270
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
56905
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
56271
56906
  } else if (issue2.code === "invalid_element") {
56272
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
56907
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
56273
56908
  } else {
56274
- const fullpath = [...path7, ...issue2.path];
56909
+ const fullpath = [...path8, ...issue2.path];
56275
56910
  if (fullpath.length === 0) {
56276
56911
  fieldErrors._errors.push(mapper(issue2));
56277
56912
  } else {
@@ -56298,17 +56933,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
56298
56933
  }
56299
56934
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
56300
56935
  const result = { errors: [] };
56301
- const processError = (error52, path7 = []) => {
56936
+ const processError = (error52, path8 = []) => {
56302
56937
  var _a3, _b;
56303
56938
  for (const issue2 of error52.issues) {
56304
56939
  if (issue2.code === "invalid_union" && issue2.errors.length) {
56305
- issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
56940
+ issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
56306
56941
  } else if (issue2.code === "invalid_key") {
56307
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
56942
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
56308
56943
  } else if (issue2.code === "invalid_element") {
56309
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
56944
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
56310
56945
  } else {
56311
- const fullpath = [...path7, ...issue2.path];
56946
+ const fullpath = [...path8, ...issue2.path];
56312
56947
  if (fullpath.length === 0) {
56313
56948
  result.errors.push(mapper(issue2));
56314
56949
  continue;
@@ -56340,8 +56975,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
56340
56975
  }
56341
56976
  function toDotPath(_path) {
56342
56977
  const segs = [];
56343
- const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
56344
- for (const seg of path7) {
56978
+ const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
56979
+ for (const seg of path8) {
56345
56980
  if (typeof seg === "number")
56346
56981
  segs.push(`[${seg}]`);
56347
56982
  else if (typeof seg === "symbol")
@@ -69466,13 +70101,13 @@ function resolveRef(ref, ctx2) {
69466
70101
  if (!ref.startsWith("#")) {
69467
70102
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
69468
70103
  }
69469
- const path7 = ref.slice(1).split("/").filter(Boolean);
69470
- if (path7.length === 0) {
70104
+ const path8 = ref.slice(1).split("/").filter(Boolean);
70105
+ if (path8.length === 0) {
69471
70106
  return ctx2.rootSchema;
69472
70107
  }
69473
70108
  const defsKey = ctx2.version === "draft-2020-12" ? "$defs" : "definitions";
69474
- if (path7[0] === defsKey) {
69475
- const key = path7[1];
70109
+ if (path8[0] === defsKey) {
70110
+ const key = path8[1];
69476
70111
  if (!key || !ctx2.defs[key]) {
69477
70112
  throw new Error(`Reference not found: ${ref}`);
69478
70113
  }
@@ -73244,7 +73879,7 @@ var Protocol = class {
73244
73879
  return;
73245
73880
  }
73246
73881
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
73247
- await new Promise((resolve32) => setTimeout(resolve32, pollInterval));
73882
+ await new Promise((resolve33) => setTimeout(resolve33, pollInterval));
73248
73883
  options?.signal?.throwIfAborted();
73249
73884
  }
73250
73885
  } catch (error51) {
@@ -73261,7 +73896,7 @@ var Protocol = class {
73261
73896
  */
73262
73897
  request(request, resultSchema, options) {
73263
73898
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
73264
- return new Promise((resolve32, reject) => {
73899
+ return new Promise((resolve33, reject) => {
73265
73900
  const earlyReject = (error51) => {
73266
73901
  reject(error51);
73267
73902
  };
@@ -73339,7 +73974,7 @@ var Protocol = class {
73339
73974
  if (!parseResult.success) {
73340
73975
  reject(parseResult.error);
73341
73976
  } else {
73342
- resolve32(parseResult.data);
73977
+ resolve33(parseResult.data);
73343
73978
  }
73344
73979
  } catch (error51) {
73345
73980
  reject(error51);
@@ -73600,12 +74235,12 @@ var Protocol = class {
73600
74235
  }
73601
74236
  } catch {
73602
74237
  }
73603
- return new Promise((resolve32, reject) => {
74238
+ return new Promise((resolve33, reject) => {
73604
74239
  if (signal.aborted) {
73605
74240
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
73606
74241
  return;
73607
74242
  }
73608
- const timeoutId = setTimeout(resolve32, interval);
74243
+ const timeoutId = setTimeout(resolve33, interval);
73609
74244
  signal.addEventListener("abort", () => {
73610
74245
  clearTimeout(timeoutId);
73611
74246
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -74705,7 +75340,7 @@ var McpServer = class {
74705
75340
  let task = createTaskResult.task;
74706
75341
  const pollInterval = task.pollInterval ?? 5e3;
74707
75342
  while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
74708
- await new Promise((resolve32) => setTimeout(resolve32, pollInterval));
75343
+ await new Promise((resolve33) => setTimeout(resolve33, pollInterval));
74709
75344
  const updatedTask = await extra.taskStore.getTask(taskId);
74710
75345
  if (!updatedTask) {
74711
75346
  throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
@@ -75408,12 +76043,12 @@ var StdioServerTransport = class {
75408
76043
  this.onclose?.();
75409
76044
  }
75410
76045
  send(message) {
75411
- return new Promise((resolve32) => {
76046
+ return new Promise((resolve33) => {
75412
76047
  const json2 = serializeMessage(message);
75413
76048
  if (this._stdout.write(json2)) {
75414
- resolve32();
76049
+ resolve33();
75415
76050
  } else {
75416
- this._stdout.once("drain", resolve32);
76051
+ this._stdout.once("drain", resolve33);
75417
76052
  }
75418
76053
  });
75419
76054
  }
@@ -75912,7 +76547,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
75912
76547
  });
75913
76548
  if (!chunk) {
75914
76549
  if (i === 1) {
75915
- await new Promise((resolve32) => setTimeout(resolve32));
76550
+ await new Promise((resolve33) => setTimeout(resolve33));
75916
76551
  maxReadCount = 3;
75917
76552
  continue;
75918
76553
  }
@@ -76412,9 +77047,9 @@ data:
76412
77047
  const initRequest = messages.find((m) => isInitializeRequest(m));
76413
77048
  const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
76414
77049
  if (this._enableJsonResponse) {
76415
- return new Promise((resolve32) => {
77050
+ return new Promise((resolve33) => {
76416
77051
  this._streamMapping.set(streamId, {
76417
- resolveJson: resolve32,
77052
+ resolveJson: resolve33,
76418
77053
  cleanup: () => {
76419
77054
  this._streamMapping.delete(streamId);
76420
77055
  }
@@ -76799,8 +77434,8 @@ init_native_tasks();
76799
77434
 
76800
77435
  // apps/cli/src/handlers/dispatch.ts
76801
77436
  var import_crypto34 = require("crypto");
76802
- var import_fs78 = require("fs");
76803
- var import_path85 = require("path");
77437
+ var import_fs79 = require("fs");
77438
+ var import_path86 = require("path");
76804
77439
  init_src4();
76805
77440
  init_src3();
76806
77441
 
@@ -76934,10 +77569,11 @@ function nativeDispatchViaLabel(host = detectNativeHost()) {
76934
77569
 
76935
77570
  // apps/cli/src/handlers/dispatch.ts
76936
77571
  init_mcp_context();
77572
+ init_orchestrator_precondition_runner();
76937
77573
  init_native_tasks();
76938
77574
  init_dispatch_prompt_storage();
76939
77575
  init_dispatch_prompt_cache();
76940
- var import_fs79 = require("fs");
77576
+ var import_fs80 = require("fs");
76941
77577
 
76942
77578
  // apps/cli/src/handlers/relay-tasks.ts
76943
77579
  init_mcp_context();
@@ -77108,7 +77744,7 @@ function tryWarmCacheHit(liveTaskBlock, cacheKey2, promptFormat) {
77108
77744
  const cached4 = getCachedPrompt(cacheKey2);
77109
77745
  if (!cached4) return null;
77110
77746
  if (cached4.skillFingerprint !== cacheKey2.skillFingerprint) return null;
77111
- if (!(0, import_fs79.existsSync)(cached4.skillsSectionPath)) return null;
77747
+ if (!(0, import_fs80.existsSync)(cached4.skillsSectionPath)) return null;
77112
77748
  try {
77113
77749
  const skillsSection = require("fs").readFileSync(cached4.skillsSectionPath, "utf8");
77114
77750
  return skillsSection + liveTaskBlock;
@@ -77185,9 +77821,9 @@ function formatFalsifiedNote(block, verdicts) {
77185
77821
  }
77186
77822
  function writePremiseVerificationLog(projectRoot, taskId, result, opts) {
77187
77823
  try {
77188
- const logPath = (0, import_path85.join)(projectRoot, PREMISE_VERIFICATION_LOG);
77824
+ const logPath = (0, import_path86.join)(projectRoot, PREMISE_VERIFICATION_LOG);
77189
77825
  rotateIfNeeded2(logPath, MAX_PREMISE_VERIFICATION_BYTES);
77190
- (0, import_fs78.mkdirSync)((0, import_path85.join)(projectRoot, ".gossip"), { recursive: true });
77826
+ (0, import_fs79.mkdirSync)((0, import_path86.join)(projectRoot, ".gossip"), { recursive: true });
77191
77827
  const row = {
77192
77828
  ts: (/* @__PURE__ */ new Date()).toISOString(),
77193
77829
  consensus_id: null,
@@ -77201,7 +77837,7 @@ function writePremiseVerificationLog(projectRoot, taskId, result, opts) {
77201
77837
  skill_bound: opts.skill_bound
77202
77838
  };
77203
77839
  if (opts.schema_lint) row.schema_lint = opts.schema_lint;
77204
- (0, import_fs78.appendFileSync)(logPath, JSON.stringify(row) + "\n");
77840
+ (0, import_fs79.appendFileSync)(logPath, JSON.stringify(row) + "\n");
77205
77841
  } catch {
77206
77842
  }
77207
77843
  }
@@ -77313,7 +77949,7 @@ var AGENT_PROVIDER_MAP = {
77313
77949
  };
77314
77950
  function readQuotaState() {
77315
77951
  try {
77316
- const raw = (0, import_fs78.readFileSync)((0, import_path85.join)(process.cwd(), ".gossip", "quota-state.json"), "utf8");
77952
+ const raw = (0, import_fs79.readFileSync)((0, import_path86.join)(process.cwd(), ".gossip", "quota-state.json"), "utf8");
77317
77953
  return JSON.parse(raw);
77318
77954
  } catch {
77319
77955
  return {};
@@ -77379,6 +78015,19 @@ async function handleDispatchSingle(agent_id, task, write_mode, scope, timeout_m
77379
78015
  const relayToken = (0, import_crypto34.randomUUID)().slice(0, 12);
77380
78016
  const timeoutMs = timeout_ms ?? NATIVE_TASK_TTL_MS;
77381
78017
  stashDispatchWarnings([taskId], dispatchWarnings);
78018
+ runDispatchPreconditionGuard({
78019
+ projectRoot: process.cwd(),
78020
+ taskId,
78021
+ resolutionRoots,
78022
+ taskText: task,
78023
+ writeMode: write_mode
78024
+ }).then(({ warnings: precondWarnings }) => {
78025
+ for (const w of precondWarnings) {
78026
+ process.stderr.write(`[gossipcat] \u26A0\uFE0F precondition: ${w}
78027
+ `);
78028
+ }
78029
+ }).catch(() => {
78030
+ });
77382
78031
  const premiseResult = await maybeVerifyPremiseClaims(task, process.cwd(), taskId, agent_id);
77383
78032
  task = premiseResult.annotatedTask;
77384
78033
  if (premiseResult.signals.length > 0) {
@@ -77796,6 +78445,24 @@ Task: ${def.task}`;
77796
78445
  }
77797
78446
  }
77798
78447
  stashDispatchWarnings(allParallelTaskIds, dispatchWarnings);
78448
+ if (allParallelTaskIds.length > 0) {
78449
+ runDispatchPreconditionGuard({
78450
+ projectRoot: process.cwd(),
78451
+ taskId: allParallelTaskIds[0],
78452
+ resolutionRoots: effectiveResolutionRoots,
78453
+ taskText: taskDefs[0]?.task ?? "",
78454
+ writeMode: taskDefs[0]?.write_mode,
78455
+ // Bug A follow-up (Fix 1): scan ALL tasks for referenced paths, not just
78456
+ // taskDefs[0]. Stale-base/mid-flight stay one-per-dispatch above.
78457
+ additionalTasks: taskDefs.slice(1).map((d) => ({ taskText: d.task ?? "", writeMode: d.write_mode }))
78458
+ }).then(({ warnings: precondWarnings }) => {
78459
+ for (const w of precondWarnings) {
78460
+ process.stderr.write(`[gossipcat] \u26A0\uFE0F precondition: ${w}
78461
+ `);
78462
+ }
78463
+ }).catch(() => {
78464
+ });
78465
+ }
77799
78466
  const parallelHost = detectNativeHost();
77800
78467
  let msg = "";
77801
78468
  if (nativeInstructions.length > 0) {
@@ -77874,8 +78541,8 @@ async function handleDispatchConsensus(taskDefs, _utility_task_id, dispatchResol
77874
78541
  });
77875
78542
  const lenses = await Promise.race([
77876
78543
  lensPromise,
77877
- new Promise((resolve32) => {
77878
- timerId = setTimeout(() => resolve32(null), LENS_TIMEOUT_MS);
78544
+ new Promise((resolve33) => {
78545
+ timerId = setTimeout(() => resolve33(null), LENS_TIMEOUT_MS);
77879
78546
  })
77880
78547
  ]);
77881
78548
  if (timerId) clearTimeout(timerId);
@@ -78031,6 +78698,24 @@ Task: ${def.task}`;
78031
78698
  }
78032
78699
  }
78033
78700
  stashDispatchWarnings(allTaskIds, dispatchRoundWarnings);
78701
+ if (allTaskIds.length > 0) {
78702
+ runDispatchPreconditionGuard({
78703
+ projectRoot: process.cwd(),
78704
+ taskId: allTaskIds[0],
78705
+ resolutionRoots: dispatchResolutionRoots,
78706
+ taskText: taskDefs[0]?.task ?? "",
78707
+ writeMode: taskDefs[0]?.write_mode,
78708
+ // Bug A follow-up (Fix 1): scan ALL tasks for referenced paths, not just
78709
+ // taskDefs[0]. Stale-base/mid-flight stay one-per-dispatch above.
78710
+ additionalTasks: taskDefs.slice(1).map((d) => ({ taskText: d.task ?? "", writeMode: d.write_mode }))
78711
+ }).then(({ warnings: precondWarnings }) => {
78712
+ for (const w of precondWarnings) {
78713
+ process.stderr.write(`[gossipcat] \u26A0\uFE0F precondition: ${w}
78714
+ `);
78715
+ }
78716
+ }).catch(() => {
78717
+ });
78718
+ }
78034
78719
  const consensusHost = detectNativeHost();
78035
78720
  const nativeTool = nativeToolName(consensusHost);
78036
78721
  const collectCall = `gossip_collect(task_ids: [${allTaskIds.map((id) => `"${id}"`).join(", ")}], consensus: true)`;
@@ -78080,6 +78765,70 @@ ${p.prompt}` });
78080
78765
  return dispatchWarnings.length > 0 ? { content, warnings: dispatchWarnings } : { content };
78081
78766
  }
78082
78767
 
78768
+ // apps/cli/src/handlers/ask-back.ts
78769
+ var import_fs81 = require("fs");
78770
+ var import_path87 = require("path");
78771
+ var LEDGER_REL = (0, import_path87.join)(".gossip", "fabrication-introspections.jsonl");
78772
+ var MAX_INTROSPECTION_BYTES = 5 * 1024 * 1024;
78773
+ function ledgerPath(projectRoot) {
78774
+ return (0, import_path87.join)(projectRoot, LEDGER_REL);
78775
+ }
78776
+ function buildIntrospectionPrompt(claim, groundTruth) {
78777
+ return [
78778
+ "You are being asked to help improve the reliability of this review pipeline.",
78779
+ "",
78780
+ "A prior response from you was identified as a fabrication:",
78781
+ ` Claim made: ${claim}`,
78782
+ ` Ground truth: ${groundTruth}`,
78783
+ "",
78784
+ "Please reflect on the specific process failure that led to this.",
78785
+ "Do not apologize \u2014 instead, name the exact mechanism: for example,",
78786
+ '"I pattern-matched the task framing and assumed the identifier existed"',
78787
+ 'or "I cited from memory without opening the file to verify".',
78788
+ "",
78789
+ "Your answer should be one to three sentences describing the HOW and WHY",
78790
+ "of the specific reasoning step that went wrong."
78791
+ ].join("\n");
78792
+ }
78793
+ function appendIntrospection(projectRoot, record2, deps) {
78794
+ if (typeof record2.agentId !== "string" || !record2.agentId || typeof record2.status !== "string" || !record2.status) {
78795
+ return;
78796
+ }
78797
+ if (record2.status === "asked") {
78798
+ if (typeof record2.claim !== "string" || !record2.claim.trim() || typeof record2.groundTruth !== "string" || !record2.groundTruth.trim()) {
78799
+ return;
78800
+ }
78801
+ }
78802
+ const clean = {
78803
+ agentId: record2.agentId,
78804
+ claim: record2.claim,
78805
+ groundTruth: record2.groundTruth,
78806
+ status: record2.status
78807
+ };
78808
+ if (record2.askedAt !== void 0) clean["askedAt"] = record2.askedAt;
78809
+ if (record2.findingId !== void 0) clean["findingId"] = record2.findingId;
78810
+ if (record2.answer !== void 0) clean["answer"] = record2.answer;
78811
+ if (record2.answeredAt !== void 0) clean["answeredAt"] = record2.answeredAt;
78812
+ const line = JSON.stringify(clean) + "\n";
78813
+ const path8 = ledgerPath(projectRoot);
78814
+ try {
78815
+ const fsMkdir = deps?.mkdirSync ?? import_fs81.mkdirSync;
78816
+ const fsAppend = deps?.appendFileSync ?? import_fs81.appendFileSync;
78817
+ const fsStat = deps?.statSync ?? import_fs81.statSync;
78818
+ const fsRename = deps?.renameSync ?? import_fs81.renameSync;
78819
+ fsMkdir((0, import_path87.join)(projectRoot, ".gossip"), { recursive: true });
78820
+ try {
78821
+ const st = fsStat(path8);
78822
+ if (st.size >= MAX_INTROSPECTION_BYTES) {
78823
+ fsRename(path8, path8 + ".1");
78824
+ }
78825
+ } catch {
78826
+ }
78827
+ fsAppend(path8, line);
78828
+ } catch {
78829
+ }
78830
+ }
78831
+
78083
78832
  // apps/cli/src/mcp-server-sdk.ts
78084
78833
  init_dispatch_prompt_cache();
78085
78834
 
@@ -78120,6 +78869,7 @@ function discoverVerifier(agents, override) {
78120
78869
  init_src4();
78121
78870
  var import_node_fs = require("node:fs");
78122
78871
  var import_node_path = require("node:path");
78872
+ init_orchestrator_precondition_runner();
78123
78873
  function scheduleSkillRunner(c, mainAgent) {
78124
78874
  if (!c.skillEngine) return;
78125
78875
  const skillEngine = c.skillEngine;
@@ -78263,7 +79013,7 @@ Relay may be down. Check gossip_status() for connection state.` }] };
78263
79013
  process.stderr.write(`[gossipcat] \u23F3 Consensus: ${doneCount}/${pendingNativeIds.length} agents complete (${agentStatus})
78264
79014
  `);
78265
79015
  }
78266
- await new Promise((resolve32) => setTimeout(resolve32, POLL_INTERVAL));
79016
+ await new Promise((resolve33) => setTimeout(resolve33, POLL_INTERVAL));
78267
79017
  }
78268
79018
  const arrived = pendingNativeIds.filter((id) => ctx.nativeResultMap.has(id)).length;
78269
79019
  const timedOutCount = pendingNativeIds.filter((id) => {
@@ -78645,6 +79395,7 @@ ${t.skillWarnings.map((w) => ` - ${w}`).join("\n")}`;
78645
79395
  relayCrossReviewSkipped
78646
79396
  );
78647
79397
  } else {
79398
+ const roundStartSha = captureHeadSha(process.cwd());
78648
79399
  ctx.pendingConsensusRounds.set(consensusId, {
78649
79400
  consensusId,
78650
79401
  allResults: allResults.filter((r) => r.status === "completed"),
@@ -78668,7 +79419,12 @@ ${t.skillWarnings.map((w) => ` - ${w}`).join("\n")}`;
78668
79419
  // warnings + read its roots. The flat resolutionRoots above stays
78669
79420
  // populated in parallel for old-reader back-compat. PR-C: this is
78670
79421
  // always a concrete RoundContext (the engine now requires one).
78671
- roundContext: effectiveRound
79422
+ roundContext: effectiveRound,
79423
+ // UNIT 3: capture HEAD SHA at Phase 2 start for mid_flight_fixup detection.
79424
+ // Best-effort — undefined when git is unavailable (never blocks the round).
79425
+ // FIX 2: hoisted out of the set() literal so execFileSync does not block
79426
+ // the MCP handler inline inside the Map mutation.
79427
+ roundStartSha
78672
79428
  });
78673
79429
  const recentTaskIds = [
78674
79430
  ...allResults.filter((r) => r.status === "completed").map((r) => r.id)
@@ -78855,7 +79611,7 @@ ${np.user}
78855
79611
  const autoResolveEnabled = cfgPathAr?.consensus?.autoResolveOnRoundClose !== false;
78856
79612
  if (autoResolveEnabled) {
78857
79613
  const { resolveFindings: rf } = await Promise.resolve().then(() => (init_src4(), src_exports3));
78858
- const resolveResult = await rf(process.cwd(), { lineAnchored: cfgPathAr?.consensus?.resolverLineAnchored ?? false });
79614
+ const resolveResult = await rf(process.cwd(), { lineAnchored: cfgPathAr?.consensus?.resolverLineAnchored ?? true });
78859
79615
  if (resolveResult.ok) {
78860
79616
  if (resolveResult.resolved > 0) {
78861
79617
  process.stderr.write(
@@ -79158,19 +79914,19 @@ function filterWatchEvents(rawJsonl, opts) {
79158
79914
  }
79159
79915
 
79160
79916
  // apps/cli/src/stickyPort.ts
79161
- var import_fs82 = require("fs");
79162
- var import_path88 = require("path");
79917
+ var import_fs84 = require("fs");
79918
+ var import_path90 = require("path");
79163
79919
  var import_net = require("net");
79164
- var RELAY_STICKY_FILE = (0, import_path88.join)(".gossip", "relay.port");
79165
- var HTTP_MCP_STICKY_FILE = (0, import_path88.join)(".gossip", "http-mcp.port");
79920
+ var RELAY_STICKY_FILE = (0, import_path90.join)(".gossip", "relay.port");
79921
+ var HTTP_MCP_STICKY_FILE = (0, import_path90.join)(".gossip", "http-mcp.port");
79166
79922
  function stickyPath(filename) {
79167
- return (0, import_path88.join)(process.cwd(), filename);
79923
+ return (0, import_path90.join)(process.cwd(), filename);
79168
79924
  }
79169
79925
  function readStickyPort(filename) {
79170
79926
  const p = stickyPath(filename);
79171
- if (!(0, import_fs82.existsSync)(p)) return null;
79927
+ if (!(0, import_fs84.existsSync)(p)) return null;
79172
79928
  try {
79173
- const raw = (0, import_fs82.readFileSync)(p, "utf-8").trim();
79929
+ const raw = (0, import_fs84.readFileSync)(p, "utf-8").trim();
79174
79930
  const n = parseInt(raw, 10);
79175
79931
  if (!Number.isFinite(n) || n < 1 || n > 65535) return null;
79176
79932
  return n;
@@ -79182,13 +79938,13 @@ function writeStickyPort(filename, port) {
79182
79938
  if (!Number.isFinite(port) || port < 1 || port > 65535) return;
79183
79939
  const p = stickyPath(filename);
79184
79940
  try {
79185
- (0, import_fs82.mkdirSync)((0, import_path88.dirname)(p), { recursive: true });
79186
- (0, import_fs82.writeFileSync)(p, String(port), "utf-8");
79941
+ (0, import_fs84.mkdirSync)((0, import_path90.dirname)(p), { recursive: true });
79942
+ (0, import_fs84.writeFileSync)(p, String(port), "utf-8");
79187
79943
  } catch {
79188
79944
  }
79189
79945
  }
79190
79946
  function probePort(port, host = "127.0.0.1") {
79191
- return new Promise((resolve32) => {
79947
+ return new Promise((resolve33) => {
79192
79948
  const srv = (0, import_net.createServer)();
79193
79949
  let settled = false;
79194
79950
  const done = (ok) => {
@@ -79198,7 +79954,7 @@ function probePort(port, host = "127.0.0.1") {
79198
79954
  srv.close();
79199
79955
  } catch {
79200
79956
  }
79201
- resolve32(ok);
79957
+ resolve33(ok);
79202
79958
  };
79203
79959
  srv.once("error", () => done(false));
79204
79960
  try {
@@ -79256,20 +80012,20 @@ function mergeSetupConfig(input) {
79256
80012
  function buildMalformedConfigHint(configPath, message) {
79257
80013
  return `\u26A0\uFE0F config.json is malformed: ${message} \u2014 fix or delete ${configPath}`;
79258
80014
  }
79259
- function flushStagedAgentFileWrites(writes, fs6) {
80015
+ function flushStagedAgentFileWrites(writes, fs7) {
79260
80016
  for (const w of writes) {
79261
- fs6.mkdirSync(w.dir, { recursive: true });
79262
- fs6.writeFileSync(w.path, w.content, "utf-8");
80017
+ fs7.mkdirSync(w.dir, { recursive: true });
80018
+ fs7.writeFileSync(w.path, w.content, "utf-8");
79263
80019
  }
79264
80020
  }
79265
80021
 
79266
80022
  // apps/cli/src/native-agent-cache.ts
79267
- var import_fs83 = require("fs");
79268
- var import_path89 = require("path");
80023
+ var import_fs85 = require("fs");
80024
+ var import_path91 = require("path");
79269
80025
  var realFs = {
79270
- existsSync: import_fs83.existsSync,
79271
- readFileSync: import_fs83.readFileSync,
79272
- statSync: (p) => ({ mtimeMs: (0, import_fs83.statSync)(p).mtimeMs })
80026
+ existsSync: import_fs85.existsSync,
80027
+ readFileSync: import_fs85.readFileSync,
80028
+ statSync: (p) => ({ mtimeMs: (0, import_fs85.statSync)(p).mtimeMs })
79273
80029
  };
79274
80030
  function modelTierFromId(modelId) {
79275
80031
  if (modelId.includes("opus")) return "opus";
@@ -79277,16 +80033,16 @@ function modelTierFromId(modelId) {
79277
80033
  if (modelId.includes("fable")) return "fable";
79278
80034
  return "sonnet";
79279
80035
  }
79280
- function refreshNativeAgentFromDisk(ac, cache3, projectRoot, fs6 = realFs) {
79281
- const claudeAgentPath = (0, import_path89.join)(projectRoot, ".claude", "agents", `${ac.id}.md`);
79282
- const instrPath = (0, import_path89.join)(projectRoot, ".gossip", "agents", ac.id, "instructions.md");
80036
+ function refreshNativeAgentFromDisk(ac, cache3, projectRoot, fs7 = realFs) {
80037
+ const claudeAgentPath = (0, import_path91.join)(projectRoot, ".claude", "agents", `${ac.id}.md`);
80038
+ const instrPath = (0, import_path91.join)(projectRoot, ".gossip", "agents", ac.id, "instructions.md");
79283
80039
  const prev = cache3.get(ac.id);
79284
80040
  let sourcePath = null;
79285
80041
  let stripFrontmatter = false;
79286
- if (fs6.existsSync(claudeAgentPath)) {
80042
+ if (fs7.existsSync(claudeAgentPath)) {
79287
80043
  sourcePath = claudeAgentPath;
79288
80044
  stripFrontmatter = true;
79289
- } else if (fs6.existsSync(instrPath)) {
80045
+ } else if (fs7.existsSync(instrPath)) {
79290
80046
  sourcePath = instrPath;
79291
80047
  stripFrontmatter = false;
79292
80048
  }
@@ -79305,7 +80061,7 @@ function refreshNativeAgentFromDisk(ac, cache3, projectRoot, fs6 = realFs) {
79305
80061
  }
79306
80062
  let currentMtimeMs;
79307
80063
  try {
79308
- currentMtimeMs = fs6.statSync(sourcePath).mtimeMs;
80064
+ currentMtimeMs = fs7.statSync(sourcePath).mtimeMs;
79309
80065
  } catch {
79310
80066
  if (prev && prev.instructions.length > 0) {
79311
80067
  return;
@@ -79321,7 +80077,7 @@ function refreshNativeAgentFromDisk(ac, cache3, projectRoot, fs6 = realFs) {
79321
80077
  if (prev && prev.cachedMtimeMs === currentMtimeMs) {
79322
80078
  return;
79323
80079
  }
79324
- let instructions = fs6.readFileSync(sourcePath, "utf-8");
80080
+ let instructions = fs7.readFileSync(sourcePath, "utf-8");
79325
80081
  if (stripFrontmatter) {
79326
80082
  instructions = instructions.replace(/^---\n[\s\S]*?\n---\n*/, "").trim();
79327
80083
  }
@@ -79338,22 +80094,22 @@ function refreshNativeAgentFromDisk(ac, cache3, projectRoot, fs6 = realFs) {
79338
80094
  }
79339
80095
 
79340
80096
  // apps/cli/src/rules-content.ts
79341
- var import_fs84 = require("fs");
79342
- var import_path90 = require("path");
80097
+ var import_fs86 = require("fs");
80098
+ var import_path92 = require("path");
79343
80099
  var AGENT_LIST_PLACEHOLDER = "{{AGENT_LIST}}";
79344
80100
  function resolveRulesPath(host = detectNativeHost()) {
79345
80101
  const fileName = host === "cursor" ? "CURSOR_RULES.md" : "RULES.md";
79346
80102
  const candidates = [
79347
- (0, import_path90.join)(process.cwd(), "docs", fileName),
79348
- (0, import_path90.join)(__dirname, "..", "docs", fileName),
79349
- (0, import_path90.join)(__dirname, "docs", fileName),
80103
+ (0, import_path92.join)(process.cwd(), "docs", fileName),
80104
+ (0, import_path92.join)(__dirname, "..", "docs", fileName),
80105
+ (0, import_path92.join)(__dirname, "docs", fileName),
79350
80106
  // Fallback: bundled RULES.md when CURSOR_RULES.md not yet shipped
79351
80107
  ...host === "cursor" ? [
79352
- (0, import_path90.join)(process.cwd(), "docs", "RULES.md"),
79353
- (0, import_path90.join)(__dirname, "..", "docs", "RULES.md")
80108
+ (0, import_path92.join)(process.cwd(), "docs", "RULES.md"),
80109
+ (0, import_path92.join)(__dirname, "..", "docs", "RULES.md")
79354
80110
  ] : []
79355
80111
  ];
79356
- return candidates.find((p) => (0, import_fs84.existsSync)(p)) ?? null;
80112
+ return candidates.find((p) => (0, import_fs86.existsSync)(p)) ?? null;
79357
80113
  }
79358
80114
  function generateRulesContent(agentList, host) {
79359
80115
  const resolvedHost = host ?? detectNativeHost();
@@ -79363,7 +80119,7 @@ function generateRulesContent(agentList, host) {
79363
80119
  `[gossipcat] generateRulesContent: docs/RULES.md not found for host=${resolvedHost} (cwd=${process.cwd()}, dirname=${__dirname}). Expected docs/RULES.md or docs/CURSOR_RULES.md tracked in the gossipcat repo or shipped alongside the MCP bundle.`
79364
80120
  );
79365
80121
  }
79366
- let template = (0, import_fs84.readFileSync)(rulesPath, "utf-8");
80122
+ let template = (0, import_fs86.readFileSync)(rulesPath, "utf-8");
79367
80123
  if (resolvedHost === "cursor" && rulesPath.endsWith("RULES.md")) {
79368
80124
  template = template.replace(/Agent\(\)/g, "Task()").replace(/Agent\(/g, "Task(").replace(/Claude Code/g, "Cursor");
79369
80125
  }
@@ -79463,7 +80219,7 @@ var __argvShimHandled = (() => {
79463
80219
  }
79464
80220
  if (kind === "help") {
79465
80221
  process.stdout.write(
79466
- "gossipcat \u2014 Multi-Agent Orchestration\n\nUsage:\n gossipcat Start MCP server (for Claude Code / Cursor)\n gossipcat hook --run Run UserPromptSubmit bootstrap hook (internal)\n gossipcat hook mirror-prompt|mirror-stop|mirror-tool Activity-mirror hooks (internal; opt-in via gossip_setup mirror_hooks)\n gossipcat key set <provider> Store an API key in the OS keychain (service: gossip-mesh)\n gossipcat key list Show which providers have a stored key\n gossipcat code [args...] Launch Claude Code with the gossipcat channel active\n gossipcat help Show this help\n\nThe published binary is the MCP server bundle. The full CLI\n(setup wizard, create-agent, chat, etc.) lives in apps/cli/src/index.ts\nand is available via `npm start` / `npx ts-node` in the source repo.\nThe `code` subcommand is available in the published binary.\n"
80222
+ "gossipcat \u2014 Multi-Agent Orchestration\n\nUsage:\n gossipcat Start MCP server (for Claude Code / Cursor)\n gossipcat hook --run Run UserPromptSubmit bootstrap hook (internal)\n gossipcat hook mirror-prompt|mirror-stop|mirror-tool Activity-mirror hooks (internal; opt-in via gossip_setup mirror_hooks)\n gossipcat key set <provider> Store an API key in the OS keychain (service: gossip-mesh)\n gossipcat key list Show which providers have a stored key\n gossipcat code [args...] Launch Claude Code with the gossipcat channel active\n Note: <cwd>/.mcp.json is treated as trusted config (server name is read from it).\n gossipcat help Show this help\n\nThe published binary is the MCP server bundle. The full CLI\n(setup wizard, create-agent, chat, etc.) lives in apps/cli/src/index.ts\nand is available via `npm start` / `npx ts-node` in the source repo.\nThe `code` subcommand is available in the published binary.\n"
79467
80223
  );
79468
80224
  process.exit(0);
79469
80225
  }
@@ -79511,15 +80267,15 @@ var __argvShimHandled = (() => {
79511
80267
  function readSecretFromStdin() {
79512
80268
  const stdin = process.stdin;
79513
80269
  if (!stdin.isTTY) {
79514
- return new Promise((resolve32, reject) => {
80270
+ return new Promise((resolve33, reject) => {
79515
80271
  const chunks = [];
79516
80272
  stdin.on("data", (c) => chunks.push(c));
79517
- stdin.on("end", () => resolve32(Buffer.concat(chunks).toString("utf8")));
80273
+ stdin.on("end", () => resolve33(Buffer.concat(chunks).toString("utf8")));
79518
80274
  stdin.on("error", (e) => reject(e));
79519
80275
  stdin.resume();
79520
80276
  });
79521
80277
  }
79522
- return new Promise((resolve32) => {
80278
+ return new Promise((resolve33) => {
79523
80279
  process.stderr.write("Paste the API key, then Enter: ");
79524
80280
  let buf = "";
79525
80281
  const wasRaw = stdin.isRaw === true;
@@ -79534,7 +80290,7 @@ function readSecretFromStdin() {
79534
80290
  stdin.pause();
79535
80291
  stdin.removeListener("data", onData);
79536
80292
  process.stderr.write("\n");
79537
- resolve32(buf);
80293
+ resolve33(buf);
79538
80294
  return;
79539
80295
  } else if (code === 3) {
79540
80296
  stdin.setRawMode(wasRaw);
@@ -79553,12 +80309,12 @@ function readSecretFromStdin() {
79553
80309
  });
79554
80310
  }
79555
80311
  if (process.env.GOSSIPCAT_MCP_NO_MAIN !== "1" && !__argvShimHandled) {
79556
- const gossipDir = (0, import_path95.join)(process.cwd(), ".gossip");
80312
+ const gossipDir = (0, import_path97.join)(process.cwd(), ".gossip");
79557
80313
  try {
79558
- (0, import_fs89.mkdirSync)(gossipDir, { recursive: true });
80314
+ (0, import_fs91.mkdirSync)(gossipDir, { recursive: true });
79559
80315
  } catch {
79560
80316
  }
79561
- const logStream = (0, import_fs89.createWriteStream)((0, import_path95.join)(gossipDir, "mcp.log"), { flags: "a", mode: 384 });
80317
+ const logStream = (0, import_fs91.createWriteStream)((0, import_path97.join)(gossipDir, "mcp.log"), { flags: "a", mode: 384 });
79562
80318
  process.stderr.write = ((chunk, ...args) => {
79563
80319
  return logStream.write(chunk, ...args);
79564
80320
  });
@@ -79569,7 +80325,7 @@ try {
79569
80325
  } catch {
79570
80326
  }
79571
80327
  function memoryDirForProject(cwd) {
79572
- return (0, import_path95.join)((0, import_os8.homedir)(), ".claude", "projects", cwd.replaceAll("/", "-"), "memory");
80328
+ return (0, import_path97.join)((0, import_os8.homedir)(), ".claude", "projects", cwd.replaceAll("/", "-"), "memory");
79573
80329
  }
79574
80330
  function dashboardClickableUrl(url2, key) {
79575
80331
  if (!key) return url2;
@@ -79644,14 +80400,14 @@ var _pendingPlanData = /* @__PURE__ */ new Map();
79644
80400
  var _utilityGuardSnapshots = /* @__PURE__ */ new Map();
79645
80401
  var _modules = null;
79646
80402
  function lookupFindingSeverity(findingId, projectRoot) {
79647
- const { existsSync: existsSync73, readdirSync: readdirSync22, readFileSync: readFileSync69 } = require("fs");
79648
- const { join: join91 } = require("path");
79649
- const reportsDir = join91(projectRoot, ".gossip", "consensus-reports");
79650
- if (!existsSync73(reportsDir)) return null;
80403
+ const { existsSync: existsSync74, readdirSync: readdirSync22, readFileSync: readFileSync70 } = require("fs");
80404
+ const { join: join93 } = require("path");
80405
+ const reportsDir = join93(projectRoot, ".gossip", "consensus-reports");
80406
+ if (!existsSync74(reportsDir)) return null;
79651
80407
  try {
79652
80408
  const files = readdirSync22(reportsDir).filter((f) => f.endsWith(".json"));
79653
80409
  for (const file2 of files) {
79654
- const report = JSON.parse(readFileSync69(join91(reportsDir, file2), "utf-8"));
80410
+ const report = JSON.parse(readFileSync70(join93(reportsDir, file2), "utf-8"));
79655
80411
  for (const bucket of ["confirmed", "disputed", "unverified", "unique"]) {
79656
80412
  for (const finding of report[bucket] || []) {
79657
80413
  if (finding.id === findingId && finding.severity) {
@@ -79750,7 +80506,7 @@ async function doBoot() {
79750
80506
  const agentConfigs = m.configToAgentConfigs(config2);
79751
80507
  ctx.keychain = new m.Keychain();
79752
80508
  const { existsSync: pidExists, readFileSync: readPid, writeFileSync: writePid, unlinkSync: delPid } = require("fs");
79753
- const pidFile = (0, import_path95.join)(process.cwd(), ".gossip", "relay.pid");
80509
+ const pidFile = (0, import_path97.join)(process.cwd(), ".gossip", "relay.pid");
79754
80510
  if (pidExists(pidFile)) {
79755
80511
  const oldPid = parseInt(readPid(pidFile, "utf-8").trim(), 10);
79756
80512
  if (!isNaN(oldPid) && oldPid !== process.pid) {
@@ -79872,10 +80628,10 @@ async function doBoot() {
79872
80628
  { id: ac.id, provider: ac.provider, model: ac.model, base_url: ac.base_url, key_ref: ac.key_ref },
79873
80629
  (s) => ctx.keychain.getKey(s)
79874
80630
  );
79875
- const { existsSync: existsSync73, readFileSync: readFileSync69 } = require("fs");
79876
- const { join: join91 } = require("path");
79877
- const instructionsPath = join91(process.cwd(), ".gossip", "agents", ac.id, "instructions.md");
79878
- const baseInstructions = existsSync73(instructionsPath) ? readFileSync69(instructionsPath, "utf-8") : "";
80631
+ const { existsSync: existsSync74, readFileSync: readFileSync70 } = require("fs");
80632
+ const { join: join93 } = require("path");
80633
+ const instructionsPath = join93(process.cwd(), ".gossip", "agents", ac.id, "instructions.md");
80634
+ const baseInstructions = existsSync74(instructionsPath) ? readFileSync70(instructionsPath, "utf-8") : "";
79879
80635
  const identity = ctx.identityRegistry.get(ac.id);
79880
80636
  const identityBlock = identity ? m.formatIdentityBlock(identity) + "\n" : "";
79881
80637
  const instructions = (identityBlock + baseInstructions).trim() || void 0;
@@ -80804,6 +81560,70 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
80804
81560
  };
80805
81561
  }
80806
81562
  );
81563
+ server.tool(
81564
+ "gossip_ask_back",
81565
+ `Re-engage an agent after a fabrication (hallucination_caught) for first-person root-cause analysis. action:"ask" dispatches an introspection prompt to the agent and logs the event; action:"record" stores the agent's answer. Builds a rich failure ledger (.gossip/fabrication-introspections.jsonl) that feeds skill development.`,
81566
+ {
81567
+ action: external_exports.enum(["ask", "record"]).default("ask").describe(`"ask" (default): dispatch an introspection prompt to the agent. "record": store the agent's answer.`),
81568
+ agent_id: external_exports.string().describe("The agent that produced the fabrication."),
81569
+ claim: external_exports.string().optional().describe('Required for action:"ask". The fabricated claim the agent made.'),
81570
+ ground_truth: external_exports.string().optional().describe('Required for action:"ask". What the code/evidence actually shows.'),
81571
+ finding_id: external_exports.string().optional().describe("Optional consensus finding_id (format: <consensus_id>:<agent:fN>) to link the introspection to a specific finding."),
81572
+ answer: external_exports.string().optional().describe(`Required for action:"record". The agent's root-cause explanation.`)
81573
+ },
81574
+ async ({ action, agent_id, claim, ground_truth, finding_id, answer }) => {
81575
+ const projectRoot = process.cwd();
81576
+ const now = (/* @__PURE__ */ new Date()).toISOString();
81577
+ if (action === "ask") {
81578
+ if (!claim || !ground_truth) {
81579
+ return {
81580
+ content: [{ type: "text", text: 'gossip_ask_back error: action:"ask" requires both claim and ground_truth.' }],
81581
+ isError: true
81582
+ };
81583
+ }
81584
+ appendIntrospection(projectRoot, {
81585
+ agentId: agent_id,
81586
+ findingId: finding_id,
81587
+ claim,
81588
+ groundTruth: ground_truth,
81589
+ status: "asked",
81590
+ askedAt: now
81591
+ });
81592
+ const prompt = buildIntrospectionPrompt(claim, ground_truth);
81593
+ const dispatchResult = await handleDispatchSingle(agent_id, prompt);
81594
+ const instruction = `After the agent answers, call gossip_ask_back(action:'record', agent_id:'${agent_id}'` + (finding_id ? `, finding_id:'${finding_id}'` : "") + `, answer:<agent response>) to log the introspection.
81595
+
81596
+ `;
81597
+ const dispatchText = dispatchResult.content.filter((c) => c.type === "text").map((c) => c.text).join("\n");
81598
+ return {
81599
+ content: [{ type: "text", text: instruction + dispatchText }]
81600
+ };
81601
+ }
81602
+ if (!answer) {
81603
+ return {
81604
+ content: [{ type: "text", text: 'gossip_ask_back error: action:"record" requires answer.' }],
81605
+ isError: true
81606
+ };
81607
+ }
81608
+ appendIntrospection(projectRoot, {
81609
+ agentId: agent_id,
81610
+ findingId: finding_id,
81611
+ claim: claim ?? "",
81612
+ groundTruth: ground_truth ?? "",
81613
+ answer,
81614
+ status: "answered",
81615
+ answeredAt: now
81616
+ });
81617
+ const ledgerPath2 = `${projectRoot}/.gossip/fabrication-introspections.jsonl`;
81618
+ return {
81619
+ content: [{
81620
+ type: "text",
81621
+ text: `Introspection recorded for ${agent_id}${finding_id ? ` (finding: ${finding_id})` : ""}.
81622
+ Ledger: ${ledgerPath2}`
81623
+ }]
81624
+ };
81625
+ }
81626
+ );
80807
81627
  server.tool(
80808
81628
  "gossip_status",
80809
81629
  "Check Gossip Mesh system status, host environment, available agents, dashboard URL/key, and agent list with provider/model/skills. Pass slim:true to skip the handbook inline (~21KB savings) on reconnect refreshes.",
@@ -80861,7 +81681,7 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
80861
81681
  }
80862
81682
  try {
80863
81683
  const { readFileSync: rfHealth } = await import("fs");
80864
- const healthPath = (0, import_path95.join)(process.cwd(), ".gossip", "skill-runner-health.json");
81684
+ const healthPath = (0, import_path97.join)(process.cwd(), ".gossip", "skill-runner-health.json");
80865
81685
  const raw = rfHealth(healthPath, "utf8");
80866
81686
  const h = JSON.parse(raw);
80867
81687
  const lastMs = h.last_run_at ? new Date(h.last_run_at).getTime() : NaN;
@@ -80877,9 +81697,9 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
80877
81697
  lines.push(" Skill graduation: never run since session start (expected after first gossip_collect)");
80878
81698
  }
80879
81699
  try {
80880
- const { readFileSync: readFileSync69 } = await import("fs");
80881
- const quotaPath = (0, import_path95.join)(process.cwd(), ".gossip", "quota-state.json");
80882
- const quotaRaw = readFileSync69(quotaPath, "utf8");
81700
+ const { readFileSync: readFileSync70 } = await import("fs");
81701
+ const quotaPath = (0, import_path97.join)(process.cwd(), ".gossip", "quota-state.json");
81702
+ const quotaRaw = readFileSync70(quotaPath, "utf8");
80883
81703
  const quotaState = JSON.parse(quotaRaw);
80884
81704
  for (const [provider, state] of Object.entries(quotaState)) {
80885
81705
  const now = Date.now();
@@ -80931,7 +81751,7 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
80931
81751
  }
80932
81752
  try {
80933
81753
  const { existsSync: hookExists } = await import("fs");
80934
- const hookScriptPath = (0, import_path95.join)(process.cwd(), ".claude", "hooks", "worktree-sandbox.sh");
81754
+ const hookScriptPath = (0, import_path97.join)(process.cwd(), ".claude", "hooks", "worktree-sandbox.sh");
80935
81755
  const { isWorktreeSandboxHookRegistered: isWorktreeSandboxHookRegistered2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
80936
81756
  if (hookExists(hookScriptPath) && !isWorktreeSandboxHookRegistered2(process.cwd())) {
80937
81757
  lines.push(" \u26A0\uFE0F Sandbox: worktree-sandbox hook installed but UNREGISTERED \u2014 run gossip_setup to re-register");
@@ -80939,21 +81759,21 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
80939
81759
  } catch {
80940
81760
  }
80941
81761
  try {
80942
- const { readdirSync: readdirSync22, statSync: statSync36, readFileSync: readFileSync69 } = await import("fs");
81762
+ const { readdirSync: readdirSync22, statSync: statSync36, readFileSync: readFileSync70 } = await import("fs");
80943
81763
  const { readJsonlWithRotated: readJsonlRotated1506 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
80944
- const reportsDir = (0, import_path95.join)(process.cwd(), ".gossip", "consensus-reports");
80945
- const perfPath = (0, import_path95.join)(process.cwd(), ".gossip", "agent-performance.jsonl");
81764
+ const reportsDir = (0, import_path97.join)(process.cwd(), ".gossip", "consensus-reports");
81765
+ const perfPath = (0, import_path97.join)(process.cwd(), ".gossip", "agent-performance.jsonl");
80946
81766
  const WINDOW_MS3 = 24 * 60 * 60 * 1e3;
80947
81767
  const now = Date.now();
80948
81768
  const recentReports = [];
80949
81769
  try {
80950
81770
  for (const fname of readdirSync22(reportsDir)) {
80951
81771
  if (!fname.endsWith(".json")) continue;
80952
- const fpath = (0, import_path95.join)(reportsDir, fname);
81772
+ const fpath = (0, import_path97.join)(reportsDir, fname);
80953
81773
  const st = statSync36(fpath);
80954
81774
  if (now - st.mtimeMs > WINDOW_MS3) continue;
80955
81775
  try {
80956
- const report = JSON.parse(readFileSync69(fpath, "utf8"));
81776
+ const report = JSON.parse(readFileSync70(fpath, "utf8"));
80957
81777
  const isEmpty = (report.confirmed?.length ?? 0) === 0 && (report.disputed?.length ?? 0) === 0 && (report.unverified?.length ?? 0) === 0 && (report.unique?.length ?? 0) === 0 && (report.newFindings?.length ?? 0) === 0 && (report.insights?.length ?? 0) === 0;
80958
81778
  if (isEmpty) continue;
80959
81779
  } catch {
@@ -81327,8 +82147,8 @@ ${body}`
81327
82147
  }
81328
82148
  return { content: [{ type: "text", text: results.join("\n") }] };
81329
82149
  }
81330
- const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45, existsSync: existsSync73 } = require("fs");
81331
- const { join: join91 } = require("path");
82150
+ const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45, existsSync: existsSync74 } = require("fs");
82151
+ const { join: join93 } = require("path");
81332
82152
  const root = process.cwd();
81333
82153
  const CLAUDE_MODEL_MAP2 = {
81334
82154
  opus: { provider: "anthropic", model: "claude-opus-4-6" },
@@ -81344,8 +82164,8 @@ ${body}`
81344
82164
  let existingConfig = {};
81345
82165
  let existingAgents = {};
81346
82166
  try {
81347
- const { readFileSync: readFileSync69 } = require("fs");
81348
- const existing = JSON.parse(readFileSync69(join91(root, ".gossip", "config.json"), "utf-8"));
82167
+ const { readFileSync: readFileSync70 } = require("fs");
82168
+ const existing = JSON.parse(readFileSync70(join93(root, ".gossip", "config.json"), "utf-8"));
81349
82169
  if (existing && typeof existing === "object" && !Array.isArray(existing)) {
81350
82170
  existingConfig = existing;
81351
82171
  if (mode === "merge") existingAgents = existing.agents || {};
@@ -81379,8 +82199,8 @@ ${body}`
81379
82199
  body
81380
82200
  ].join("\n");
81381
82201
  pendingAgentFileWrites.push({
81382
- dir: join91(root, ".claude", "agents"),
81383
- path: join91(root, ".claude", "agents", `${agent.id}.md`),
82202
+ dir: join93(root, ".claude", "agents"),
82203
+ path: join93(root, ".claude", "agents", `${agent.id}.md`),
81384
82204
  content: md
81385
82205
  });
81386
82206
  nativeCreated.push(agent.id);
@@ -81401,8 +82221,8 @@ ${body}`
81401
82221
  errors.push(`${agent.id}: custom agent requires "custom_model" field`);
81402
82222
  continue;
81403
82223
  }
81404
- const nativeFile = join91(root, ".claude", "agents", `${agent.id}.md`);
81405
- const wasNative = existingAgents[agent.id]?.native || configAgents[agent.id]?.native || existsSync73(nativeFile);
82224
+ const nativeFile = join93(root, ".claude", "agents", `${agent.id}.md`);
82225
+ const wasNative = existingAgents[agent.id]?.native || configAgents[agent.id]?.native || existsSync74(nativeFile);
81406
82226
  if (wasNative) {
81407
82227
  errors.push(`${agent.id}: cannot re-register native agent as custom \u2014 .claude/agents/${agent.id}.md exists. Remove the file first or keep it as native.`);
81408
82228
  continue;
@@ -81417,10 +82237,10 @@ ${body}`
81417
82237
  };
81418
82238
  customCreated.push(agent.id);
81419
82239
  if (agent.instructions) {
81420
- const instrDir = join91(root, ".gossip", "agents", agent.id);
82240
+ const instrDir = join93(root, ".gossip", "agents", agent.id);
81421
82241
  pendingAgentFileWrites.push({
81422
82242
  dir: instrDir,
81423
- path: join91(instrDir, "instructions.md"),
82243
+ path: join93(instrDir, "instructions.md"),
81424
82244
  content: agent.instructions
81425
82245
  });
81426
82246
  }
@@ -81439,8 +82259,8 @@ ${body}`
81439
82259
  return { content: [{ type: "text", text: `Invalid config: ${err.message}` }] };
81440
82260
  }
81441
82261
  flushStagedAgentFileWrites(pendingAgentFileWrites, { mkdirSync: mkdirSync45, writeFileSync: writeFileSync38 });
81442
- mkdirSync45(join91(root, ".gossip"), { recursive: true });
81443
- writeFileSync38(join91(root, ".gossip", "config.json"), JSON.stringify(config2, null, 2));
82262
+ mkdirSync45(join93(root, ".gossip"), { recursive: true });
82263
+ writeFileSync38(join93(root, ".gossip", "config.json"), JSON.stringify(config2, null, 2));
81444
82264
  let hookSummary = "";
81445
82265
  try {
81446
82266
  const { installWorktreeSandboxHook: installWorktreeSandboxHook2, writeOrchestratorRoleMarker: writeOrchestratorRoleMarker2 } = (init_src4(), __toCommonJS(src_exports3));
@@ -81543,8 +82363,8 @@ ${body}`
81543
82363
  }
81544
82364
  }
81545
82365
  const agentList = Object.entries(config2.agents).map(([id, a]) => `- ${id}: ${a.provider}/${a.model} (${a.preset || "custom"})${a.native ? " \u2014 native" : ""}`).join("\n");
81546
- const rulesDir = join91(root, env.rulesDir);
81547
- const rulesFile = join91(root, env.rulesFile);
82366
+ const rulesDir = join93(root, env.rulesDir);
82367
+ const rulesFile = join93(root, env.rulesFile);
81548
82368
  mkdirSync45(rulesDir, { recursive: true });
81549
82369
  writeFileSync38(rulesFile, generateRulesContent(
81550
82370
  agentList,
@@ -81853,11 +82673,11 @@ The original signal remains in the audit log but will be excluded from scoring.`
81853
82673
  const fid = finding_id.trim();
81854
82674
  const cwd = process.cwd();
81855
82675
  const findingsPath = require("path").join(cwd, ".gossip", "implementation-findings.jsonl");
81856
- const { readFileSync: readFileSync69, existsSync: existsSync73, writeFileSync: writeFileSync38, renameSync: renameSync18 } = require("fs");
81857
- if (!existsSync73(findingsPath)) {
82676
+ const { readFileSync: readFileSync70, existsSync: existsSync74, writeFileSync: writeFileSync38, renameSync: renameSync18 } = require("fs");
82677
+ if (!existsSync74(findingsPath)) {
81858
82678
  return { content: [{ type: "text", text: `No implementation-findings.jsonl found at ${findingsPath}` }] };
81859
82679
  }
81860
- const lines = readFileSync69(findingsPath, "utf-8").split("\n");
82680
+ const lines = readFileSync70(findingsPath, "utf-8").split("\n");
81861
82681
  let matched = false;
81862
82682
  let alreadyTarget = false;
81863
82683
  let matchedEntry = null;
@@ -81945,18 +82765,18 @@ The original signal remains in the audit log but will be excluded from scoring.`
81945
82765
  return { content: [{ type: "text", text: "Error: consensus_id is required for bulk_from_consensus." }] };
81946
82766
  }
81947
82767
  try {
81948
- const { readFileSync: readFileSync69 } = await import("fs");
81949
- const { join: join91 } = await import("path");
81950
- const reportPath = join91(process.cwd(), ".gossip", "consensus-reports", `${consensus_id}.json`);
82768
+ const { readFileSync: readFileSync70 } = await import("fs");
82769
+ const { join: join93 } = await import("path");
82770
+ const reportPath = join93(process.cwd(), ".gossip", "consensus-reports", `${consensus_id}.json`);
81951
82771
  let report;
81952
82772
  try {
81953
- report = JSON.parse(readFileSync69(reportPath, "utf-8"));
82773
+ report = JSON.parse(readFileSync70(reportPath, "utf-8"));
81954
82774
  } catch {
81955
82775
  return { content: [{ type: "text", text: `Error: consensus report not found: ${consensus_id}` }] };
81956
82776
  }
81957
82777
  const existingFindingIds = /* @__PURE__ */ new Set();
81958
82778
  try {
81959
- const perfPath = join91(process.cwd(), ".gossip", "agent-performance.jsonl");
82779
+ const perfPath = join93(process.cwd(), ".gossip", "agent-performance.jsonl");
81960
82780
  const { readJsonlWithRotated: readJsonlRotated2570 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
81961
82781
  const lines = readJsonlRotated2570(perfPath).split("\n").filter(Boolean);
81962
82782
  for (const line of lines) {
@@ -82571,7 +83391,7 @@ These will influence future agent selection via dispatch weighting.`;
82571
83391
  return null;
82572
83392
  }
82573
83393
  })();
82574
- const result = await resolveFindings2(process.cwd(), { full, sinceSha, lineAnchored: cfg?.consensus?.resolverLineAnchored ?? false });
83394
+ const result = await resolveFindings2(process.cwd(), { full, sinceSha, lineAnchored: cfg?.consensus?.resolverLineAnchored ?? true });
82575
83395
  if (!result.ok) {
82576
83396
  return { content: [{ type: "text", text: `Resolver skipped: ${result.reason} (another resolver run in progress; try again in a moment).` }] };
82577
83397
  }
@@ -82591,7 +83411,7 @@ These will influence future agent selection via dispatch weighting.`;
82591
83411
  if (nonZeroSkips.length > 0) {
82592
83412
  lines.push(` skipped: ${nonZeroSkips.map(([k, n]) => `${k}=${n}`).join(", ")}`);
82593
83413
  if ((result.skipReasons?.lineAnchoredOff ?? 0) > 0) {
82594
- lines.push(` (lineAnchoredOff: enable consensus.resolverLineAnchored to resolve present-elsewhere findings as stale_anchor)`);
83414
+ lines.push(` (lineAnchoredOff: consensus.resolverLineAnchored is explicitly false in your config; set it to true or remove it \u2014 it now defaults on \u2014 to resolve present-elsewhere findings as stale_anchor)`);
82595
83415
  }
82596
83416
  }
82597
83417
  return { content: [{ type: "text", text: lines.join("\n") }] };
@@ -83004,16 +83824,16 @@ ${preview}` }]
83004
83824
  const { SkillGapTracker: SkillGapTracker2, parseSkillFrontmatter: parseSkillFrontmatter2, normalizeSkillName: normalizeSkillName2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
83005
83825
  const tracker = new SkillGapTracker2(process.cwd());
83006
83826
  if (skills && skills.length > 0) {
83007
- const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45, existsSync: existsSync73, readFileSync: readFileSync69 } = require("fs");
83008
- const { join: join91 } = require("path");
83009
- const dir = join91(process.cwd(), ".gossip", "skills");
83827
+ const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45, existsSync: existsSync74, readFileSync: readFileSync70 } = require("fs");
83828
+ const { join: join93 } = require("path");
83829
+ const dir = join93(process.cwd(), ".gossip", "skills");
83010
83830
  mkdirSync45(dir, { recursive: true });
83011
83831
  const results = [];
83012
83832
  for (const sk of skills) {
83013
83833
  const name = normalizeSkillName2(sk.name);
83014
- const filePath = join91(dir, `${name}.md`);
83015
- if (existsSync73(filePath)) {
83016
- const existing = readFileSync69(filePath, "utf-8");
83834
+ const filePath = join93(dir, `${name}.md`);
83835
+ if (existsSync74(filePath)) {
83836
+ const existing = readFileSync70(filePath, "utf-8");
83017
83837
  const fm = parseSkillFrontmatter2(existing);
83018
83838
  if (fm) {
83019
83839
  if (fm.generated_by === "manual") {
@@ -83737,7 +84557,8 @@ Paste this entire block into any Agent() prompt that should produce parseable fi
83737
84557
  { name: "gossip_watch", desc: "Pull signals recorded since a cursor timestamp. Stateless, cursor-based; max 24h lookback. Use to see consensus signals as they land." },
83738
84558
  { name: "gossip_reload", desc: "Terminate MCP server so Claude Code respawns with fresh bundle. Use after npm run build:mcp." },
83739
84559
  { name: "gossip_format", desc: "Return the CONSENSUS_OUTPUT_FORMAT block to paste into ad-hoc Agent() prompts so native subagents emit parseable <agent_finding> tags." },
83740
- { name: "gossip_bug_feedback", desc: "File a GitHub issue on the gossipcat repo from an in-session bug report. Dedupes against open issues." }
84560
+ { name: "gossip_bug_feedback", desc: "File a GitHub issue on the gossipcat repo from an in-session bug report. Dedupes against open issues." },
84561
+ { name: "gossip_ask_back", desc: 'Re-engage an agent after a fabrication for first-person root-cause analysis. action:"ask" dispatches the introspection prompt; action:"record" logs the answer.' }
83741
84562
  ];
83742
84563
  const list = tools.map((t) => `- ${t.name}: ${t.desc}`).join("\n");
83743
84564
  return { content: [{ type: "text", text: `Gossipcat Tools (${tools.length}):
@@ -83853,9 +84674,9 @@ ${p.user}
83853
84674
  max_events: external_exports.number().int().positive().max(WATCH_MAX_EVENTS).optional().describe(`Cap events returned (default ${WATCH_MAX_EVENTS}).`)
83854
84675
  },
83855
84676
  async ({ cursor, max_events }) => {
83856
- const { join: join91 } = await import("node:path");
84677
+ const { join: join93 } = await import("node:path");
83857
84678
  const { readJsonlWithRotated: readJsonlWithRotated2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
83858
- const perfPath = join91(process.cwd(), ".gossip", "agent-performance.jsonl");
84679
+ const perfPath = join93(process.cwd(), ".gossip", "agent-performance.jsonl");
83859
84680
  const raw = readJsonlWithRotated2(perfPath);
83860
84681
  const result = filterWatchEvents(raw, { cursor, maxEvents: max_events });
83861
84682
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
@@ -84002,10 +84823,10 @@ async function startHttpMcpTransport() {
84002
84823
  }
84003
84824
  let body;
84004
84825
  if (req.method === "POST") {
84005
- const raw = await new Promise((resolve32, reject) => {
84826
+ const raw = await new Promise((resolve33, reject) => {
84006
84827
  const chunks = [];
84007
84828
  req.on("data", (c) => chunks.push(c));
84008
- req.on("end", () => resolve32(Buffer.concat(chunks).toString("utf-8")));
84829
+ req.on("end", () => resolve33(Buffer.concat(chunks).toString("utf-8")));
84009
84830
  req.on("error", reject);
84010
84831
  });
84011
84832
  try {