gossipcat 0.6.6 → 0.6.7

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 });
@@ -7009,9 +7009,9 @@ var init_log = __esm({
7009
7009
  function statePath(projectRoot) {
7010
7010
  return (0, import_path4.join)(projectRoot, ".gossip", "auth-state.json");
7011
7011
  }
7012
- function readState(path7) {
7012
+ function readState(path8) {
7013
7013
  try {
7014
- return JSON.parse((0, import_fs5.readFileSync)(path7, "utf-8"));
7014
+ return JSON.parse((0, import_fs5.readFileSync)(path8, "utf-8"));
7015
7015
  } catch {
7016
7016
  return {};
7017
7017
  }
@@ -7020,33 +7020,33 @@ function recordAuthFailure(projectRoot, provider, status) {
7020
7020
  if (!projectRoot) return;
7021
7021
  if (!PROVIDER_RE.test(provider)) return;
7022
7022
  try {
7023
- const path7 = statePath(projectRoot);
7024
- const dir = (0, import_path4.join)(path7, "..");
7023
+ const path8 = statePath(projectRoot);
7024
+ const dir = (0, import_path4.join)(path8, "..");
7025
7025
  if (!(0, import_fs5.existsSync)(dir)) (0, import_fs5.mkdirSync)(dir, { recursive: true });
7026
- const existing = readState(path7);
7026
+ const existing = readState(path8);
7027
7027
  existing[provider] = { status, at: Date.now() };
7028
- (0, import_fs5.writeFileSync)(path7, JSON.stringify(existing, null, 2));
7028
+ (0, import_fs5.writeFileSync)(path8, JSON.stringify(existing, null, 2));
7029
7029
  } catch {
7030
7030
  }
7031
7031
  }
7032
7032
  function clearAuthFailure(projectRoot, provider) {
7033
7033
  if (!projectRoot) return;
7034
7034
  try {
7035
- const path7 = statePath(projectRoot);
7036
- if (!(0, import_fs5.existsSync)(path7)) return;
7037
- const existing = readState(path7);
7035
+ const path8 = statePath(projectRoot);
7036
+ if (!(0, import_fs5.existsSync)(path8)) return;
7037
+ const existing = readState(path8);
7038
7038
  if (!(provider in existing)) return;
7039
7039
  delete existing[provider];
7040
- (0, import_fs5.writeFileSync)(path7, JSON.stringify(existing, null, 2));
7040
+ (0, import_fs5.writeFileSync)(path8, JSON.stringify(existing, null, 2));
7041
7041
  } catch {
7042
7042
  }
7043
7043
  }
7044
7044
  function readRecentAuthFailures(projectRoot, ttlMs = 6 * 60 * 60 * 1e3) {
7045
7045
  if (!projectRoot) return [];
7046
7046
  try {
7047
- const path7 = statePath(projectRoot);
7048
- if (!(0, import_fs5.existsSync)(path7)) return [];
7049
- const state = readState(path7);
7047
+ const path8 = statePath(projectRoot);
7048
+ if (!(0, import_fs5.existsSync)(path8)) return [];
7049
+ const state = readState(path8);
7050
7050
  const now = Date.now();
7051
7051
  const out = [];
7052
7052
  for (const [provider, entry] of Object.entries(state)) {
@@ -13951,7 +13951,7 @@ var init_gossip_agent = __esm({
13951
13951
  }
13952
13952
  // ─── Public API ─────────────────────────────────────────────────────────────
13953
13953
  connect() {
13954
- return new Promise((resolve32, reject) => {
13954
+ return new Promise((resolve33, reject) => {
13955
13955
  const ws = new wrapper_default(this.config.relayUrl);
13956
13956
  const timeout = setTimeout(() => {
13957
13957
  ws.removeAllListeners();
@@ -13984,7 +13984,7 @@ var init_gossip_agent = __esm({
13984
13984
  ws.on("error", (err) => this.emit("error", err));
13985
13985
  this.startKeepAlive();
13986
13986
  this.emit("connect", msg.sessionId);
13987
- resolve32();
13987
+ resolve33();
13988
13988
  } else if (msg.type === "error") {
13989
13989
  clearTimeout(timeout);
13990
13990
  ws.removeAllListeners();
@@ -14010,7 +14010,7 @@ var init_gossip_agent = __esm({
14010
14010
  this.reconnectTimer = null;
14011
14011
  }
14012
14012
  if (!this.ws) return;
14013
- return new Promise((resolve32) => {
14013
+ return new Promise((resolve33) => {
14014
14014
  this.intentionalDisconnect = true;
14015
14015
  this._connected = false;
14016
14016
  const ws = this.ws;
@@ -14021,7 +14021,7 @@ var init_gossip_agent = __esm({
14021
14021
  settled = true;
14022
14022
  this.intentionalDisconnect = false;
14023
14023
  this.emit("disconnect", code);
14024
- resolve32();
14024
+ resolve33();
14025
14025
  };
14026
14026
  const timer = setTimeout(() => done(1e3), 2e3);
14027
14027
  ws.once("close", (code) => {
@@ -14060,8 +14060,8 @@ var init_gossip_agent = __esm({
14060
14060
  throw new Error("Not connected to relay");
14061
14061
  }
14062
14062
  const encoded = Buffer.from(this.codec.encode(envelope));
14063
- return new Promise((resolve32, reject) => {
14064
- this.ws.send(encoded, (err) => err ? reject(err) : resolve32());
14063
+ return new Promise((resolve33, reject) => {
14064
+ this.ws.send(encoded, (err) => err ? reject(err) : resolve33());
14065
14065
  });
14066
14066
  }
14067
14067
  // ─── Internal ────────────────────────────────────────────────────────────────
@@ -14541,7 +14541,7 @@ ${context}` : ""}
14541
14541
  this.memoryQueryCalled = true;
14542
14542
  }
14543
14543
  const requestId = (0, import_crypto6.randomUUID)();
14544
- const resultPromise = new Promise((resolve32, reject) => {
14544
+ const resultPromise = new Promise((resolve33, reject) => {
14545
14545
  const timer = setTimeout(() => {
14546
14546
  if (this.pendingToolCalls.has(requestId)) {
14547
14547
  this.pendingToolCalls.delete(requestId);
@@ -14552,7 +14552,7 @@ ${context}` : ""}
14552
14552
  this.pendingToolCalls.set(requestId, {
14553
14553
  resolve: (r) => {
14554
14554
  clearTimeout(timer);
14555
- resolve32(r);
14555
+ resolve33(r);
14556
14556
  },
14557
14557
  reject: (e) => {
14558
14558
  clearTimeout(timer);
@@ -15566,8 +15566,8 @@ var init_parseUtil = __esm({
15566
15566
  init_errors2();
15567
15567
  init_en();
15568
15568
  makeIssue2 = (params) => {
15569
- const { data, path: path7, errorMaps, issueData } = params;
15570
- const fullPath = [...path7, ...issueData.path || []];
15569
+ const { data, path: path8, errorMaps, issueData } = params;
15570
+ const fullPath = [...path8, ...issueData.path || []];
15571
15571
  const fullIssue = {
15572
15572
  ...issueData,
15573
15573
  path: fullPath
@@ -15878,11 +15878,11 @@ var init_types = __esm({
15878
15878
  init_parseUtil();
15879
15879
  init_util();
15880
15880
  ParseInputLazyPath2 = class {
15881
- constructor(parent, value, path7, key) {
15881
+ constructor(parent, value, path8, key) {
15882
15882
  this._cachedPath = [];
15883
15883
  this.parent = parent;
15884
15884
  this.data = value;
15885
- this._path = path7;
15885
+ this._path = path8;
15886
15886
  this._key = key;
15887
15887
  }
15888
15888
  get path() {
@@ -19916,7 +19916,7 @@ ${truncateAtLine(fullDiff, 3e3)}`;
19916
19916
  }
19917
19917
  async requestPeerReview(callerId, diff, testResult) {
19918
19918
  const requestId = (0, import_crypto8.randomUUID)();
19919
- const reviewPromise = new Promise((resolve32, reject) => {
19919
+ const reviewPromise = new Promise((resolve33, reject) => {
19920
19920
  const timer = setTimeout(() => {
19921
19921
  this.pendingReviews.delete(requestId);
19922
19922
  reject(new Error("Review timed out"));
@@ -19925,7 +19925,7 @@ ${truncateAtLine(fullDiff, 3e3)}`;
19925
19925
  this.pendingReviews.set(requestId, {
19926
19926
  resolve: (r) => {
19927
19927
  clearTimeout(timer);
19928
- resolve32(r);
19928
+ resolve33(r);
19929
19929
  },
19930
19930
  reject: (e) => {
19931
19931
  clearTimeout(timer);
@@ -20296,7 +20296,14 @@ var init_consensus_types = __esm({
20296
20296
  "transport_failure",
20297
20297
  "worktree_isolation_failed",
20298
20298
  "auto_verify_attempted",
20299
- "auto_verify_skipped_misconfigured"
20299
+ "auto_verify_skipped_misconfigured",
20300
+ /**
20301
+ * Orchestrator dispatch-hygiene signals (UNIT 1 — orchestrator signal pipeline).
20302
+ * Tallied as operational; never affect agent accuracy scoring.
20303
+ */
20304
+ "dispatched_stale_base",
20305
+ "referenced_unreadable_path",
20306
+ "mid_flight_fixup"
20300
20307
  ]);
20301
20308
  }
20302
20309
  });
@@ -20324,21 +20331,21 @@ function extractFrontmatterField(content, field) {
20324
20331
  return null;
20325
20332
  }
20326
20333
  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 };
20334
+ const path8 = resolveSkillFilePath(agentId, category, skillRoot);
20335
+ if (!(0, import_fs12.existsSync)(path8)) {
20336
+ return { boundAt: null, status: null, path: path8, regressedFromPassedAt: null };
20330
20337
  }
20331
20338
  let content;
20332
20339
  try {
20333
- content = (0, import_fs12.readFileSync)(path7, "utf-8");
20340
+ content = (0, import_fs12.readFileSync)(path8, "utf-8");
20334
20341
  } catch {
20335
- return { boundAt: null, status: null, path: path7, regressedFromPassedAt: null };
20342
+ return { boundAt: null, status: null, path: path8, regressedFromPassedAt: null };
20336
20343
  }
20337
20344
  const boundAt = extractFrontmatterField(content, "bound_at");
20338
20345
  const rawStatus = extractFrontmatterField(content, "status");
20339
20346
  const status = rawStatus === null ? null : coerceStatus(rawStatus);
20340
20347
  const regressedFromPassedAt = extractFrontmatterField(content, "regressed_from_passed_at");
20341
- return { boundAt, status, path: path7, regressedFromPassedAt };
20348
+ return { boundAt, status, path: path8, regressedFromPassedAt };
20342
20349
  }
20343
20350
  function computeCooldown(input) {
20344
20351
  let status;
@@ -21928,15 +21935,15 @@ function classifyForAggregate(signal) {
21928
21935
  }
21929
21936
  }
21930
21937
  function readAggregateIndex(projectRoot) {
21931
- const path7 = (0, import_path14.join)(projectRoot, ".gossip", SIDECAR_FILENAME);
21932
- if (!(0, import_fs14.existsSync)(path7)) {
21938
+ const path8 = (0, import_path14.join)(projectRoot, ".gossip", SIDECAR_FILENAME);
21939
+ if (!(0, import_fs14.existsSync)(path8)) {
21933
21940
  cachedAggregateData = null;
21934
21941
  cachedAggregateMtimeMs = 0;
21935
21942
  return null;
21936
21943
  }
21937
21944
  let mtimeMs = 0;
21938
21945
  try {
21939
- mtimeMs = (0, import_fs14.statSync)(path7).mtimeMs;
21946
+ mtimeMs = (0, import_fs14.statSync)(path8).mtimeMs;
21940
21947
  } catch (err) {
21941
21948
  logSidecarError("stat", err);
21942
21949
  return null;
@@ -21946,7 +21953,7 @@ function readAggregateIndex(projectRoot) {
21946
21953
  }
21947
21954
  let raw;
21948
21955
  try {
21949
- raw = (0, import_fs14.readFileSync)(path7, "utf-8");
21956
+ raw = (0, import_fs14.readFileSync)(path8, "utf-8");
21950
21957
  } catch (err) {
21951
21958
  logSidecarError("read", err);
21952
21959
  return null;
@@ -21982,14 +21989,14 @@ function readAggregateIndex(projectRoot) {
21982
21989
  return result;
21983
21990
  }
21984
21991
  function writeAggregateIndex(projectRoot, data) {
21985
- const path7 = (0, import_path14.join)(projectRoot, ".gossip", SIDECAR_FILENAME);
21992
+ const path8 = (0, import_path14.join)(projectRoot, ".gossip", SIDECAR_FILENAME);
21986
21993
  try {
21987
- (0, import_fs14.mkdirSync)((0, import_path14.dirname)(path7), { recursive: true });
21988
- const tmp = path7 + ".tmp";
21994
+ (0, import_fs14.mkdirSync)((0, import_path14.dirname)(path8), { recursive: true });
21995
+ const tmp = path8 + ".tmp";
21989
21996
  (0, import_fs14.writeFileSync)(tmp, JSON.stringify(data, null, 2) + "\n");
21990
- (0, import_fs14.renameSync)(tmp, path7);
21997
+ (0, import_fs14.renameSync)(tmp, path8);
21991
21998
  cachedAggregateData = data;
21992
- cachedAggregateMtimeMs = (0, import_fs14.statSync)(path7).mtimeMs;
21999
+ cachedAggregateMtimeMs = (0, import_fs14.statSync)(path8).mtimeMs;
21993
22000
  } catch (err) {
21994
22001
  logSidecarError("write", err);
21995
22002
  }
@@ -22375,14 +22382,14 @@ var init_performance_reader = __esm({
22375
22382
  */
22376
22383
  getSkillIndexEnabledMap() {
22377
22384
  if (this.skillIndexCache !== void 0) return this.skillIndexCache;
22378
- const path7 = (0, import_path15.join)(this.projectRoot, ".gossip", "skill-index.json");
22385
+ const path8 = (0, import_path15.join)(this.projectRoot, ".gossip", "skill-index.json");
22379
22386
  let parsed;
22380
22387
  try {
22381
- if (!(0, import_fs15.existsSync)(path7)) {
22388
+ if (!(0, import_fs15.existsSync)(path8)) {
22382
22389
  this.skillIndexCache = null;
22383
22390
  return null;
22384
22391
  }
22385
- parsed = JSON.parse((0, import_fs15.readFileSync)(path7, "utf-8"));
22392
+ parsed = JSON.parse((0, import_fs15.readFileSync)(path8, "utf-8"));
22386
22393
  } catch {
22387
22394
  this.skillIndexCache = null;
22388
22395
  return null;
@@ -23776,7 +23783,14 @@ var init_performance_writer = __esm({
23776
23783
  "relay_findings_dropped",
23777
23784
  // Phase A self-telemetry: collect-end reconciliation detected fewer signals
23778
23785
  // written than findings in the consensus report. Observability-only.
23779
- "signal_loss_suspected"
23786
+ "signal_loss_suspected",
23787
+ // UNIT 1 orchestrator signal pipeline: dispatch-hygiene precondition signals.
23788
+ // Operational-only (tallied, never scored). Emitted by orchestrator-preconditions.ts
23789
+ // when a dispatch-hygiene failure is detected (stale base, unreadable reference
23790
+ // paths, mid-flight commits during a consensus round).
23791
+ "dispatched_stale_base",
23792
+ "referenced_unreadable_path",
23793
+ "mid_flight_fixup"
23780
23794
  ]);
23781
23795
  SYSTEM_SENTINEL_AGENT_ID = "_system";
23782
23796
  rowsWrittenSinceCheck = 0;
@@ -24489,13 +24503,13 @@ function resolveSkill(agentId, skill, projectRoot) {
24489
24503
  if ((0, import_fs19.existsSync)(candidate)) {
24490
24504
  try {
24491
24505
  const content = (0, import_fs19.readFileSync)(candidate, "utf-8");
24492
- let path7;
24506
+ let path8;
24493
24507
  try {
24494
- path7 = (0, import_fs19.realpathSync)(candidate);
24508
+ path8 = (0, import_fs19.realpathSync)(candidate);
24495
24509
  } catch {
24496
- path7 = candidate;
24510
+ path8 = candidate;
24497
24511
  }
24498
- return { content, path: path7 };
24512
+ return { content, path: path8 };
24499
24513
  } catch (err) {
24500
24514
  log("skill-loader", `Failed to read skill file ${candidate}: ${err?.message ?? err}`);
24501
24515
  continue;
@@ -25599,14 +25613,14 @@ ${cleanSummary}` : cleanSummary;
25599
25613
  const citations = [];
25600
25614
  let m;
25601
25615
  while ((m = fileRegex.exec(body)) !== null) {
25602
- const path7 = m[1];
25616
+ const path8 = m[1];
25603
25617
  const before = body.slice(Math.max(0, m.index - 8), m.index + 1);
25604
- if (/https?:\/\//.test(before) || /https?:\/\//.test(path7)) continue;
25618
+ if (/https?:\/\//.test(before) || /https?:\/\//.test(path8)) continue;
25605
25619
  const line = m[2] ? parseInt(m[2], 10) : void 0;
25606
- const key = line !== void 0 ? `${path7}:${line}` : path7;
25620
+ const key = line !== void 0 ? `${path8}:${line}` : path8;
25607
25621
  if (seen.has(key)) continue;
25608
25622
  seen.add(key);
25609
- citations.push({ path: path7, line, key });
25623
+ citations.push({ path: path8, line, key });
25610
25624
  }
25611
25625
  const roots = [this.projectRoot, ...resolutionRoots ?? []];
25612
25626
  const unverified = [];
@@ -29268,12 +29282,12 @@ async function getUncategorizedStatusLine(projectRoot, opts) {
29268
29282
  let mostRecentText = "";
29269
29283
  let mostRecentTs = 0;
29270
29284
  const uncatPath = (0, import_path31.join)(projectRoot, ".gossip", "uncategorized-findings.jsonl");
29271
- const scanFile = (filePath) => new Promise((resolve32) => {
29285
+ const scanFile = (filePath) => new Promise((resolve33) => {
29272
29286
  if (!(0, import_fs29.existsSync)(filePath)) {
29273
- return resolve32();
29287
+ return resolve33();
29274
29288
  }
29275
29289
  const stream = (0, import_fs29.createReadStream)(filePath, { encoding: "utf8" });
29276
- stream.on("error", () => resolve32());
29290
+ stream.on("error", () => resolve33());
29277
29291
  const rl = (0, import_readline.createInterface)({ input: stream, crlfDelay: Infinity });
29278
29292
  rl.on("line", (line) => {
29279
29293
  if (!line) return;
@@ -29290,8 +29304,8 @@ async function getUncategorizedStatusLine(projectRoot, opts) {
29290
29304
  } catch {
29291
29305
  }
29292
29306
  });
29293
- rl.on("close", resolve32);
29294
- rl.on("error", () => resolve32());
29307
+ rl.on("close", resolve33);
29308
+ rl.on("error", () => resolve33());
29295
29309
  });
29296
29310
  await scanFile(uncatPath);
29297
29311
  if ((0, import_fs29.existsSync)(uncatPath + ".1")) {
@@ -29480,6 +29494,26 @@ var init_consensus_engine = __esm({
29480
29494
  if (!report.warnings) report.warnings = [];
29481
29495
  report.warnings.push(entry);
29482
29496
  }
29497
+ /**
29498
+ * Idempotent helper: appends the UNSCORED ROUND banner to report.summary and
29499
+ * records a zero_tags warning when any agents emitted zero <agent_finding> tags.
29500
+ * Safe to call multiple times — skips if the banner is already present or if
29501
+ * zeroTagAgents is empty/absent.
29502
+ * Called at each finalization point: run(), runSelectedCrossReview(), and
29503
+ * synthesizeWithCrossReview() — so ALL synthesize paths surface the banner.
29504
+ */
29505
+ surfaceZeroTagBanner(report) {
29506
+ if (!report.zeroTagAgents?.length) return;
29507
+ if (report.summary.includes("UNSCORED ROUND")) return;
29508
+ const n = report.zeroTagAgents.length;
29509
+ const overflow = report.zeroTagOverflow ?? 0;
29510
+ const list = report.zeroTagAgents.join(", ");
29511
+ 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})`;
29512
+ report.summary += `
29513
+ \u26A0\uFE0F ${evidence}
29514
+ `;
29515
+ this.appendReportWarning(report, "zero_tags", evidence);
29516
+ }
29483
29517
  /** True when a PerformanceReader is available for orchestrator-selected cross-review (Step 3). */
29484
29518
  get hasPerformanceReader() {
29485
29519
  return this.config.performanceReader !== void 0;
@@ -29730,6 +29764,7 @@ var init_consensus_engine = __esm({
29730
29764
  );
29731
29765
  report.unverified = enriched;
29732
29766
  report.summary = this.formatReport(report.confirmed, report.disputed, report.unverified, report.unique, report.newFindings, successful.length, report.rounds, timing, report.insights);
29767
+ this.surfaceZeroTagBanner(report);
29733
29768
  return report;
29734
29769
  }
29735
29770
  /**
@@ -30107,7 +30142,7 @@ Return only valid JSON.${skillsBlock}`;
30107
30142
  }
30108
30143
  log(
30109
30144
  "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.`
30145
+ `\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
30146
  );
30112
30147
  } else {
30113
30148
  const offending = Object.entries(parseResult.droppedUnknownType).map(([t, n]) => `${t}:${n}`).join(",") || "(missing type attribute)";
@@ -31547,7 +31582,9 @@ ${safeSnippet}
31547
31582
  }
31548
31583
  if (findingSeq === 0) {
31549
31584
  log("consensus", "runSelectedCrossReview: no structured findings extracted; synthesizing without cross-review");
31550
- return this.synthesize(results, [], consensusId);
31585
+ const report2 = await this.synthesize(results, [], consensusId);
31586
+ this.surfaceZeroTagBanner(report2);
31587
+ return report2;
31551
31588
  }
31552
31589
  const agentCandidates = successful.map((r) => ({ agentId: r.agentId }));
31553
31590
  const assignments = selectCrossReviewers(findingsForSelection, agentCandidates, performanceReader);
@@ -31555,6 +31592,7 @@ ${safeSnippet}
31555
31592
  log("consensus", "runSelectedCrossReview: no reviewers selected; synthesizing without cross-review");
31556
31593
  const report2 = await this.synthesize(results, [], consensusId);
31557
31594
  this.appendReportWarning(report2, "partial_review", "no cross-reviewers selected \u2014 every finding is under-reviewed (0 of target K)");
31595
+ this.surfaceZeroTagBanner(report2);
31558
31596
  return report2;
31559
31597
  }
31560
31598
  const reviewerCountPerFinding = /* @__PURE__ */ new Map();
@@ -31609,6 +31647,7 @@ ${safeSnippet}
31609
31647
  assigned: reviewerCountPerFinding.get(f.id) ?? 0,
31610
31648
  targetK: findingKMap.get(f.id) ?? 2
31611
31649
  }));
31650
+ this.surfaceZeroTagBanner(report);
31612
31651
  return report;
31613
31652
  }
31614
31653
  /**
@@ -31654,6 +31693,7 @@ ${safeSnippet}
31654
31693
  `;
31655
31694
  this.appendReportWarning(report, "coverage_degraded", evidence);
31656
31695
  }
31696
+ this.surfaceZeroTagBanner(report);
31657
31697
  if (relayCrossReviewSkipped && relayCrossReviewSkipped.length > 0) {
31658
31698
  const lines = ["", "\u26A0\uFE0F Relay cross-review skipped:"];
31659
31699
  for (const s of relayCrossReviewSkipped) {
@@ -34212,11 +34252,11 @@ var init_archetype_catalog = __esm({
34212
34252
  ArchetypeCatalog = class {
34213
34253
  archetypes;
34214
34254
  constructor(catalogPath) {
34215
- const path7 = catalogPath ?? findArchetypeCatalog();
34216
- if (!path7) {
34255
+ const path8 = catalogPath ?? findArchetypeCatalog();
34256
+ if (!path8) {
34217
34257
  throw new Error("archetypes.json not found \u2014 tried bundled dist-mcp/data/, dev ts-node path, and cwd/data/. Reinstall gossipcat.");
34218
34258
  }
34219
- const raw = (0, import_fs34.readFileSync)(path7, "utf-8");
34259
+ const raw = (0, import_fs34.readFileSync)(path8, "utf-8");
34220
34260
  this.archetypes = JSON.parse(raw);
34221
34261
  }
34222
34262
  /** Return all archetype IDs */
@@ -34270,8 +34310,7 @@ function findBundledHook() {
34270
34310
  const candidates = [
34271
34311
  (0, import_path37.resolve)(__dirname, "assets", "hooks", HOOK_FILENAME),
34272
34312
  (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)
34313
+ (0, import_path37.resolve)(__dirname, "..", "assets", "hooks", HOOK_FILENAME)
34275
34314
  ];
34276
34315
  for (const p of candidates) {
34277
34316
  if ((0, import_fs35.existsSync)(p)) return p;
@@ -34331,11 +34370,6 @@ function installWorktreeSandboxHook(projectRoot) {
34331
34370
  try {
34332
34371
  const bundled = findBundledHook();
34333
34372
  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
34373
  const settingsPath = (0, import_path37.join)(projectRoot, ".claude", "settings.json");
34340
34374
  (0, import_fs35.mkdirSync)((0, import_path37.dirname)(settingsPath), { recursive: true });
34341
34375
  let settings;
@@ -34348,6 +34382,11 @@ function installWorktreeSandboxHook(projectRoot) {
34348
34382
  );
34349
34383
  return { installed: false, reason: err.message };
34350
34384
  }
34385
+ const targetDir = (0, import_path37.join)(projectRoot, ".claude", "hooks");
34386
+ const target = (0, import_path37.join)(targetDir, HOOK_FILENAME);
34387
+ (0, import_fs35.mkdirSync)(targetDir, { recursive: true });
34388
+ (0, import_fs35.copyFileSync)(bundled, target);
34389
+ (0, import_fs35.chmodSync)(target, 493);
34351
34390
  const mutated = mergePreToolUseEntry(settings);
34352
34391
  if (mutated) {
34353
34392
  (0, import_fs35.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2) + "\n");
@@ -34381,8 +34420,7 @@ function findDisciplineHook(filename) {
34381
34420
  const candidates = [
34382
34421
  (0, import_path37.resolve)(__dirname, "assets", "hooks", DISCIPLINE_HOOK_DIR, filename),
34383
34422
  (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)
34423
+ (0, import_path37.resolve)(__dirname, "..", "assets", "hooks", DISCIPLINE_HOOK_DIR, filename)
34386
34424
  ];
34387
34425
  for (const p of candidates) {
34388
34426
  if ((0, import_fs35.existsSync)(p)) return p;
@@ -34563,18 +34601,6 @@ function installDisciplineHooks(projectRoot) {
34563
34601
  const installed = [];
34564
34602
  const skipped = [];
34565
34603
  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
34604
  const settingsPath = (0, import_path37.join)(projectRoot, ".claude", "settings.local.json");
34579
34605
  (0, import_fs35.mkdirSync)((0, import_path37.dirname)(settingsPath), { recursive: true });
34580
34606
  let settings;
@@ -34587,6 +34613,18 @@ function installDisciplineHooks(projectRoot) {
34587
34613
  );
34588
34614
  return { installed, skipped, reason: err.message };
34589
34615
  }
34616
+ const targetDir = (0, import_path37.join)(projectRoot, ".claude", "hooks", DISCIPLINE_HOOK_DIR);
34617
+ (0, import_fs35.mkdirSync)(targetDir, { recursive: true });
34618
+ for (const hook of DISCIPLINE_HOOKS) {
34619
+ const bundled = findDisciplineHook(hook.filename);
34620
+ if (!bundled) {
34621
+ skipped.push(hook.name);
34622
+ continue;
34623
+ }
34624
+ const target = (0, import_path37.join)(targetDir, hook.filename);
34625
+ (0, import_fs35.copyFileSync)(bundled, target);
34626
+ (0, import_fs35.chmodSync)(target, 493);
34627
+ }
34590
34628
  let anyMutated = false;
34591
34629
  for (const hook of DISCIPLINE_HOOKS) {
34592
34630
  const bundled = findDisciplineHook(hook.filename);
@@ -35274,8 +35312,8 @@ message: Your question?
35274
35312
  }
35275
35313
  /** Start all worker agents (connect to relay) */
35276
35314
  async start() {
35277
- const { existsSync: existsSync73, readFileSync: readFileSync69 } = await import("fs");
35278
- const { join: join91 } = await import("path");
35315
+ const { existsSync: existsSync74, readFileSync: readFileSync70 } = await import("fs");
35316
+ const { join: join93 } = await import("path");
35279
35317
  for (const config2 of this.registry.getAll()) {
35280
35318
  if (config2.native) continue;
35281
35319
  if (this.workers.has(config2.id)) continue;
@@ -35293,8 +35331,8 @@ message: Your question?
35293
35331
  void 0,
35294
35332
  config2.key_ref
35295
35333
  );
35296
- const instructionsPath = join91(this.projectRoot, ".gossip", "agents", config2.id, "instructions.md");
35297
- const instructions = existsSync73(instructionsPath) ? readFileSync69(instructionsPath, "utf-8") : void 0;
35334
+ const instructionsPath = join93(this.projectRoot, ".gossip", "agents", config2.id, "instructions.md");
35335
+ const instructions = existsSync74(instructionsPath) ? readFileSync70(instructionsPath, "utf-8") : void 0;
35298
35336
  const enableWebSearch = config2.preset === "researcher" || config2.skills.includes("research");
35299
35337
  const worker = new WorkerAgent(config2.id, llm, this.relayUrl, ALL_TOOLS, instructions, enableWebSearch, this.relayApiKey, config2.maxToolTurns);
35300
35338
  await worker.start();
@@ -35491,8 +35529,8 @@ message: Your question?
35491
35529
  this.registry.register(config2);
35492
35530
  }
35493
35531
  async syncWorkers(keyProvider) {
35494
- const { existsSync: existsSync73, readFileSync: readFileSync69 } = await import("fs");
35495
- const { join: join91 } = await import("path");
35532
+ const { existsSync: existsSync74, readFileSync: readFileSync70 } = await import("fs");
35533
+ const { join: join93 } = await import("path");
35496
35534
  let added = 0;
35497
35535
  for (const ac of this.registry.getAll()) {
35498
35536
  if (ac.native) continue;
@@ -35509,8 +35547,8 @@ message: Your question?
35509
35547
  this.workers.delete(ac.id);
35510
35548
  }
35511
35549
  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;
35550
+ const instructionsPath = join93(this.projectRoot, ".gossip", "agents", ac.id, "instructions.md");
35551
+ const instructions = existsSync74(instructionsPath) ? readFileSync70(instructionsPath, "utf-8") : void 0;
35514
35552
  const enableWebSearch = ac.preset === "researcher" || ac.skills.includes("research");
35515
35553
  const worker = new WorkerAgent(ac.id, llm, this.relayUrl, ALL_TOOLS, instructions, enableWebSearch, this.relayApiKey, ac.maxToolTurns);
35516
35554
  await worker.start();
@@ -36487,8 +36525,8 @@ function applyStatusTags(input, statusMap) {
36487
36525
  }
36488
36526
  return { output: lines.join("\n"), changed };
36489
36527
  }
36490
- function atomicWrite(path7, content) {
36491
- const tmp = `${path7}.tmp`;
36528
+ function atomicWrite(path8, content) {
36529
+ const tmp = `${path8}.tmp`;
36492
36530
  let fd;
36493
36531
  try {
36494
36532
  (0, import_fs40.writeFileSync)(tmp, content, "utf-8");
@@ -36496,7 +36534,7 @@ function atomicWrite(path7, content) {
36496
36534
  (0, import_fs40.fsyncSync)(fd);
36497
36535
  (0, import_fs40.closeSync)(fd);
36498
36536
  fd = void 0;
36499
- (0, import_fs40.renameSync)(tmp, path7);
36537
+ (0, import_fs40.renameSync)(tmp, path8);
36500
36538
  } catch (err) {
36501
36539
  if (fd !== void 0) {
36502
36540
  try {
@@ -36637,8 +36675,8 @@ function corpusDir(projectRoot) {
36637
36675
  const encoded = projectRoot.replace(/\//g, "-");
36638
36676
  return (0, import_path43.join)((0, import_os3.homedir)(), ".claude", "projects", encoded, "memory");
36639
36677
  }
36640
- function atomicWriteJson(path7, data) {
36641
- const tmp = `${path7}.tmp`;
36678
+ function atomicWriteJson(path8, data) {
36679
+ const tmp = `${path8}.tmp`;
36642
36680
  let fd;
36643
36681
  try {
36644
36682
  (0, import_fs41.writeFileSync)(tmp, JSON.stringify(data, null, 2), "utf-8");
@@ -36646,7 +36684,7 @@ function atomicWriteJson(path7, data) {
36646
36684
  (0, import_fs41.fsyncSync)(fd);
36647
36685
  (0, import_fs41.closeSync)(fd);
36648
36686
  fd = void 0;
36649
- (0, import_fs41.renameSync)(tmp, path7);
36687
+ (0, import_fs41.renameSync)(tmp, path8);
36650
36688
  } catch (err) {
36651
36689
  if (fd !== void 0) {
36652
36690
  try {
@@ -36856,8 +36894,8 @@ function rebuildIndex(projectRoot) {
36856
36894
  atomicWriteJson(idxPath, index);
36857
36895
  return index;
36858
36896
  }
36859
- function atomicWriteText(path7, content) {
36860
- const tmp = `${path7}.tmp`;
36897
+ function atomicWriteText(path8, content) {
36898
+ const tmp = `${path8}.tmp`;
36861
36899
  let fd;
36862
36900
  try {
36863
36901
  (0, import_fs41.writeFileSync)(tmp, content, "utf-8");
@@ -36865,7 +36903,7 @@ function atomicWriteText(path7, content) {
36865
36903
  (0, import_fs41.fsyncSync)(fd);
36866
36904
  (0, import_fs41.closeSync)(fd);
36867
36905
  fd = void 0;
36868
- (0, import_fs41.renameSync)(tmp, path7);
36906
+ (0, import_fs41.renameSync)(tmp, path8);
36869
36907
  } catch (err) {
36870
36908
  if (fd !== void 0) {
36871
36909
  try {
@@ -37259,29 +37297,29 @@ var init_task_graph_sync = __esm({
37259
37297
  );
37260
37298
  }
37261
37299
  }
37262
- async patch(path7, body) {
37263
- const res = await fetch(`${this.supabaseUrl}${path7}`, {
37300
+ async patch(path8, body) {
37301
+ const res = await fetch(`${this.supabaseUrl}${path8}`, {
37264
37302
  method: "PATCH",
37265
37303
  headers: this.headers(),
37266
37304
  body: JSON.stringify(body)
37267
37305
  });
37268
- if (!res.ok) throw new Error(`PATCH ${path7} failed: ${res.status} ${await res.text()}`);
37306
+ if (!res.ok) throw new Error(`PATCH ${path8} failed: ${res.status} ${await res.text()}`);
37269
37307
  }
37270
- async post(path7, body) {
37271
- const res = await fetch(`${this.supabaseUrl}${path7}`, {
37308
+ async post(path8, body) {
37309
+ const res = await fetch(`${this.supabaseUrl}${path8}`, {
37272
37310
  method: "POST",
37273
37311
  headers: { ...this.headers(), "Prefer": "return=representation" },
37274
37312
  body: JSON.stringify(body)
37275
37313
  });
37276
- if (!res.ok) throw new Error(`POST ${path7} failed: ${res.status} ${await res.text()}`);
37314
+ if (!res.ok) throw new Error(`POST ${path8} failed: ${res.status} ${await res.text()}`);
37277
37315
  }
37278
- async upsert(path7, body) {
37279
- const res = await fetch(`${this.supabaseUrl}${path7}`, {
37316
+ async upsert(path8, body) {
37317
+ const res = await fetch(`${this.supabaseUrl}${path8}`, {
37280
37318
  method: "POST",
37281
37319
  headers: { ...this.headers(), "Prefer": "resolution=merge-duplicates,return=representation" },
37282
37320
  body: JSON.stringify(body)
37283
37321
  });
37284
- if (!res.ok) throw new Error(`UPSERT ${path7} failed: ${res.status} ${await res.text()}`);
37322
+ if (!res.ok) throw new Error(`UPSERT ${path8} failed: ${res.status} ${await res.text()}`);
37285
37323
  }
37286
37324
  headers() {
37287
37325
  return {
@@ -37478,22 +37516,22 @@ async function readJsonBody(req, cap) {
37478
37516
  return { err: "invalid_json", msg: err instanceof Error ? err.message : "parse error" };
37479
37517
  }
37480
37518
  }
37481
- function replyBodyErr(ctx2, req, res, rec, started, path7, body) {
37519
+ function replyBodyErr(ctx2, req, res, rec, started, path8, body) {
37482
37520
  if (body.err === "too_large") {
37483
37521
  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 });
37522
+ ctx2.logEvent({ started, req, status: 413, path: path8, bytesRead: 0, bytesWritten: 0, token: rec.token });
37485
37523
  } else {
37486
37524
  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 });
37525
+ ctx2.logEvent({ started, req, status: 400, path: path8, bytesRead: 0, bytesWritten: 0, token: rec.token });
37488
37526
  }
37489
37527
  }
37490
- function reply403(ctx2, req, res, rec, started, path7, msg) {
37528
+ function reply403(ctx2, req, res, rec, started, path8, msg) {
37491
37529
  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 });
37530
+ ctx2.logEvent({ started, req, status: 403, path: path8, bytesRead: 0, bytesWritten: 0, token: rec.token });
37493
37531
  }
37494
- function reply429(ctx2, req, res, rec, started, path7) {
37532
+ function reply429(ctx2, req, res, rec, started, path8) {
37495
37533
  ctx2.send429(res);
37496
- ctx2.logEvent({ started, req, status: 429, path: path7, bytesRead: 0, bytesWritten: 0, token: rec.token });
37534
+ ctx2.logEvent({ started, req, status: 429, path: path8, bytesRead: 0, bytesWritten: 0, token: rec.token });
37497
37535
  }
37498
37536
  async function handleBridgeInfo(ctx2, req, res, started, ip) {
37499
37537
  if (!ctx2.limBridgeInfo.record(ip)) {
@@ -37532,12 +37570,12 @@ async function handleFileRead(ctx2, req, res, rec, started) {
37532
37570
  if (!ctx2.limRead.record(`read:${rec.token}`)) return reply429(ctx2, req, res, rec, started, "/file-read");
37533
37571
  const body = await readJsonBody(req, MAX_FILE_BYTES);
37534
37572
  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) {
37573
+ const path8 = typeof body.value?.path === "string" ? body.value.path : "";
37574
+ if (!path8) {
37537
37575
  ctx2.sendJson(res, 400, ctx2.errBody("bad_request", "bad_request", "path is required"));
37538
37576
  return ctx2.logEvent({ started, req, status: 400, path: "/file-read", bytesRead: 0, bytesWritten: 0, token: rec.token });
37539
37577
  }
37540
- const abs = resolveInScope(rec, path7);
37578
+ const abs = resolveInScope(rec, path8);
37541
37579
  if (!abs.ok) return reply403(ctx2, req, res, rec, started, "/file-read", abs.msg);
37542
37580
  let fileSize;
37543
37581
  let mtime;
@@ -37578,14 +37616,14 @@ async function handleFileWrite(ctx2, req, res, rec, started) {
37578
37616
  if (!ctx2.limWrite.record(`write:${rec.token}`)) return reply429(ctx2, req, res, rec, started, "/file-write");
37579
37617
  const body = await readJsonBody(req, MAX_FILE_BYTES);
37580
37618
  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 : "";
37619
+ const path8 = typeof body.value?.path === "string" ? body.value.path : "";
37582
37620
  const content = typeof body.value?.content === "string" ? body.value.content : "";
37583
37621
  const ifMatch = typeof body.value?.if_match === "string" ? body.value.if_match : void 0;
37584
- if (!path7) {
37622
+ if (!path8) {
37585
37623
  ctx2.sendJson(res, 400, ctx2.errBody("bad_request", "bad_request", "path is required"));
37586
37624
  return ctx2.logEvent({ started, req, status: 400, path: "/file-write", bytesRead: 0, bytesWritten: 0, token: rec.token });
37587
37625
  }
37588
- const abs = resolveInScope(rec, path7);
37626
+ const abs = resolveInScope(rec, path8);
37589
37627
  if (!abs.ok) return reply403(ctx2, req, res, rec, started, "/file-write", abs.msg);
37590
37628
  const buf = Buffer.from(content, "utf-8");
37591
37629
  if (buf.byteLength > MAX_FILE_BYTES) {
@@ -38234,12 +38272,12 @@ function buildIndexFromDisk(memoryDir, agentIds) {
38234
38272
  };
38235
38273
  }
38236
38274
  function readValidSidecar(projectRoot, memoryDir) {
38237
- const path7 = proseResolverPath(projectRoot);
38238
- if (!(0, import_fs44.existsSync)(path7)) return null;
38275
+ const path8 = proseResolverPath(projectRoot);
38276
+ if (!(0, import_fs44.existsSync)(path8)) return null;
38239
38277
  let parsed;
38240
38278
  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"));
38279
+ if ((0, import_fs44.statSync)(path8).size > SIDECAR_READ_LIMIT) return null;
38280
+ parsed = JSON.parse((0, import_fs44.readFileSync)(path8, "utf-8"));
38243
38281
  } catch {
38244
38282
  return null;
38245
38283
  }
@@ -38259,10 +38297,10 @@ function readValidSidecar(projectRoot, memoryDir) {
38259
38297
  return idx;
38260
38298
  }
38261
38299
  function writeSidecar(projectRoot, idx) {
38262
- const path7 = proseResolverPath(projectRoot);
38300
+ const path8 = proseResolverPath(projectRoot);
38263
38301
  try {
38264
- (0, import_fs44.mkdirSync)((0, import_path48.dirname)(path7), { recursive: true });
38265
- (0, import_fs44.writeFileSync)(path7, JSON.stringify(idx));
38302
+ (0, import_fs44.mkdirSync)((0, import_path48.dirname)(path8), { recursive: true });
38303
+ (0, import_fs44.writeFileSync)(path8, JSON.stringify(idx));
38266
38304
  } catch {
38267
38305
  }
38268
38306
  }
@@ -38427,11 +38465,11 @@ function isLedgerIndex(x) {
38427
38465
  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
38466
  }
38429
38467
  function readLedgerIndex(projectRoot, liveLedgerContent, liveLedgerMtime) {
38430
- const path7 = ledgerIndexPath(projectRoot);
38431
- if (!(0, import_fs45.existsSync)(path7)) return null;
38468
+ const path8 = ledgerIndexPath(projectRoot);
38469
+ if (!(0, import_fs45.existsSync)(path8)) return null;
38432
38470
  let parsed;
38433
38471
  try {
38434
- parsed = JSON.parse((0, import_fs45.readFileSync)(path7, "utf-8"));
38472
+ parsed = JSON.parse((0, import_fs45.readFileSync)(path8, "utf-8"));
38435
38473
  } catch {
38436
38474
  return null;
38437
38475
  }
@@ -38441,10 +38479,10 @@ function readLedgerIndex(projectRoot, liveLedgerContent, liveLedgerMtime) {
38441
38479
  return parsed;
38442
38480
  }
38443
38481
  function writeLedgerIndex(projectRoot, index) {
38444
- const path7 = ledgerIndexPath(projectRoot);
38482
+ const path8 = ledgerIndexPath(projectRoot);
38445
38483
  try {
38446
- (0, import_fs45.mkdirSync)((0, import_path49.dirname)(path7), { recursive: true });
38447
- (0, import_fs45.writeFileSync)(path7, JSON.stringify(index, null, 2));
38484
+ (0, import_fs45.mkdirSync)((0, import_path49.dirname)(path8), { recursive: true });
38485
+ (0, import_fs45.writeFileSync)(path8, JSON.stringify(index, null, 2));
38448
38486
  } catch {
38449
38487
  }
38450
38488
  }
@@ -38552,9 +38590,9 @@ function annotateLedgerText(raw, bullets, entriesByHash) {
38552
38590
  }
38553
38591
  return lines.join("\n");
38554
38592
  }
38555
- function ledgerMtime(ledgerPath) {
38593
+ function ledgerMtime(ledgerPath2) {
38556
38594
  try {
38557
- return (0, import_fs45.statSync)(ledgerPath).mtimeMs;
38595
+ return (0, import_fs45.statSync)(ledgerPath2).mtimeMs;
38558
38596
  } catch {
38559
38597
  return 0;
38560
38598
  }
@@ -38616,10 +38654,10 @@ function checkDistMcpStaleness(bundlePath) {
38616
38654
  let newestMtime = 0;
38617
38655
  let newestPath;
38618
38656
  for (const root of SRC_ROOTS) {
38619
- walk((0, import_path50.join)(repoRoot, root), (path7, mtimeMs) => {
38657
+ walk((0, import_path50.join)(repoRoot, root), (path8, mtimeMs) => {
38620
38658
  if (mtimeMs > newestMtime) {
38621
38659
  newestMtime = mtimeMs;
38622
- newestPath = path7;
38660
+ newestPath = path8;
38623
38661
  }
38624
38662
  });
38625
38663
  }
@@ -39089,13 +39127,13 @@ Skills are auto-injected from agent config. Project-wide skills in .gossip/skill
39089
39127
  *
39090
39128
  * Bootstrap critical path stays synchronous and fast.
39091
39129
  */
39092
- applyLedgerAnnotations(content, ledgerPath) {
39130
+ applyLedgerAnnotations(content, ledgerPath2) {
39093
39131
  try {
39094
39132
  const bullets = parseNextSessionBullets(content);
39095
39133
  if (bullets.length === 0) return content;
39096
39134
  let mtime = 0;
39097
39135
  try {
39098
- mtime = (0, import_fs47.statSync)(ledgerPath).mtimeMs;
39136
+ mtime = (0, import_fs47.statSync)(ledgerPath2).mtimeMs;
39099
39137
  } catch {
39100
39138
  }
39101
39139
  const index = readLedgerIndex(this.projectRoot, content, mtime);
@@ -39241,19 +39279,19 @@ function hasControlChars(s) {
39241
39279
  }
39242
39280
  return false;
39243
39281
  }
39244
- async function gitCommonDir(path7) {
39282
+ async function gitCommonDir(path8) {
39245
39283
  try {
39246
39284
  const { stdout } = await execFileP(
39247
39285
  "git",
39248
- ["-C", path7, "rev-parse", "--git-common-dir"],
39286
+ ["-C", path8, "rev-parse", "--git-common-dir"],
39249
39287
  GIT_EXEC_OPTS
39250
39288
  );
39251
39289
  const out = stdout.trim();
39252
39290
  if (!out) return null;
39253
39291
  try {
39254
- return (0, import_fs48.realpathSync)((0, import_path52.resolve)(path7, out));
39292
+ return (0, import_fs48.realpathSync)((0, import_path52.resolve)(path8, out));
39255
39293
  } catch {
39256
- return (0, import_path52.resolve)(path7, out);
39294
+ return (0, import_path52.resolve)(path8, out);
39257
39295
  }
39258
39296
  } catch {
39259
39297
  return null;
@@ -39279,17 +39317,17 @@ function parseWorktreePorcelain(stdout, { includeLocked = false } = {}) {
39279
39317
  const fields = rec.split("\0").filter(Boolean);
39280
39318
  const worktreeField = fields.find((f) => f.startsWith("worktree "));
39281
39319
  if (!worktreeField) continue;
39282
- const path7 = worktreeField.slice("worktree ".length);
39320
+ const path8 = worktreeField.slice("worktree ".length);
39283
39321
  if (fields.some(
39284
39322
  (f) => f === "bare" || !includeLocked && f.startsWith("locked") || f.startsWith("prunable")
39285
39323
  )) {
39286
39324
  continue;
39287
39325
  }
39288
- let canonical = path7;
39326
+ let canonical = path8;
39289
39327
  try {
39290
- canonical = (0, import_fs48.realpathSync)((0, import_path52.resolve)(path7));
39328
+ canonical = (0, import_fs48.realpathSync)((0, import_path52.resolve)(path8));
39291
39329
  } catch {
39292
- canonical = (0, import_path52.resolve)(path7);
39330
+ canonical = (0, import_path52.resolve)(path8);
39293
39331
  }
39294
39332
  out.push(canonical);
39295
39333
  if (out.length >= 100) break;
@@ -40415,6 +40453,89 @@ var init_chatbot_agent = __esm({
40415
40453
  }
40416
40454
  });
40417
40455
 
40456
+ // packages/orchestrator/src/orchestrator-preconditions.ts
40457
+ function detectStaleBase(dispatchSha, originMasterSha, mergeBaseSha) {
40458
+ if (dispatchSha === originMasterSha) {
40459
+ return { stale: false, reason: null };
40460
+ }
40461
+ if (mergeBaseSha === dispatchSha) {
40462
+ return { stale: true, reason: "behind_origin" };
40463
+ }
40464
+ if (mergeBaseSha === originMasterSha) {
40465
+ return { stale: false, reason: "ahead_of_origin" };
40466
+ }
40467
+ return { stale: true, reason: "branched_pre_merge" };
40468
+ }
40469
+ function findUnreadablePaths(paths, canRead) {
40470
+ return paths.filter((p) => !canRead(p));
40471
+ }
40472
+ function extractReferencedPathsWithMeta(taskText) {
40473
+ if (!taskText) {
40474
+ return { paths: [], droppedOverCap: 0 };
40475
+ }
40476
+ const rawTokens = taskText.split(/[\s`]+/);
40477
+ const seen = /* @__PURE__ */ new Set();
40478
+ const out = [];
40479
+ let droppedOverCap = 0;
40480
+ for (const raw of rawTokens) {
40481
+ const trimmed = raw.replace(/^[([{<"']+/, "").replace(/[)\]}>"',.;:]+$/, "");
40482
+ const token = trimmed.replace(/:\d+(?::\d+)?$/, "");
40483
+ if (token.length === 0) {
40484
+ continue;
40485
+ }
40486
+ if (token.startsWith("/") || token.includes("..")) {
40487
+ continue;
40488
+ }
40489
+ if (!REPO_PATH_SHAPE.test(token)) {
40490
+ continue;
40491
+ }
40492
+ if (seen.has(token)) {
40493
+ continue;
40494
+ }
40495
+ seen.add(token);
40496
+ if (out.length >= MAX_REFERENCED_PATHS) {
40497
+ droppedOverCap += 1;
40498
+ continue;
40499
+ }
40500
+ out.push(token);
40501
+ }
40502
+ return { paths: out, droppedOverCap };
40503
+ }
40504
+ function extractReferencedPaths(taskText) {
40505
+ return extractReferencedPathsWithMeta(taskText).paths;
40506
+ }
40507
+ function findUnreadableReferencedPaths(taskText, opts) {
40508
+ return findUnreadableReferencedPathsWithMeta(taskText, opts).unreadable;
40509
+ }
40510
+ function findUnreadableReferencedPathsWithMeta(taskText, opts) {
40511
+ const { paths, droppedOverCap } = extractReferencedPathsWithMeta(taskText);
40512
+ const out = [];
40513
+ const isWorktree = opts.writeMode === "worktree";
40514
+ for (const path8 of paths) {
40515
+ const exists = opts.pathExists(path8);
40516
+ if (!exists) {
40517
+ out.push({ path: path8, reason: "missing" });
40518
+ continue;
40519
+ }
40520
+ if (isWorktree && opts.isGitignoredOrUntracked(path8)) {
40521
+ out.push({ path: path8, reason: "gitignored_in_worktree" });
40522
+ }
40523
+ }
40524
+ return { unreadable: out, droppedOverCap };
40525
+ }
40526
+ function detectMidFlightCommits(commitsBetween) {
40527
+ const count = commitsBetween.length;
40528
+ return { detected: count > 0, count };
40529
+ }
40530
+ var REPO_PATH_SHAPE, MAX_REFERENCED_PATHS;
40531
+ var init_orchestrator_preconditions = __esm({
40532
+ "packages/orchestrator/src/orchestrator-preconditions.ts"() {
40533
+ "use strict";
40534
+ REPO_PATH_SHAPE = /^(?:\.\/)?[\w./-]+\.(?:md|ts|tsx|js|json|txt|ya?ml)$/;
40535
+ MAX_REFERENCED_PATHS = 20;
40536
+ }
40537
+ });
40538
+
40418
40539
  // packages/orchestrator/src/index.ts
40419
40540
  var src_exports3 = {};
40420
40541
  __export(src_exports3, {
@@ -40540,6 +40661,8 @@ __export(src_exports3, {
40540
40661
  defaultVerifierFactory: () => defaultVerifierFactory,
40541
40662
  deriveConsensusId: () => deriveConsensusId,
40542
40663
  detectFormatCompliance: () => detectFormatCompliance,
40664
+ detectMidFlightCommits: () => detectMidFlightCommits,
40665
+ detectStaleBase: () => detectStaleBase,
40543
40666
  discoverAgentIdsForRoot: () => discoverAgentIdsForRoot,
40544
40667
  discoverGitWorktrees: () => discoverGitWorktrees,
40545
40668
  emitCitationFabricatedSignal: () => emitCitationFabricatedSignal,
@@ -40552,11 +40675,16 @@ __export(src_exports3, {
40552
40675
  ensureRulesFile: () => ensureRulesFile,
40553
40676
  extractCategories: () => extractCategories,
40554
40677
  extractConsensusId: () => extractConsensusId,
40678
+ extractReferencedPaths: () => extractReferencedPaths,
40679
+ extractReferencedPathsWithMeta: () => extractReferencedPathsWithMeta,
40555
40680
  extractSpecReferences: () => extractSpecReferences,
40556
40681
  extractTokens: () => extractTokens,
40557
40682
  findBundledHook: () => findBundledHook,
40558
40683
  findBundledRules: () => findBundledRules,
40559
40684
  findOpenSectionLine: () => findOpenSectionLine,
40685
+ findUnreadablePaths: () => findUnreadablePaths,
40686
+ findUnreadableReferencedPaths: () => findUnreadableReferencedPaths,
40687
+ findUnreadableReferencedPathsWithMeta: () => findUnreadableReferencedPathsWithMeta,
40560
40688
  formatCooldownMessage: () => formatCooldownMessage,
40561
40689
  formatStalenessWarning: () => formatStalenessWarning,
40562
40690
  getRoundCounter: () => get,
@@ -40739,6 +40867,7 @@ var init_src4 = __esm({
40739
40867
  init_runtime_config();
40740
40868
  init_runtime_config_schema();
40741
40869
  init_chatbot_agent();
40870
+ init_orchestrator_preconditions();
40742
40871
  }
40743
40872
  });
40744
40873
 
@@ -41958,10 +42087,10 @@ var init_auth = __esm({
41958
42087
  * left half-written by a crash. Validate the shape before trusting it and
41959
42088
  * fail closed (regenerate) on anything unexpected — never throw.
41960
42089
  */
41961
- loadPersisted(path7) {
42090
+ loadPersisted(path8) {
41962
42091
  try {
41963
- if (!(0, import_fs54.existsSync)(path7)) return false;
41964
- const parsed = JSON.parse((0, import_fs54.readFileSync)(path7, "utf8"));
42092
+ if (!(0, import_fs54.existsSync)(path8)) return false;
42093
+ const parsed = JSON.parse((0, import_fs54.readFileSync)(path8, "utf8"));
41965
42094
  if (!isPersistedAuth(parsed)) return false;
41966
42095
  this.key = parsed.key;
41967
42096
  this.sessions.clear();
@@ -42197,9 +42326,9 @@ var init_api_open_findings = __esm({
42197
42326
  });
42198
42327
 
42199
42328
  // packages/relay/src/dashboard/api-overview.ts
42200
- function readSkillStatus(path7) {
42329
+ function readSkillStatus(path8) {
42201
42330
  try {
42202
- const content = (0, import_fs56.readFileSync)(path7, "utf-8");
42331
+ const content = (0, import_fs56.readFileSync)(path8, "utf-8");
42203
42332
  const m = content.match(/^---\n([\s\S]*?)\n---/);
42204
42333
  if (!m) return null;
42205
42334
  const block = m[1];
@@ -42513,9 +42642,9 @@ var init_api_fleet_trend = __esm({
42513
42642
  // packages/relay/src/dashboard/api-agents.ts
42514
42643
  function readSkillFrontmatter(projectRoot, agentId, skillName) {
42515
42644
  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");
42645
+ const path8 = (0, import_path62.join)(projectRoot, ".gossip", "agents", agentId, "skills", `${skillName}.md`);
42646
+ if (!(0, import_fs58.existsSync)(path8)) return null;
42647
+ const raw = (0, import_fs58.readFileSync)(path8, "utf-8");
42519
42648
  if (!raw.startsWith("---")) return null;
42520
42649
  const end = raw.indexOf("\n---", 3);
42521
42650
  if (end === -1) return null;
@@ -42553,9 +42682,9 @@ function normalizeCategory(s) {
42553
42682
  }
42554
42683
  function readForcedDevelops(projectRoot, agentId, category) {
42555
42684
  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");
42685
+ const path8 = (0, import_path62.join)(projectRoot, ".gossip", "forced-skill-develops.jsonl");
42686
+ if (!(0, import_fs58.existsSync)(path8)) return [];
42687
+ const raw = (0, import_fs58.readFileSync)(path8, "utf-8");
42559
42688
  const target = normalizeCategory(category);
42560
42689
  const out = [];
42561
42690
  for (const line of raw.split("\n")) {
@@ -43837,7 +43966,9 @@ async function tasksHandler(projectRoot, query) {
43837
43966
  });
43838
43967
  } else if (entry.type === "task.completed") {
43839
43968
  completed.set(entry.taskId, {
43840
- duration: entry.duration,
43969
+ // On-disk field is "durationMs"; "entry.duration" was previously
43970
+ // undefined, silently dropping all task durations from the response.
43971
+ duration: entry.durationMs ?? entry.duration,
43841
43972
  timestamp: entry.timestamp,
43842
43973
  failed: false,
43843
43974
  inputTokens: entry.inputTokens,
@@ -43873,7 +44004,11 @@ async function tasksHandler(projectRoot, query) {
43873
44004
  result: result?.result,
43874
44005
  status: result ? result.cancelled ? "cancelled" : result.failed ? "failed" : "completed" : "running",
43875
44006
  duration: result?.duration,
44007
+ // timestamp = completion time for terminal tasks (used as "Completed" node in timeline).
44008
+ // For running tasks, falls back to createdAt.
43876
44009
  timestamp: result?.timestamp || info.timestamp,
44010
+ // createdAt = always the dispatch time (task.created event timestamp).
44011
+ createdAt: info.timestamp,
43877
44012
  inputTokens: result?.inputTokens,
43878
44013
  outputTokens: result?.outputTokens
43879
44014
  });
@@ -43891,14 +44026,149 @@ var init_api_tasks = __esm({
43891
44026
  }
43892
44027
  });
43893
44028
 
44029
+ // packages/relay/src/dashboard/api-task-detail.ts
44030
+ function readJsonlLines(filePath) {
44031
+ const out = [];
44032
+ const archive = filePath + ".1";
44033
+ if ((0, import_fs67.existsSync)(archive)) {
44034
+ out.push(...(0, import_fs67.readFileSync)(archive, "utf-8").split("\n").filter(Boolean));
44035
+ }
44036
+ if ((0, import_fs67.existsSync)(filePath)) {
44037
+ out.push(...(0, import_fs67.readFileSync)(filePath, "utf-8").split("\n").filter(Boolean));
44038
+ }
44039
+ return out;
44040
+ }
44041
+ async function taskDetailHandler(projectRoot, taskId) {
44042
+ const graphPath = (0, import_path74.join)(projectRoot, ".gossip", "task-graph.jsonl");
44043
+ if (!(0, import_fs67.existsSync)(graphPath) && !(0, import_fs67.existsSync)(graphPath + ".1")) {
44044
+ return null;
44045
+ }
44046
+ const created = /* @__PURE__ */ new Map();
44047
+ const completed = /* @__PURE__ */ new Map();
44048
+ try {
44049
+ const lines = readJsonlLines(graphPath);
44050
+ for (const line of lines) {
44051
+ try {
44052
+ const entry = JSON.parse(line);
44053
+ if (entry.type === "task.created") {
44054
+ created.set(entry.taskId, {
44055
+ agentId: entry.agentId || "?",
44056
+ task: entry.task || "",
44057
+ timestamp: entry.timestamp
44058
+ });
44059
+ } else if (entry.type === "task.completed") {
44060
+ completed.set(entry.taskId, {
44061
+ duration: entry.durationMs ?? entry.duration,
44062
+ timestamp: entry.timestamp,
44063
+ failed: false,
44064
+ inputTokens: entry.inputTokens,
44065
+ outputTokens: entry.outputTokens,
44066
+ result: typeof entry.result === "string" ? entry.result : void 0
44067
+ });
44068
+ } else if (entry.type === "task.failed") {
44069
+ completed.set(entry.taskId, { timestamp: entry.timestamp, failed: true });
44070
+ } else if (entry.type === "task.cancelled") {
44071
+ completed.set(entry.taskId, { timestamp: entry.timestamp, failed: false, cancelled: true });
44072
+ }
44073
+ } catch {
44074
+ }
44075
+ }
44076
+ } catch {
44077
+ return null;
44078
+ }
44079
+ const info = created.get(taskId);
44080
+ if (!info) return null;
44081
+ const result = completed.get(taskId);
44082
+ const base = {
44083
+ taskId,
44084
+ agentId: info.agentId,
44085
+ task: info.task,
44086
+ result: result?.result,
44087
+ status: result ? result.cancelled ? "cancelled" : result.failed ? "failed" : "completed" : "running",
44088
+ duration: result?.duration,
44089
+ timestamp: result?.timestamp || info.timestamp,
44090
+ createdAt: info.timestamp,
44091
+ inputTokens: result?.inputTokens,
44092
+ outputTokens: result?.outputTokens
44093
+ };
44094
+ let consensusId;
44095
+ let signalCount = 0;
44096
+ const siblingSet = /* @__PURE__ */ new Set();
44097
+ const perfPath = (0, import_path74.join)(projectRoot, ".gossip", "agent-performance.jsonl");
44098
+ try {
44099
+ const lines = readJsonlLines(perfPath);
44100
+ const allEntries = [];
44101
+ for (const line of lines) {
44102
+ try {
44103
+ const entry = JSON.parse(line);
44104
+ if (typeof entry.taskId !== "string") continue;
44105
+ allEntries.push(entry);
44106
+ if (entry.taskId === taskId) {
44107
+ signalCount++;
44108
+ if (!consensusId && typeof entry.consensusId === "string" && entry.consensusId) {
44109
+ consensusId = entry.consensusId;
44110
+ }
44111
+ }
44112
+ } catch {
44113
+ }
44114
+ }
44115
+ if (consensusId) {
44116
+ for (const entry of allEntries) {
44117
+ if (siblingSet.size >= SIBLING_CAP) break;
44118
+ if (entry.consensusId === consensusId && typeof entry.taskId === "string" && entry.taskId && entry.taskId !== taskId) {
44119
+ siblingSet.add(entry.taskId);
44120
+ }
44121
+ }
44122
+ }
44123
+ } catch {
44124
+ }
44125
+ let findingCount = 0;
44126
+ if (consensusId) {
44127
+ const prefix = `${consensusId}:`;
44128
+ const findingsPath = (0, import_path74.join)(projectRoot, ".gossip", "implementation-findings.jsonl");
44129
+ try {
44130
+ const lines = readJsonlLines(findingsPath);
44131
+ for (const line of lines) {
44132
+ try {
44133
+ const entry = JSON.parse(line);
44134
+ if (typeof entry.taskId === "string" && entry.taskId.startsWith(prefix)) {
44135
+ findingCount++;
44136
+ }
44137
+ } catch {
44138
+ }
44139
+ }
44140
+ } catch {
44141
+ }
44142
+ }
44143
+ const siblingTaskIds = siblingSet.size > 0 ? [...siblingSet] : void 0;
44144
+ const siblingsTruncated = siblingSet.size >= SIBLING_CAP;
44145
+ return {
44146
+ ...base,
44147
+ ...consensusId !== void 0 && { consensusId },
44148
+ ...siblingTaskIds !== void 0 && { siblingTaskIds },
44149
+ ...siblingsTruncated && { siblingsTruncated },
44150
+ signalCount,
44151
+ findingCount
44152
+ };
44153
+ }
44154
+ var import_fs67, import_path74, SIBLING_CAP;
44155
+ var init_api_task_detail = __esm({
44156
+ "packages/relay/src/dashboard/api-task-detail.ts"() {
44157
+ "use strict";
44158
+ import_fs67 = require("fs");
44159
+ import_path74 = require("path");
44160
+ SIBLING_CAP = 25;
44161
+ }
44162
+ });
44163
+
43894
44164
  // packages/relay/src/dashboard/api-active-tasks.ts
43895
44165
  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: [] };
44166
+ const taskGraphPath = (0, import_path75.join)(projectRoot, ".gossip", "task-graph.jsonl");
44167
+ if (!(0, import_fs68.existsSync)(taskGraphPath)) return { tasks: [] };
43898
44168
  const created = /* @__PURE__ */ new Map();
43899
44169
  const finished = /* @__PURE__ */ new Set();
43900
44170
  try {
43901
- const lines = (0, import_fs67.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
44171
+ const lines = (0, import_fs68.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
43902
44172
  for (const line of lines) {
43903
44173
  try {
43904
44174
  const ev = JSON.parse(line);
@@ -43926,19 +44196,19 @@ async function activeTasksHandler(projectRoot) {
43926
44196
  active.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
43927
44197
  return { tasks: active.slice(0, 10) };
43928
44198
  }
43929
- var import_fs67, import_path74;
44199
+ var import_fs68, import_path75;
43930
44200
  var init_api_active_tasks = __esm({
43931
44201
  "packages/relay/src/dashboard/api-active-tasks.ts"() {
43932
44202
  "use strict";
43933
- import_fs67 = require("fs");
43934
- import_path74 = require("path");
44203
+ import_fs68 = require("fs");
44204
+ import_path75 = require("path");
43935
44205
  init_utility_agents();
43936
44206
  }
43937
44207
  });
43938
44208
 
43939
44209
  // packages/relay/src/dashboard/api-session.ts
43940
44210
  function resolveGitBranch(cwd) {
43941
- return new Promise((resolve32) => {
44211
+ return new Promise((resolve33) => {
43942
44212
  let done = false;
43943
44213
  const child = (0, import_node_child_process2.execFile)(
43944
44214
  "git",
@@ -43948,21 +44218,21 @@ function resolveGitBranch(cwd) {
43948
44218
  if (done) return;
43949
44219
  done = true;
43950
44220
  if (err) {
43951
- resolve32(null);
44221
+ resolve33(null);
43952
44222
  return;
43953
44223
  }
43954
44224
  const branch = stdout.trim();
43955
44225
  if (!branch || branch === "HEAD") {
43956
- resolve32(null);
44226
+ resolve33(null);
43957
44227
  return;
43958
44228
  }
43959
- resolve32(branch);
44229
+ resolve33(branch);
43960
44230
  }
43961
44231
  );
43962
44232
  child.on("error", () => {
43963
44233
  if (!done) {
43964
44234
  done = true;
43965
- resolve32(null);
44235
+ resolve33(null);
43966
44236
  }
43967
44237
  });
43968
44238
  });
@@ -43974,16 +44244,16 @@ async function sessionHandler(projectRoot) {
43974
44244
  ]);
43975
44245
  return {
43976
44246
  gitBranch,
43977
- projectName: (0, import_path75.basename)(projectRoot),
44247
+ projectName: (0, import_path76.basename)(projectRoot),
43978
44248
  activeTasks
43979
44249
  };
43980
44250
  }
43981
- var import_node_child_process2, import_path75;
44251
+ var import_node_child_process2, import_path76;
43982
44252
  var init_api_session = __esm({
43983
44253
  "packages/relay/src/dashboard/api-session.ts"() {
43984
44254
  "use strict";
43985
44255
  import_node_child_process2 = require("node:child_process");
43986
- import_path75 = require("path");
44256
+ import_path76 = require("path");
43987
44257
  init_api_active_tasks();
43988
44258
  }
43989
44259
  });
@@ -43997,25 +44267,25 @@ function categorize(text) {
43997
44267
  return "other";
43998
44268
  }
43999
44269
  function logsHandler(projectRoot, query) {
44000
- const logPath = (0, import_path76.join)(projectRoot, ".gossip", "mcp.log");
44001
- if (!(0, import_fs68.existsSync)(logPath)) {
44270
+ const logPath = (0, import_path77.join)(projectRoot, ".gossip", "mcp.log");
44271
+ if (!(0, import_fs69.existsSync)(logPath)) {
44002
44272
  return { entries: [], totalLines: 0, fileSize: 0 };
44003
44273
  }
44004
44274
  const filter = query?.get("filter") || void 0;
44005
44275
  const tail = parseInt(query?.get("tail") || "200", 10);
44006
44276
  const clampedTail = Math.min(Math.max(tail, 10), 2e3);
44007
- const fileSize = (0, import_fs68.statSync)(logPath).size;
44277
+ const fileSize = (0, import_fs69.statSync)(logPath).size;
44008
44278
  const MAX_READ = 512 * 1024;
44009
44279
  const readFrom = Math.max(0, fileSize - MAX_READ);
44010
44280
  const readLen = fileSize - readFrom;
44011
- const fd = (0, import_fs68.openSync)(logPath, "r");
44281
+ const fd = (0, import_fs69.openSync)(logPath, "r");
44012
44282
  let buf = Buffer.alloc(0);
44013
44283
  try {
44014
44284
  buf = Buffer.allocUnsafe(readLen);
44015
- const bytesRead = (0, import_fs68.readSync)(fd, buf, 0, readLen, readFrom);
44285
+ const bytesRead = (0, import_fs69.readSync)(fd, buf, 0, readLen, readFrom);
44016
44286
  buf = buf.subarray(0, bytesRead);
44017
44287
  } finally {
44018
- (0, import_fs68.closeSync)(fd);
44288
+ (0, import_fs69.closeSync)(fd);
44019
44289
  }
44020
44290
  let raw = buf.toString("utf-8");
44021
44291
  let lineOffset = 0;
@@ -44023,13 +44293,13 @@ function logsHandler(projectRoot, query) {
44023
44293
  const nl = raw.indexOf("\n");
44024
44294
  raw = nl >= 0 ? raw.slice(nl + 1) : raw;
44025
44295
  const SCAN_CHUNK = 64 * 1024;
44026
- const scanFd = (0, import_fs68.openSync)(logPath, "r");
44296
+ const scanFd = (0, import_fs69.openSync)(logPath, "r");
44027
44297
  try {
44028
44298
  let pos = 0;
44029
44299
  const chunk = Buffer.allocUnsafe(SCAN_CHUNK);
44030
44300
  while (pos < readFrom) {
44031
44301
  const len = Math.min(SCAN_CHUNK, readFrom - pos);
44032
- const n = (0, import_fs68.readSync)(scanFd, chunk, 0, len, pos);
44302
+ const n = (0, import_fs69.readSync)(scanFd, chunk, 0, len, pos);
44033
44303
  if (n === 0) break;
44034
44304
  for (let j = 0; j < n; j++) {
44035
44305
  if (chunk[j] === 10) lineOffset++;
@@ -44037,7 +44307,7 @@ function logsHandler(projectRoot, query) {
44037
44307
  pos += n;
44038
44308
  }
44039
44309
  } finally {
44040
- (0, import_fs68.closeSync)(scanFd);
44310
+ (0, import_fs69.closeSync)(scanFd);
44041
44311
  }
44042
44312
  }
44043
44313
  const allLines = raw.split("\n").filter(Boolean);
@@ -44055,12 +44325,12 @@ function logsHandler(projectRoot, query) {
44055
44325
  entries = entries.slice(-clampedTail);
44056
44326
  return { entries, totalLines, fileSize, filter };
44057
44327
  }
44058
- var import_fs68, import_path76, CATEGORY_PATTERNS2;
44328
+ var import_fs69, import_path77, CATEGORY_PATTERNS2;
44059
44329
  var init_api_logs = __esm({
44060
44330
  "packages/relay/src/dashboard/api-logs.ts"() {
44061
44331
  "use strict";
44062
- import_fs68 = require("fs");
44063
- import_path76 = require("path");
44332
+ import_fs69 = require("fs");
44333
+ import_path77 = require("path");
44064
44334
  CATEGORY_PATTERNS2 = [
44065
44335
  [/^\[worker:/, "worker"],
44066
44336
  [/^\[Gemini\]/, "gemini"],
@@ -44092,11 +44362,11 @@ function violationsHandler(projectRoot, query) {
44092
44362
  const page = Math.max(1, parseInt(query?.get("page") ?? "1", 10));
44093
44363
  const pageSize = Math.min(100, Math.max(1, parseInt(query?.get("pageSize") ?? "25", 10)));
44094
44364
  const agentFilter = query?.get("agentId") ?? null;
44095
- const filePath = (0, import_path77.join)(projectRoot, FILE);
44096
- if (!(0, import_fs69.existsSync)(filePath)) {
44365
+ const filePath = (0, import_path78.join)(projectRoot, FILE);
44366
+ if (!(0, import_fs70.existsSync)(filePath)) {
44097
44367
  return { items: [], total: 0, page, pageSize };
44098
44368
  }
44099
- const raw = (0, import_fs69.readFileSync)(filePath, "utf-8");
44369
+ const raw = (0, import_fs70.readFileSync)(filePath, "utf-8");
44100
44370
  const lines = raw.trim().split("\n").filter(Boolean);
44101
44371
  const entries = [];
44102
44372
  for (const line of lines) {
@@ -44116,12 +44386,12 @@ function violationsHandler(projectRoot, query) {
44116
44386
  const start = (page - 1) * pageSize;
44117
44387
  return { items: entries.slice(start, start + pageSize), total, page, pageSize };
44118
44388
  }
44119
- var import_fs69, import_path77, FILE;
44389
+ var import_fs70, import_path78, FILE;
44120
44390
  var init_api_violations = __esm({
44121
44391
  "packages/relay/src/dashboard/api-violations.ts"() {
44122
44392
  "use strict";
44123
- import_fs69 = require("fs");
44124
- import_path77 = require("path");
44393
+ import_fs70 = require("fs");
44394
+ import_path78 = require("path");
44125
44395
  FILE = ".gossip/process-violations.jsonl";
44126
44396
  }
44127
44397
  });
@@ -44217,12 +44487,12 @@ function isMirrorFrameShaped(obj) {
44217
44487
  const f = obj;
44218
44488
  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
44489
  }
44220
- var import_fs70, import_path78, CHAT_ID_RE, PERSIST_CAP, MAX_LINE_BYTES, NullChatStore, FileChatStore;
44490
+ var import_fs71, import_path79, CHAT_ID_RE, PERSIST_CAP, MAX_LINE_BYTES, NullChatStore, FileChatStore;
44221
44491
  var init_chat_store = __esm({
44222
44492
  "packages/relay/src/dashboard/chat-store.ts"() {
44223
44493
  "use strict";
44224
- import_fs70 = require("fs");
44225
- import_path78 = require("path");
44494
+ import_fs71 = require("fs");
44495
+ import_path79 = require("path");
44226
44496
  CHAT_ID_RE = /^[a-zA-Z0-9_-]{1,128}$/;
44227
44497
  PERSIST_CAP = 1e3;
44228
44498
  MAX_LINE_BYTES = 256 * 1024;
@@ -44254,15 +44524,15 @@ var init_chat_store = __esm({
44254
44524
  return CHAT_ID_RE.test(chatId);
44255
44525
  }
44256
44526
  filePath(chatId) {
44257
- return (0, import_path78.join)(this.chatDir, `${chatId}.jsonl`);
44527
+ return (0, import_path79.join)(this.chatDir, `${chatId}.jsonl`);
44258
44528
  }
44259
44529
  append(chatId, frame) {
44260
44530
  if (!this.isValidChatId(chatId)) return;
44261
44531
  if (chatId.startsWith("_")) return;
44262
44532
  try {
44263
- (0, import_fs70.mkdirSync)(this.chatDir, { recursive: true });
44533
+ (0, import_fs71.mkdirSync)(this.chatDir, { recursive: true });
44264
44534
  const line = JSON.stringify(frame) + "\n";
44265
- (0, import_fs70.appendFileSync)(this.filePath(chatId), line, "utf8");
44535
+ (0, import_fs71.appendFileSync)(this.filePath(chatId), line, "utf8");
44266
44536
  const prev = this.appendCounters.get(chatId);
44267
44537
  const count = (prev ?? 0) + 1;
44268
44538
  this.appendCounters.set(chatId, count);
@@ -44278,13 +44548,13 @@ var init_chat_store = __esm({
44278
44548
  if (chatId.startsWith("_")) return;
44279
44549
  try {
44280
44550
  const fp = this.filePath(chatId);
44281
- const content = (0, import_fs70.readFileSync)(fp, "utf8");
44551
+ const content = (0, import_fs71.readFileSync)(fp, "utf8");
44282
44552
  const lines = content.split("\n").filter((l) => l.length > 0);
44283
44553
  if (lines.length < 2 * PERSIST_CAP) return;
44284
44554
  const kept = lines.slice(lines.length - PERSIST_CAP);
44285
44555
  const tmp = fp + ".tmp";
44286
- (0, import_fs70.writeFileSync)(tmp, kept.join("\n") + "\n", "utf8");
44287
- (0, import_fs70.renameSync)(tmp, fp);
44556
+ (0, import_fs71.writeFileSync)(tmp, kept.join("\n") + "\n", "utf8");
44557
+ (0, import_fs71.renameSync)(tmp, fp);
44288
44558
  } catch (err) {
44289
44559
  this.cleanupStaleTmp(chatId);
44290
44560
  console.warn(`[chat-store] retain failed for chatId=${chatId}`, err);
@@ -44299,7 +44569,7 @@ var init_chat_store = __esm({
44299
44569
  */
44300
44570
  cleanupStaleTmp(chatId) {
44301
44571
  try {
44302
- (0, import_fs70.unlinkSync)(this.filePath(chatId) + ".tmp");
44572
+ (0, import_fs71.unlinkSync)(this.filePath(chatId) + ".tmp");
44303
44573
  } catch (err) {
44304
44574
  if (err?.code !== "ENOENT") {
44305
44575
  console.warn(`[chat-store] stale .tmp cleanup failed for chatId=${chatId}:`, err);
@@ -44311,7 +44581,7 @@ var init_chat_store = __esm({
44311
44581
  this.cleanupStaleTmp(chatId);
44312
44582
  let content;
44313
44583
  try {
44314
- content = (0, import_fs70.readFileSync)(this.filePath(chatId), "utf8");
44584
+ content = (0, import_fs71.readFileSync)(this.filePath(chatId), "utf8");
44315
44585
  } catch (err) {
44316
44586
  if (err?.code === "ENOENT") return [];
44317
44587
  console.warn(`[chat-store] load failed for chatId=${chatId}:`, err);
@@ -44341,7 +44611,7 @@ var init_chat_store = __esm({
44341
44611
  drop(chatId) {
44342
44612
  if (!this.isValidChatId(chatId)) return;
44343
44613
  try {
44344
- (0, import_fs70.unlinkSync)(this.filePath(chatId));
44614
+ (0, import_fs71.unlinkSync)(this.filePath(chatId));
44345
44615
  } catch (err) {
44346
44616
  if (err?.code !== "ENOENT") {
44347
44617
  console.warn(`[chat-store] drop failed for chatId=${chatId}:`, err);
@@ -45552,20 +45822,20 @@ function normalizeLegacyDegradedFields(report) {
45552
45822
  }
45553
45823
  function resolveDashboardRoot(projectRoot) {
45554
45824
  const candidates = [
45555
- (0, import_path79.resolve)(__dirname, "..", "dist-dashboard"),
45825
+ (0, import_path80.resolve)(__dirname, "..", "dist-dashboard"),
45556
45826
  // bundled: dist-mcp/mcp-server.js → ../dist-dashboard
45557
- (0, import_path79.resolve)(__dirname, "..", "..", "..", "..", "dist-dashboard"),
45827
+ (0, import_path80.resolve)(__dirname, "..", "..", "..", "..", "dist-dashboard"),
45558
45828
  // tsc dev: packages/relay/dist/dashboard → repo-root
45559
- (0, import_path79.join)(projectRoot, "dist-dashboard")
45829
+ (0, import_path80.join)(projectRoot, "dist-dashboard")
45560
45830
  // legacy dev fallback (git-clone running from repo root)
45561
45831
  ];
45562
45832
  for (const p of candidates) {
45563
- if ((0, import_fs71.existsSync)(p)) return p;
45833
+ if ((0, import_fs72.existsSync)(p)) return p;
45564
45834
  }
45565
45835
  return null;
45566
45836
  }
45567
45837
  function readBody(req, maxBytes = MAX_BODY_SIZE) {
45568
- return new Promise((resolve32, reject) => {
45838
+ return new Promise((resolve33, reject) => {
45569
45839
  const chunks = [];
45570
45840
  let size = 0;
45571
45841
  let tooLarge = false;
@@ -45580,14 +45850,14 @@ function readBody(req, maxBytes = MAX_BODY_SIZE) {
45580
45850
  chunks.push(chunk);
45581
45851
  });
45582
45852
  req.on("end", () => {
45583
- if (!tooLarge) resolve32(Buffer.concat(chunks).toString("utf-8"));
45853
+ if (!tooLarge) resolve33(Buffer.concat(chunks).toString("utf-8"));
45584
45854
  });
45585
45855
  req.on("error", (err) => {
45586
45856
  if (!tooLarge) reject(err);
45587
45857
  });
45588
45858
  });
45589
45859
  }
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;
45860
+ 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
45861
  var init_routes = __esm({
45592
45862
  "packages/relay/src/dashboard/routes.ts"() {
45593
45863
  "use strict";
@@ -45607,6 +45877,7 @@ var init_routes = __esm({
45607
45877
  init_api_open_findings();
45608
45878
  init_api_learnings();
45609
45879
  init_api_tasks();
45880
+ init_api_task_detail();
45610
45881
  init_api_active_tasks();
45611
45882
  init_api_session();
45612
45883
  init_api_logs();
@@ -45615,8 +45886,8 @@ var init_routes = __esm({
45615
45886
  init_api_bridge();
45616
45887
  init_chat_session_store();
45617
45888
  init_src4();
45618
- import_fs71 = require("fs");
45619
- import_path79 = require("path");
45889
+ import_fs72 = require("fs");
45890
+ import_path80 = require("path");
45620
45891
  import_crypto28 = require("crypto");
45621
45892
  AUTH_MAX_ATTEMPTS = 10;
45622
45893
  AUTH_LOCKOUT_MS = 6e4;
@@ -45634,7 +45905,7 @@ var init_routes = __esm({
45634
45905
  this.projectRoot = projectRoot;
45635
45906
  this.ctx = ctx2;
45636
45907
  this.dashboardRoot = resolveDashboardRoot(projectRoot);
45637
- this.bridge = new BridgeHub({ chatDir: (0, import_path79.join)(projectRoot, ".gossip", "chat") });
45908
+ this.bridge = new BridgeHub({ chatDir: (0, import_path80.join)(projectRoot, ".gossip", "chat") });
45638
45909
  }
45639
45910
  auth;
45640
45911
  projectRoot;
@@ -45935,6 +46206,19 @@ var init_routes = __esm({
45935
46206
  this.json(res, 200, data);
45936
46207
  return true;
45937
46208
  }
46209
+ {
46210
+ const m = url2.match(/^\/dashboard\/api\/tasks\/([^/]+)$/);
46211
+ if (m && req.method === "GET") {
46212
+ const taskId = decodeURIComponent(m[1]);
46213
+ const data = await taskDetailHandler(this.projectRoot, taskId);
46214
+ if (data === null) {
46215
+ this.json(res, 404, { error: `Task not found: ${taskId}` });
46216
+ } else {
46217
+ this.json(res, 200, data);
46218
+ }
46219
+ return true;
46220
+ }
46221
+ }
45938
46222
  if (url2 === "/dashboard/api/active-tasks" && req.method === "GET") {
45939
46223
  const data = await activeTasksHandler(this.projectRoot);
45940
46224
  this.json(res, 200, data);
@@ -46147,13 +46431,13 @@ var init_routes = __esm({
46147
46431
  res.end("Dashboard assets not found. Reinstall gossipcat or rebuild from source.");
46148
46432
  return true;
46149
46433
  }
46150
- const htmlPath = (0, import_path79.join)(this.dashboardRoot, "index.html");
46151
- if (!(0, import_fs71.existsSync)(htmlPath)) {
46434
+ const htmlPath = (0, import_path80.join)(this.dashboardRoot, "index.html");
46435
+ if (!(0, import_fs72.existsSync)(htmlPath)) {
46152
46436
  res.writeHead(503, { "Content-Type": "text/plain" });
46153
46437
  res.end(`Dashboard index.html missing at ${this.dashboardRoot}. Reinstall gossipcat.`);
46154
46438
  return true;
46155
46439
  }
46156
- const html = (0, import_fs71.readFileSync)(htmlPath, "utf-8");
46440
+ const html = (0, import_fs72.readFileSync)(htmlPath, "utf-8");
46157
46441
  res.writeHead(200, {
46158
46442
  "Content-Type": "text/html; charset=utf-8",
46159
46443
  "Cache-Control": "no-cache"
@@ -46182,16 +46466,16 @@ var init_routes = __esm({
46182
46466
  const ext = "." + (relativePath.split(".").pop() || "");
46183
46467
  const mime = MIME[ext];
46184
46468
  if (!mime) return false;
46185
- const filePath = (0, import_path79.join)(this.dashboardRoot, relativePath);
46469
+ const filePath = (0, import_path80.join)(this.dashboardRoot, relativePath);
46186
46470
  try {
46187
- const realFile = (0, import_fs71.realpathSync)(filePath);
46188
- const realBase = (0, import_fs71.realpathSync)(this.dashboardRoot);
46471
+ const realFile = (0, import_fs72.realpathSync)(filePath);
46472
+ const realBase = (0, import_fs72.realpathSync)(this.dashboardRoot);
46189
46473
  if (!realFile.startsWith(realBase + "/")) {
46190
46474
  res.writeHead(404);
46191
46475
  res.end();
46192
46476
  return true;
46193
46477
  }
46194
- const data = (0, import_fs71.readFileSync)(realFile);
46478
+ const data = (0, import_fs72.readFileSync)(realFile);
46195
46479
  res.writeHead(200, { "Content-Type": mime, "Cache-Control": "public, max-age=86400" });
46196
46480
  res.end(data);
46197
46481
  return true;
@@ -46206,8 +46490,8 @@ var init_routes = __esm({
46206
46490
  return match ? match[1] : null;
46207
46491
  }
46208
46492
  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");
46493
+ const { readdirSync: readdirSync22, readFileSync: readFileSync70, existsSync: existsSync74 } = require("fs");
46494
+ const reportsDir = (0, import_path80.join)(this.projectRoot, ".gossip", "consensus-reports");
46211
46495
  let retractedConsensusIds = [];
46212
46496
  let roundRetractions = [];
46213
46497
  try {
@@ -46217,13 +46501,13 @@ var init_routes = __esm({
46217
46501
  roundRetractions = reader.getRoundRetractions();
46218
46502
  } catch {
46219
46503
  }
46220
- if (!existsSync73(reportsDir)) return { reports: [], totalReports: 0, page, pageSize, retractedConsensusIds, roundRetractions };
46504
+ if (!existsSync74(reportsDir)) return { reports: [], totalReports: 0, page, pageSize, retractedConsensusIds, roundRetractions };
46221
46505
  try {
46222
46506
  const { statSync: statSync36 } = require("fs");
46223
46507
  const allFiles = readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).sort((a, b) => {
46224
46508
  try {
46225
- const aTime = statSync36((0, import_path79.join)(reportsDir, a)).mtimeMs;
46226
- const bTime = statSync36((0, import_path79.join)(reportsDir, b)).mtimeMs;
46509
+ const aTime = statSync36((0, import_path80.join)(reportsDir, a)).mtimeMs;
46510
+ const bTime = statSync36((0, import_path80.join)(reportsDir, b)).mtimeMs;
46227
46511
  return bTime - aTime;
46228
46512
  } catch {
46229
46513
  return 0;
@@ -46234,13 +46518,13 @@ var init_routes = __esm({
46234
46518
  const clampedPage = Math.max(page, 1);
46235
46519
  const start = (clampedPage - 1) * clampedPageSize;
46236
46520
  const files = allFiles.slice(start, start + clampedPageSize);
46237
- const realReportsDir = (0, import_fs71.realpathSync)(reportsDir);
46521
+ const realReportsDir = (0, import_fs72.realpathSync)(reportsDir);
46238
46522
  const reports = files.map((f) => {
46239
46523
  try {
46240
- const filePath = (0, import_path79.join)(reportsDir, f);
46241
- const realFile = (0, import_fs71.realpathSync)(filePath);
46524
+ const filePath = (0, import_path80.join)(reportsDir, f);
46525
+ const realFile = (0, import_fs72.realpathSync)(filePath);
46242
46526
  if (!realFile.startsWith(realReportsDir + "/")) return null;
46243
- return normalizeLegacyDegradedFields(JSON.parse(readFileSync69(realFile, "utf-8")));
46527
+ return normalizeLegacyDegradedFields(JSON.parse(readFileSync70(realFile, "utf-8")));
46244
46528
  } catch {
46245
46529
  return null;
46246
46530
  }
@@ -46251,29 +46535,29 @@ var init_routes = __esm({
46251
46535
  }
46252
46536
  }
46253
46537
  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");
46538
+ const { readdirSync: readdirSync22, readFileSync: readFileSync70, renameSync: renameSync18, writeFileSync: writeFileSync38, mkdirSync: mkdirSync45, existsSync: existsSync74 } = require("fs");
46539
+ const reportsDir = (0, import_path80.join)(this.projectRoot, ".gossip", "consensus-reports");
46540
+ const archiveDir = (0, import_path80.join)(this.projectRoot, ".gossip", "consensus-reports-archive");
46257
46541
  let archived = 0;
46258
- if (existsSync73(reportsDir)) {
46542
+ if (existsSync74(reportsDir)) {
46259
46543
  const files = readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).sort().reverse();
46260
46544
  if (files.length > 5) {
46261
46545
  mkdirSync45(archiveDir, { recursive: true });
46262
46546
  const toArchive = files.slice(5);
46263
46547
  for (const f of toArchive) {
46264
46548
  try {
46265
- renameSync18((0, import_path79.join)(reportsDir, f), (0, import_path79.join)(archiveDir, f));
46549
+ renameSync18((0, import_path80.join)(reportsDir, f), (0, import_path80.join)(archiveDir, f));
46266
46550
  archived++;
46267
46551
  } catch {
46268
46552
  }
46269
46553
  }
46270
46554
  }
46271
46555
  }
46272
- const findingsPath = (0, import_path79.join)(this.projectRoot, ".gossip", "implementation-findings.jsonl");
46556
+ const findingsPath = (0, import_path80.join)(this.projectRoot, ".gossip", "implementation-findings.jsonl");
46273
46557
  let findingsCleared = 0;
46274
- if (existsSync73(findingsPath)) {
46558
+ if (existsSync74(findingsPath)) {
46275
46559
  try {
46276
- const lines = readFileSync69(findingsPath, "utf-8").trim().split("\n").filter(Boolean);
46560
+ const lines = readFileSync70(findingsPath, "utf-8").trim().split("\n").filter(Boolean);
46277
46561
  const kept = lines.filter((line) => {
46278
46562
  try {
46279
46563
  const entry = JSON.parse(line);
@@ -46290,7 +46574,7 @@ var init_routes = __esm({
46290
46574
  } catch {
46291
46575
  }
46292
46576
  }
46293
- const remaining = existsSync73(reportsDir) ? readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).length : 0;
46577
+ const remaining = existsSync74(reportsDir) ? readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).length : 0;
46294
46578
  return { archived, remaining, findingsCleared };
46295
46579
  }
46296
46580
  json(res, status, data) {
@@ -46303,14 +46587,14 @@ var init_routes = __esm({
46303
46587
  });
46304
46588
 
46305
46589
  // packages/relay/src/dashboard/ws.ts
46306
- var import_fs72, import_fs73, import_path80, DashboardWs;
46590
+ var import_fs73, import_fs74, import_path81, DashboardWs;
46307
46591
  var init_ws = __esm({
46308
46592
  "packages/relay/src/dashboard/ws.ts"() {
46309
46593
  "use strict";
46310
46594
  init_wrapper();
46311
- import_fs72 = require("fs");
46312
46595
  import_fs73 = require("fs");
46313
- import_path80 = require("path");
46596
+ import_fs74 = require("fs");
46597
+ import_path81 = require("path");
46314
46598
  DashboardWs = class {
46315
46599
  clients = /* @__PURE__ */ new Set();
46316
46600
  logWatcher = null;
@@ -46335,15 +46619,15 @@ var init_ws = __esm({
46335
46619
  /** Start watching mcp.log for new lines and broadcasting them to connected clients. */
46336
46620
  startLogWatcher(projectRoot) {
46337
46621
  this.stopLogWatcher();
46338
- this.logPath = (0, import_path80.join)(projectRoot, ".gossip", "mcp.log");
46339
- if (!(0, import_fs72.existsSync)(this.logPath)) return;
46622
+ this.logPath = (0, import_path81.join)(projectRoot, ".gossip", "mcp.log");
46623
+ if (!(0, import_fs73.existsSync)(this.logPath)) return;
46340
46624
  try {
46341
- this.logOffset = (0, import_fs72.statSync)(this.logPath).size;
46625
+ this.logOffset = (0, import_fs73.statSync)(this.logPath).size;
46342
46626
  } catch {
46343
46627
  this.logOffset = 0;
46344
46628
  }
46345
46629
  try {
46346
- this.logWatcher = (0, import_fs73.watch)(this.logPath, () => {
46630
+ this.logWatcher = (0, import_fs74.watch)(this.logPath, () => {
46347
46631
  if (this.clients.size === 0) return;
46348
46632
  this.readNewLines();
46349
46633
  });
@@ -46360,7 +46644,7 @@ var init_ws = __esm({
46360
46644
  if (this.logReading) return;
46361
46645
  this.logReading = true;
46362
46646
  try {
46363
- const currentSize = (0, import_fs72.statSync)(this.logPath).size;
46647
+ const currentSize = (0, import_fs73.statSync)(this.logPath).size;
46364
46648
  if (currentSize < this.logOffset) {
46365
46649
  this.logOffset = 0;
46366
46650
  this.logCarry = "";
@@ -46373,7 +46657,7 @@ var init_ws = __esm({
46373
46657
  const readFrom = capped ? (this.logCarry = "", this.logCapped = true, currentSize - 65536) : (this.logCapped = false, this.logOffset);
46374
46658
  let stream;
46375
46659
  try {
46376
- stream = (0, import_fs72.createReadStream)(this.logPath, { start: readFrom, end: currentSize - 1 });
46660
+ stream = (0, import_fs73.createReadStream)(this.logPath, { start: readFrom, end: currentSize - 1 });
46377
46661
  } catch {
46378
46662
  this.logReading = false;
46379
46663
  return;
@@ -46487,7 +46771,7 @@ var init_server = __esm({
46487
46771
  return this.heartbeatRunning;
46488
46772
  }
46489
46773
  async start() {
46490
- return new Promise((resolve32) => {
46774
+ return new Promise((resolve33) => {
46491
46775
  this.httpServer = (0, import_http.createServer)(this.handleHttp.bind(this));
46492
46776
  if (this.config.dashboard) {
46493
46777
  this.dashboardAuth = new DashboardAuth();
@@ -46533,7 +46817,7 @@ var init_server = __esm({
46533
46817
  this.httpServer.listen(this.config.port, this.config.host ?? "127.0.0.1", () => {
46534
46818
  const addr = this.httpServer.address();
46535
46819
  this._port = addr.port;
46536
- resolve32();
46820
+ resolve33();
46537
46821
  });
46538
46822
  });
46539
46823
  }
@@ -46553,9 +46837,9 @@ var init_server = __esm({
46553
46837
  for (const client of this.wss.clients) {
46554
46838
  client.close(1001, "Server shutting down");
46555
46839
  }
46556
- return new Promise((resolve32) => {
46840
+ return new Promise((resolve33) => {
46557
46841
  this.wss.close(() => {
46558
- this.httpServer.close(() => resolve32());
46842
+ this.httpServer.close(() => resolve33());
46559
46843
  });
46560
46844
  });
46561
46845
  }
@@ -46969,8 +47253,8 @@ function parsePorcelain(output) {
46969
47253
  const paths = [];
46970
47254
  for (const line of lines) {
46971
47255
  if (line.length < 4) continue;
46972
- const path7 = line.slice(3);
46973
- if (path7) paths.push(path7);
47256
+ const path8 = line.slice(3);
47257
+ if (path8) paths.push(path8);
46974
47258
  }
46975
47259
  return paths.sort();
46976
47260
  }
@@ -46993,12 +47277,12 @@ function revertLeakedPaths(cwd, paths) {
46993
47277
  if (!paths || paths.length === 0) return result;
46994
47278
  const { safe: safePaths, rejected } = filterSafePaths(paths);
46995
47279
  result.rejected = rejected;
46996
- const fs6 = require("fs");
46997
- const path7 = require("path");
47280
+ const fs7 = require("fs");
47281
+ const path8 = require("path");
46998
47282
  const present = [];
46999
47283
  for (const p of safePaths) {
47000
- const abs = path7.join(cwd, p);
47001
- if (fs6.existsSync(abs)) {
47284
+ const abs = path8.join(cwd, p);
47285
+ if (fs7.existsSync(abs)) {
47002
47286
  present.push(p);
47003
47287
  } else {
47004
47288
  result.skipped.push(p);
@@ -47028,12 +47312,12 @@ function preserveLeakedPaths(cwd, paths, taskId) {
47028
47312
  }
47029
47313
  const { safe: safePaths, rejected } = filterSafePaths(paths);
47030
47314
  result.rejected = rejected;
47031
- const fs6 = require("fs");
47032
- const path7 = require("path");
47315
+ const fs7 = require("fs");
47316
+ const path8 = require("path");
47033
47317
  const crypto3 = require("crypto");
47034
47318
  const present = [];
47035
47319
  for (const p of safePaths) {
47036
- if (fs6.existsSync(path7.join(cwd, p))) {
47320
+ if (fs7.existsSync(path8.join(cwd, p))) {
47037
47321
  present.push(p);
47038
47322
  } else {
47039
47323
  result.skipped.push(p);
@@ -47068,16 +47352,16 @@ function preserveLeakedPaths(cwd, paths, taskId) {
47068
47352
  result.emptyDiff = true;
47069
47353
  return result;
47070
47354
  }
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`);
47355
+ const recoveryDir = path8.join(cwd, ".gossip", "recovery");
47356
+ fs7.mkdirSync(recoveryDir, { recursive: true });
47357
+ const finalPath = path8.join(recoveryDir, `${taskId}.patch`);
47358
+ const tmpPath = path8.join(recoveryDir, `${taskId}.patch.${crypto3.randomUUID().slice(0, 8)}.tmp`);
47075
47359
  try {
47076
- fs6.writeFileSync(tmpPath, diff);
47077
- fs6.renameSync(tmpPath, finalPath);
47360
+ fs7.writeFileSync(tmpPath, diff);
47361
+ fs7.renameSync(tmpPath, finalPath);
47078
47362
  } catch (err) {
47079
47363
  try {
47080
- fs6.unlinkSync(tmpPath);
47364
+ fs7.unlinkSync(tmpPath);
47081
47365
  } catch {
47082
47366
  }
47083
47367
  throw err;
@@ -47221,14 +47505,14 @@ __export(sandbox_exports, {
47221
47505
  });
47222
47506
  function rotateIfNeeded2(filePath, maxBytes) {
47223
47507
  try {
47224
- const st = (0, import_fs74.statSync)(filePath);
47508
+ const st = (0, import_fs75.statSync)(filePath);
47225
47509
  if (st.size < maxBytes) return;
47226
47510
  const rotated = filePath + ".1";
47227
47511
  try {
47228
- if ((0, import_fs74.existsSync)(rotated)) (0, import_fs74.unlinkSync)(rotated);
47512
+ if ((0, import_fs75.existsSync)(rotated)) (0, import_fs75.unlinkSync)(rotated);
47229
47513
  } catch {
47230
47514
  }
47231
- (0, import_fs74.renameSync)(filePath, rotated);
47515
+ (0, import_fs75.renameSync)(filePath, rotated);
47232
47516
  } catch {
47233
47517
  }
47234
47518
  }
@@ -47301,9 +47585,9 @@ Tests passing is NOT sufficient verification \u2014 the 2026-04-22 incident had
47301
47585
  }
47302
47586
  function readSandboxMode(projectRoot) {
47303
47587
  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"));
47588
+ const p = (0, import_path82.join)(projectRoot, ".gossip", "config.json");
47589
+ if (!(0, import_fs75.existsSync)(p)) return "warn";
47590
+ const raw = JSON.parse((0, import_fs75.readFileSync)(p, "utf-8"));
47307
47591
  const mode = raw?.sandboxEnforcement;
47308
47592
  if (mode === "off" || mode === "warn" || mode === "block") return mode;
47309
47593
  return "warn";
@@ -47313,8 +47597,8 @@ function readSandboxMode(projectRoot) {
47313
47597
  }
47314
47598
  function recordDispatchMetadata(projectRoot, meta3) {
47315
47599
  try {
47316
- const dir = (0, import_path81.join)(projectRoot, ".gossip");
47317
- (0, import_fs74.mkdirSync)(dir, { recursive: true });
47600
+ const dir = (0, import_path82.join)(projectRoot, ".gossip");
47601
+ (0, import_fs75.mkdirSync)(dir, { recursive: true });
47318
47602
  const snapshotted = { ...meta3 };
47319
47603
  if (meta3.writeMode === "scoped" || meta3.writeMode === "worktree") {
47320
47604
  try {
@@ -47332,15 +47616,15 @@ function recordDispatchMetadata(projectRoot, meta3) {
47332
47616
  } catch {
47333
47617
  }
47334
47618
  }
47335
- (0, import_fs74.appendFileSync)((0, import_path81.join)(dir, METADATA_FILE), JSON.stringify(snapshotted) + "\n");
47619
+ (0, import_fs75.appendFileSync)((0, import_path82.join)(dir, METADATA_FILE), JSON.stringify(snapshotted) + "\n");
47336
47620
  } catch {
47337
47621
  }
47338
47622
  }
47339
47623
  function updateDispatchMetadata(projectRoot, taskId, patch) {
47340
47624
  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");
47625
+ const p = (0, import_path82.join)(projectRoot, ".gossip", METADATA_FILE);
47626
+ if (!(0, import_fs75.existsSync)(p)) return false;
47627
+ const raw = (0, import_fs75.readFileSync)(p, "utf-8");
47344
47628
  const lines = raw.split("\n");
47345
47629
  let patched = false;
47346
47630
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -47358,7 +47642,7 @@ function updateDispatchMetadata(projectRoot, taskId, patch) {
47358
47642
  }
47359
47643
  }
47360
47644
  if (!patched) return false;
47361
- (0, import_fs74.writeFileSync)(p, lines.join("\n"));
47645
+ (0, import_fs75.writeFileSync)(p, lines.join("\n"));
47362
47646
  return true;
47363
47647
  } catch {
47364
47648
  return false;
@@ -47367,15 +47651,15 @@ function updateDispatchMetadata(projectRoot, taskId, patch) {
47367
47651
  function stampTaskSentinel(projectRoot, taskId) {
47368
47652
  if (!taskId) return null;
47369
47653
  try {
47370
- const dir = (0, import_path81.join)(projectRoot, ".gossip", SENTINEL_DIR);
47371
- (0, import_fs74.mkdirSync)(dir, { recursive: true });
47654
+ const dir = (0, import_path82.join)(projectRoot, ".gossip", SENTINEL_DIR);
47655
+ (0, import_fs75.mkdirSync)(dir, { recursive: true });
47372
47656
  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);
47657
+ const path8 = (0, import_path82.join)(dir, `${slug}.sentinel`);
47658
+ const fd = (0, import_fs75.openSync)(path8, "w");
47659
+ (0, import_fs75.closeSync)(fd);
47376
47660
  const stampTime = new Date(Date.now() - 2e3);
47377
- (0, import_fs74.utimesSync)(path7, stampTime, stampTime);
47378
- return path7;
47661
+ (0, import_fs75.utimesSync)(path8, stampTime, stampTime);
47662
+ return path8;
47379
47663
  } catch {
47380
47664
  return null;
47381
47665
  }
@@ -47383,15 +47667,15 @@ function stampTaskSentinel(projectRoot, taskId) {
47383
47667
  function cleanupTaskSentinel(sentinelPath) {
47384
47668
  if (!sentinelPath) return;
47385
47669
  try {
47386
- (0, import_fs74.unlinkSync)(sentinelPath);
47670
+ (0, import_fs75.unlinkSync)(sentinelPath);
47387
47671
  } catch {
47388
47672
  }
47389
47673
  }
47390
47674
  function lookupDispatchMetadata(projectRoot, taskId) {
47391
47675
  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");
47676
+ const p = (0, import_path82.join)(projectRoot, ".gossip", METADATA_FILE);
47677
+ if (!(0, import_fs75.existsSync)(p)) return null;
47678
+ const raw = (0, import_fs75.readFileSync)(p, "utf-8");
47395
47679
  const lines = raw.split("\n").filter(Boolean);
47396
47680
  for (let i = lines.length - 1; i >= 0; i--) {
47397
47681
  try {
@@ -47423,21 +47707,21 @@ function parseGitStatus(porcelain) {
47423
47707
  function normalizeScope(scope, projectRoot) {
47424
47708
  let s = scope.trim();
47425
47709
  if (!s) return "";
47426
- if ((0, import_path81.isAbsolute)(s)) {
47427
- s = (0, import_path81.relative)(projectRoot, s);
47710
+ if ((0, import_path82.isAbsolute)(s)) {
47711
+ s = (0, import_path82.relative)(projectRoot, s);
47428
47712
  } else if (s.startsWith("./")) {
47429
47713
  s = s.slice(2);
47430
47714
  }
47431
- s = (0, import_path81.normalize)(s).replace(/\/+$/, "");
47715
+ s = (0, import_path82.normalize)(s).replace(/\/+$/, "");
47432
47716
  if (s === "." || s === "") return "";
47433
47717
  return s;
47434
47718
  }
47435
47719
  function isInsideScope(filePath, scope) {
47436
47720
  if (!scope) return true;
47437
- const f = (0, import_path81.normalize)(filePath).replace(/^\.\//, "");
47721
+ const f = (0, import_path82.normalize)(filePath).replace(/^\.\//, "");
47438
47722
  const s = scope.replace(/^\.\//, "").replace(/\/+$/, "");
47439
47723
  if (f === s) return true;
47440
- return f.startsWith(s + "/") || f.startsWith(s + import_path81.sep);
47724
+ return f.startsWith(s + "/") || f.startsWith(s + import_path82.sep);
47441
47725
  }
47442
47726
  function detectBoundaryEscapes(meta3, modifiedFiles, projectRoot) {
47443
47727
  const mode = meta3.writeMode;
@@ -47498,8 +47782,8 @@ function recordBoundaryEscape(projectRoot, meta3, violations, mode) {
47498
47782
  } catch {
47499
47783
  }
47500
47784
  try {
47501
- const dir = (0, import_path81.join)(projectRoot, ".gossip");
47502
- (0, import_fs74.mkdirSync)(dir, { recursive: true });
47785
+ const dir = (0, import_path82.join)(projectRoot, ".gossip");
47786
+ (0, import_fs75.mkdirSync)(dir, { recursive: true });
47503
47787
  const line = {
47504
47788
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
47505
47789
  taskId: meta3.taskId,
@@ -47510,15 +47794,15 @@ function recordBoundaryEscape(projectRoot, meta3, violations, mode) {
47510
47794
  action: mode
47511
47795
  // "warn" or "block"
47512
47796
  };
47513
- const escapeFile = (0, import_path81.join)(dir, BOUNDARY_ESCAPE_FILE);
47797
+ const escapeFile = (0, import_path82.join)(dir, BOUNDARY_ESCAPE_FILE);
47514
47798
  rotateIfNeeded2(escapeFile, MAX_BOUNDARY_ESCAPE_BYTES);
47515
- (0, import_fs74.appendFileSync)(escapeFile, JSON.stringify(line) + "\n");
47799
+ (0, import_fs75.appendFileSync)(escapeFile, JSON.stringify(line) + "\n");
47516
47800
  } catch {
47517
47801
  }
47518
47802
  }
47519
47803
  function canonicalize(p) {
47520
47804
  try {
47521
- return (0, import_path81.resolve)(p).replace(/\/+$/, "") || "/";
47805
+ return (0, import_path82.resolve)(p).replace(/\/+$/, "") || "/";
47522
47806
  } catch {
47523
47807
  return p.replace(/\/+$/, "") || "/";
47524
47808
  }
@@ -47544,8 +47828,8 @@ function defaultScanRoots(writeMode, projectRoot) {
47544
47828
  out.add("/private/tmp");
47545
47829
  return Array.from(out);
47546
47830
  }
47547
- function expandTmpVariants(path7) {
47548
- const p = path7.replace(/\/+$/, "") || "/";
47831
+ function expandTmpVariants(path8) {
47832
+ const p = path8.replace(/\/+$/, "") || "/";
47549
47833
  for (const root of ["/tmp", "/etc", "/var"]) {
47550
47834
  if (p === root || p.startsWith(root + "/")) {
47551
47835
  return [p, "/private" + p];
@@ -47629,7 +47913,7 @@ function buildAuditExclusions(projectRoot, ownWorktree, scope) {
47629
47913
  for (const v of expandTmpVariants(wt)) excl.add(v);
47630
47914
  }
47631
47915
  if (scope) {
47632
- const s = canonicalize((0, import_path81.join)(projectRoot, scope));
47916
+ const s = canonicalize((0, import_path82.join)(projectRoot, scope));
47633
47917
  for (const v of expandTmpVariants(s)) excl.add(v);
47634
47918
  }
47635
47919
  return Array.from(excl);
@@ -47718,12 +48002,12 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
47718
48002
  return { violations: [], skipped: "win32" };
47719
48003
  }
47720
48004
  const sentinel = meta3.sentinelPath;
47721
- if (!sentinel || !(0, import_fs74.existsSync)(sentinel)) {
48005
+ if (!sentinel || !(0, import_fs75.existsSync)(sentinel)) {
47722
48006
  return { violations: [], skipped: "sentinel missing" };
47723
48007
  }
47724
48008
  let sentinelMtimeMs = 0;
47725
48009
  try {
47726
- sentinelMtimeMs = (0, import_fs74.statSync)(sentinel).mtimeMs;
48010
+ sentinelMtimeMs = (0, import_fs75.statSync)(sentinel).mtimeMs;
47727
48011
  } catch {
47728
48012
  }
47729
48013
  if (sentinelMtimeMs === 0) {
@@ -47735,11 +48019,11 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
47735
48019
  );
47736
48020
  const exclusions = buildAuditExclusions(projectRoot, meta3.worktreePath, options.scope);
47737
48021
  const findBin = options.findBinary ?? "find";
47738
- const sentinelDir = canonicalize((0, import_path81.join)(projectRoot, ".gossip", SENTINEL_DIR));
48022
+ const sentinelDir = canonicalize((0, import_path82.join)(projectRoot, ".gossip", SENTINEL_DIR));
47739
48023
  const mainSet = /* @__PURE__ */ new Set();
47740
48024
  const sensitiveSet = /* @__PURE__ */ new Set();
47741
48025
  for (const root of scanRoots) {
47742
- if (!(0, import_fs74.existsSync)(root)) continue;
48026
+ if (!(0, import_fs75.existsSync)(root)) continue;
47743
48027
  const canonRoot = canonicalize(root);
47744
48028
  const allExcl = [...exclusions, ...expandTmpVariants(sentinelDir)];
47745
48029
  const args = buildFindPruneArgs(canonRoot, allExcl, sentinel);
@@ -47775,7 +48059,7 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
47775
48059
  }
47776
48060
  const sensitiveTargets = buildSensitiveTargets(platform2);
47777
48061
  for (const target of sensitiveTargets) {
47778
- if (!(0, import_fs74.existsSync)(target.path)) continue;
48062
+ if (!(0, import_fs75.existsSync)(target.path)) continue;
47779
48063
  const canonTarget = canonicalize(target.path);
47780
48064
  const args = buildSensitiveFindArgs(
47781
48065
  canonTarget,
@@ -47849,21 +48133,21 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
47849
48133
  }
47850
48134
  function recordLayer3Violations(projectRoot, meta3, violations, source) {
47851
48135
  try {
47852
- const dir = (0, import_path81.join)(projectRoot, ".gossip");
47853
- (0, import_fs74.mkdirSync)(dir, { recursive: true });
48136
+ const dir = (0, import_path82.join)(projectRoot, ".gossip");
48137
+ (0, import_fs75.mkdirSync)(dir, { recursive: true });
47854
48138
  const ts2 = (/* @__PURE__ */ new Date()).toISOString();
47855
48139
  const lines = violations.map(
47856
- (path7) => JSON.stringify({
48140
+ (path8) => JSON.stringify({
47857
48141
  timestamp: ts2,
47858
48142
  taskId: meta3.taskId,
47859
48143
  agentId: meta3.agentId,
47860
- violatingPaths: [path7],
48144
+ violatingPaths: [path8],
47861
48145
  source
47862
48146
  })
47863
48147
  );
47864
- const escapeFile = (0, import_path81.join)(dir, BOUNDARY_ESCAPE_FILE);
48148
+ const escapeFile = (0, import_path82.join)(dir, BOUNDARY_ESCAPE_FILE);
47865
48149
  rotateIfNeeded2(escapeFile, MAX_BOUNDARY_ESCAPE_BYTES);
47866
- (0, import_fs74.appendFileSync)(escapeFile, lines.join("\n") + "\n");
48150
+ (0, import_fs75.appendFileSync)(escapeFile, lines.join("\n") + "\n");
47867
48151
  } catch {
47868
48152
  }
47869
48153
  if (source === "layer3-sensitive" && violations.length > 0) {
@@ -47920,14 +48204,14 @@ function runLayer3Audit(projectRoot, taskId) {
47920
48204
  }
47921
48205
  return { blockError, warnPrefix };
47922
48206
  }
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__;
48207
+ 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
48208
  var init_sandbox2 = __esm({
47925
48209
  "apps/cli/src/sandbox.ts"() {
47926
48210
  "use strict";
47927
48211
  import_child_process12 = require("child_process");
47928
- import_fs74 = require("fs");
48212
+ import_fs75 = require("fs");
47929
48213
  import_os5 = require("os");
47930
- import_path81 = require("path");
48214
+ import_path82 = require("path");
47931
48215
  METADATA_FILE = "dispatch-metadata.jsonl";
47932
48216
  BOUNDARY_ESCAPE_FILE = "boundary-escapes.jsonl";
47933
48217
  SENTINEL_DIR = "sentinels";
@@ -47999,7 +48283,7 @@ __export(dispatch_prompt_storage_exports, {
47999
48283
  writeDispatchPrompt: () => writeDispatchPrompt
48000
48284
  });
48001
48285
  function dispatchPromptsDir(projectRoot) {
48002
- return (0, import_path82.join)(projectRoot, ".gossip", DISPATCH_PROMPTS_SUBDIR);
48286
+ return (0, import_path83.join)(projectRoot, ".gossip", DISPATCH_PROMPTS_SUBDIR);
48003
48287
  }
48004
48288
  function assertSafeTaskId(taskId) {
48005
48289
  if (typeof taskId !== "string" || taskId.length === 0) {
@@ -48012,35 +48296,35 @@ function assertSafeTaskId(taskId) {
48012
48296
  function writeDispatchPrompt(projectRoot, taskId, body) {
48013
48297
  assertSafeTaskId(taskId);
48014
48298
  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`);
48299
+ (0, import_fs76.mkdirSync)(dir, { recursive: true });
48300
+ const finalPath = (0, import_path83.join)(dir, `${taskId}.txt`);
48301
+ const tmpPath = (0, import_path83.join)(dir, `${taskId}.txt.${(0, import_crypto30.randomUUID)().slice(0, 8)}.tmp`);
48018
48302
  try {
48019
- (0, import_fs75.writeFileSync)(tmpPath, body, "utf8");
48020
- (0, import_fs75.renameSync)(tmpPath, finalPath);
48303
+ (0, import_fs76.writeFileSync)(tmpPath, body, "utf8");
48304
+ (0, import_fs76.renameSync)(tmpPath, finalPath);
48021
48305
  } catch (err) {
48022
48306
  try {
48023
- (0, import_fs75.unlinkSync)(tmpPath);
48307
+ (0, import_fs76.unlinkSync)(tmpPath);
48024
48308
  } catch {
48025
48309
  }
48026
48310
  throw err;
48027
48311
  }
48028
- return (0, import_path82.resolve)(finalPath);
48312
+ return (0, import_path83.resolve)(finalPath);
48029
48313
  }
48030
48314
  function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TTL_MS, capBytes = DISPATCH_PROMPT_CAP_BYTES) {
48031
48315
  const dir = dispatchPromptsDir(projectRoot);
48032
- if (!(0, import_fs75.existsSync)(dir)) return { evictedAge: 0, evictedCap: 0 };
48316
+ if (!(0, import_fs76.existsSync)(dir)) return { evictedAge: 0, evictedCap: 0 };
48033
48317
  const now = Date.now();
48034
48318
  let entries = [];
48035
48319
  try {
48036
- for (const name of (0, import_fs75.readdirSync)(dir)) {
48037
- const path7 = (0, import_path82.join)(dir, name);
48320
+ for (const name of (0, import_fs76.readdirSync)(dir)) {
48321
+ const path8 = (0, import_path83.join)(dir, name);
48038
48322
  try {
48039
- const st = (0, import_fs75.statSync)(path7);
48323
+ const st = (0, import_fs76.statSync)(path8);
48040
48324
  if (!st.isFile()) continue;
48041
- entries.push({ name, path: path7, mtimeMs: st.mtimeMs, size: st.size });
48325
+ entries.push({ name, path: path8, mtimeMs: st.mtimeMs, size: st.size });
48042
48326
  } catch (err) {
48043
- process.stderr.write(`[gossipcat] dispatch-prompt stat failed for ${(0, import_path82.basename)(path7)}: ${err.message}
48327
+ process.stderr.write(`[gossipcat] dispatch-prompt stat failed for ${(0, import_path83.basename)(path8)}: ${err.message}
48044
48328
  `);
48045
48329
  }
48046
48330
  }
@@ -48054,7 +48338,7 @@ function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TT
48054
48338
  for (const e of entries) {
48055
48339
  if (now - e.mtimeMs > maxAgeMs) {
48056
48340
  try {
48057
- (0, import_fs75.unlinkSync)(e.path);
48341
+ (0, import_fs76.unlinkSync)(e.path);
48058
48342
  evictedAge++;
48059
48343
  } catch (err) {
48060
48344
  process.stderr.write(`[gossipcat] dispatch-prompt unlink failed for ${e.name}: ${err.message}
@@ -48071,7 +48355,7 @@ function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TT
48071
48355
  for (const e of survivors) {
48072
48356
  if (totalBytes <= capBytes) break;
48073
48357
  try {
48074
- (0, import_fs75.unlinkSync)(e.path);
48358
+ (0, import_fs76.unlinkSync)(e.path);
48075
48359
  totalBytes -= e.size;
48076
48360
  evictedCap++;
48077
48361
  } catch (err) {
@@ -48084,18 +48368,18 @@ function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TT
48084
48368
  }
48085
48369
  function pruneOrphanDispatchPrompts(projectRoot, knownTaskIds, maxAgeMs = DEFAULT_PROMPT_TTL_MS) {
48086
48370
  const dir = dispatchPromptsDir(projectRoot);
48087
- if (!(0, import_fs75.existsSync)(dir)) return { orphans: 0, aged: 0 };
48371
+ if (!(0, import_fs76.existsSync)(dir)) return { orphans: 0, aged: 0 };
48088
48372
  const now = Date.now();
48089
48373
  let orphans = 0;
48090
48374
  let aged = 0;
48091
48375
  try {
48092
- for (const name of (0, import_fs75.readdirSync)(dir)) {
48376
+ for (const name of (0, import_fs76.readdirSync)(dir)) {
48093
48377
  if (!name.endsWith(".txt")) continue;
48094
48378
  const taskId = name.slice(0, -4);
48095
- const path7 = (0, import_path82.join)(dir, name);
48379
+ const path8 = (0, import_path83.join)(dir, name);
48096
48380
  let mtimeMs = 0;
48097
48381
  try {
48098
- mtimeMs = (0, import_fs75.statSync)(path7).mtimeMs;
48382
+ mtimeMs = (0, import_fs76.statSync)(path8).mtimeMs;
48099
48383
  } catch {
48100
48384
  continue;
48101
48385
  }
@@ -48103,7 +48387,7 @@ function pruneOrphanDispatchPrompts(projectRoot, knownTaskIds, maxAgeMs = DEFAUL
48103
48387
  const orphaned = !knownTaskIds.has(taskId);
48104
48388
  if (tooOld || orphaned) {
48105
48389
  try {
48106
- (0, import_fs75.unlinkSync)(path7);
48390
+ (0, import_fs76.unlinkSync)(path8);
48107
48391
  if (orphaned) orphans++;
48108
48392
  if (tooOld) aged++;
48109
48393
  } catch (err) {
@@ -48120,14 +48404,14 @@ function pruneOrphanDispatchPrompts(projectRoot, knownTaskIds, maxAgeMs = DEFAUL
48120
48404
  }
48121
48405
  function dispatchPromptPath(projectRoot, taskId) {
48122
48406
  assertSafeTaskId(taskId);
48123
- return (0, import_path82.resolve)((0, import_path82.join)(dispatchPromptsDir(projectRoot), `${taskId}.txt`));
48407
+ return (0, import_path83.resolve)((0, import_path83.join)(dispatchPromptsDir(projectRoot), `${taskId}.txt`));
48124
48408
  }
48125
- var import_fs75, import_path82, import_crypto30, SAFE_TASK_ID2, DISPATCH_PROMPT_CAP_BYTES, DEFAULT_PROMPT_TTL_MS, DISPATCH_PROMPTS_SUBDIR;
48409
+ var import_fs76, import_path83, import_crypto30, SAFE_TASK_ID2, DISPATCH_PROMPT_CAP_BYTES, DEFAULT_PROMPT_TTL_MS, DISPATCH_PROMPTS_SUBDIR;
48126
48410
  var init_dispatch_prompt_storage = __esm({
48127
48411
  "apps/cli/src/handlers/dispatch-prompt-storage.ts"() {
48128
48412
  "use strict";
48129
- import_fs75 = require("fs");
48130
- import_path82 = require("path");
48413
+ import_fs76 = require("fs");
48414
+ import_path83 = require("path");
48131
48415
  import_crypto30 = require("crypto");
48132
48416
  SAFE_TASK_ID2 = /^(?!.*\.\.)[A-Za-z0-9._-]{1,64}$/;
48133
48417
  DISPATCH_PROMPT_CAP_BYTES = 100 * 1024 * 1024;
@@ -48181,9 +48465,9 @@ function getCommitRange(preSha, postSha) {
48181
48465
  function appendViolationRecord(record2) {
48182
48466
  try {
48183
48467
  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");
48468
+ (0, import_fs77.mkdirSync)((0, import_path84.join)(projectRoot, ".gossip"), { recursive: true });
48469
+ const logPath = (0, import_path84.join)(projectRoot, PROCESS_VIOLATIONS_FILE);
48470
+ (0, import_fs77.appendFileSync)(logPath, JSON.stringify(record2) + "\n", "utf8");
48187
48471
  } catch (err) {
48188
48472
  process.stderr.write(`[gossipcat] ref-allowlist: failed to append violation record: ${err.message}
48189
48473
  `);
@@ -48233,17 +48517,289 @@ Full audit trail at .gossip/process-violations.jsonl
48233
48517
  `
48234
48518
  );
48235
48519
  }
48236
- var import_fs76, import_path83, import_child_process13, PROCESS_VIOLATIONS_FILE;
48520
+ var import_fs77, import_path84, import_child_process13, PROCESS_VIOLATIONS_FILE;
48237
48521
  var init_ref_allowlist_detection = __esm({
48238
48522
  "apps/cli/src/handlers/ref-allowlist-detection.ts"() {
48239
48523
  "use strict";
48240
- import_fs76 = require("fs");
48241
- import_path83 = require("path");
48524
+ import_fs77 = require("fs");
48525
+ import_path84 = require("path");
48242
48526
  import_child_process13 = require("child_process");
48243
48527
  PROCESS_VIOLATIONS_FILE = ".gossip/process-violations.jsonl";
48244
48528
  }
48245
48529
  });
48246
48530
 
48531
+ // apps/cli/src/handlers/orchestrator-precondition-runner.ts
48532
+ function captureHeadSha(projectRoot, execFile6 = defaultExecFile) {
48533
+ try {
48534
+ const cwd = projectRoot || process.cwd();
48535
+ const sha = execFile6("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" }).trim();
48536
+ return sha || void 0;
48537
+ } catch {
48538
+ return void 0;
48539
+ }
48540
+ }
48541
+ function getCommitsSince(sinceSha, projectRoot, execFile6 = defaultExecFile) {
48542
+ try {
48543
+ const output = execFile6("git", ["log", `${sinceSha}..HEAD`, "--format=%H"], {
48544
+ cwd: projectRoot,
48545
+ encoding: "utf8"
48546
+ });
48547
+ return output.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
48548
+ } catch {
48549
+ return [];
48550
+ }
48551
+ }
48552
+ async function runMidFlightCheck(input, deps = {}) {
48553
+ const warnings = [];
48554
+ if (!input.roundStartSha) {
48555
+ return { warnings };
48556
+ }
48557
+ const execFile6 = deps.execFile ?? defaultExecFile;
48558
+ const emitSignals = deps.emitSignals ?? defaultEmitSignals;
48559
+ try {
48560
+ const { projectRoot, consensusId, roundStartSha } = input;
48561
+ const commits = getCommitsSince(roundStartSha, projectRoot, execFile6);
48562
+ const { detected, count } = detectMidFlightCommits(commits);
48563
+ if (!detected) {
48564
+ return { warnings };
48565
+ }
48566
+ warnings.push(
48567
+ `[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}.`
48568
+ );
48569
+ try {
48570
+ emitSignals(projectRoot, [{
48571
+ type: "pipeline",
48572
+ signal: "mid_flight_fixup",
48573
+ agentId: "orchestrator",
48574
+ taskId: consensusId,
48575
+ consensusId,
48576
+ metadata: {
48577
+ count,
48578
+ roundStartSha,
48579
+ commits
48580
+ },
48581
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
48582
+ }]);
48583
+ } catch {
48584
+ }
48585
+ } catch {
48586
+ }
48587
+ return { warnings };
48588
+ }
48589
+ function defaultExecFile(cmd, args, opts) {
48590
+ return (0, import_child_process14.execFileSync)(cmd, args, opts);
48591
+ }
48592
+ function defaultCanRead(p) {
48593
+ try {
48594
+ fs6.accessSync(p, fs6.constants.R_OK);
48595
+ return true;
48596
+ } catch {
48597
+ return false;
48598
+ }
48599
+ }
48600
+ function defaultPathExists(projectRoot, p) {
48601
+ try {
48602
+ const resolved = path7.resolve(projectRoot, p);
48603
+ fs6.accessSync(resolved, fs6.constants.R_OK);
48604
+ return true;
48605
+ } catch {
48606
+ return false;
48607
+ }
48608
+ }
48609
+ function defaultIsGitignoredOrUntracked(projectRoot, p, execFile6) {
48610
+ try {
48611
+ execFile6("git", ["check-ignore", "-q", p], { cwd: projectRoot, encoding: "utf8" });
48612
+ return true;
48613
+ } catch {
48614
+ }
48615
+ try {
48616
+ execFile6("git", ["ls-files", "--error-unmatch", p], { cwd: projectRoot, encoding: "utf8" });
48617
+ return false;
48618
+ } catch {
48619
+ return true;
48620
+ }
48621
+ }
48622
+ function defaultEmitSignals(projectRoot, signals) {
48623
+ try {
48624
+ emitPipelineSignals(projectRoot, signals);
48625
+ } catch {
48626
+ }
48627
+ }
48628
+ async function gatherStaleBaseInputs(projectRoot, execFile6 = defaultExecFile) {
48629
+ try {
48630
+ const dispatchSha = execFile6("git", ["rev-parse", "HEAD"], {
48631
+ cwd: projectRoot,
48632
+ encoding: "utf8"
48633
+ }).trim();
48634
+ const originMasterSha = execFile6("git", ["rev-parse", "origin/master"], {
48635
+ cwd: projectRoot,
48636
+ encoding: "utf8"
48637
+ }).trim();
48638
+ const mergeBaseSha = execFile6("git", ["merge-base", "HEAD", "origin/master"], {
48639
+ cwd: projectRoot,
48640
+ encoding: "utf8"
48641
+ }).trim();
48642
+ return { dispatchSha, originMasterSha, mergeBaseSha };
48643
+ } catch {
48644
+ return null;
48645
+ }
48646
+ }
48647
+ async function runDispatchPreconditionGuard(input, deps = {}) {
48648
+ const warnings = [];
48649
+ const execFile6 = deps.execFile ?? defaultExecFile;
48650
+ const canRead = deps.canRead ?? defaultCanRead;
48651
+ const pathExists = deps.pathExists ?? defaultPathExists;
48652
+ const isGitignoredOrUntracked = deps.isGitignoredOrUntracked ?? defaultIsGitignoredOrUntracked;
48653
+ const emitSignals = deps.emitSignals ?? defaultEmitSignals;
48654
+ const { projectRoot, taskId, resolutionRoots, taskText, writeMode, additionalTasks } = input;
48655
+ try {
48656
+ const gitInputs = await gatherStaleBaseInputs(projectRoot, execFile6);
48657
+ if (gitInputs !== null) {
48658
+ const staleResult = detectStaleBase(
48659
+ gitInputs.dispatchSha,
48660
+ gitInputs.originMasterSha,
48661
+ gitInputs.mergeBaseSha
48662
+ );
48663
+ if (staleResult.stale && staleResult.reason !== null) {
48664
+ const reason = staleResult.reason;
48665
+ warnings.push(
48666
+ `[dispatch-hygiene] stale base detected (${reason}): dispatch SHA ${gitInputs.dispatchSha} is behind origin/master ${gitInputs.originMasterSha}. Pull and rebase before dispatching.`
48667
+ );
48668
+ try {
48669
+ emitSignals(projectRoot, [{
48670
+ type: "pipeline",
48671
+ signal: "dispatched_stale_base",
48672
+ agentId: "orchestrator",
48673
+ taskId,
48674
+ metadata: {
48675
+ reason,
48676
+ dispatchSha: gitInputs.dispatchSha
48677
+ },
48678
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
48679
+ }]);
48680
+ } catch {
48681
+ }
48682
+ }
48683
+ }
48684
+ const roots = resolutionRoots ?? [];
48685
+ if (roots.length > 0) {
48686
+ let unreadable;
48687
+ try {
48688
+ unreadable = findUnreadablePaths(roots, canRead);
48689
+ } catch {
48690
+ unreadable = [];
48691
+ }
48692
+ if (unreadable.length > 0) {
48693
+ warnings.push(
48694
+ `[dispatch-hygiene] ${unreadable.length} resolutionRoot(s) are unreadable: ${unreadable.join(", ")}. Cross-reviewers will fall back to project root.`
48695
+ );
48696
+ try {
48697
+ emitSignals(projectRoot, [{
48698
+ type: "pipeline",
48699
+ signal: "referenced_unreadable_path",
48700
+ agentId: "orchestrator",
48701
+ taskId,
48702
+ metadata: {
48703
+ unreadable
48704
+ },
48705
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
48706
+ }]);
48707
+ } catch {
48708
+ }
48709
+ }
48710
+ }
48711
+ const scanTasks = [];
48712
+ if (taskText) {
48713
+ scanTasks.push({ taskText, writeMode });
48714
+ }
48715
+ if (additionalTasks) {
48716
+ for (const t of additionalTasks) {
48717
+ if (t && t.taskText) {
48718
+ scanTasks.push({ taskText: t.taskText, writeMode: t.writeMode });
48719
+ }
48720
+ }
48721
+ }
48722
+ if (scanTasks.length > 0) {
48723
+ const byPath = /* @__PURE__ */ new Map();
48724
+ let droppedOverCap = 0;
48725
+ for (const t of scanTasks) {
48726
+ let result = {
48727
+ unreadable: [],
48728
+ droppedOverCap: 0
48729
+ };
48730
+ try {
48731
+ result = findUnreadableReferencedPathsWithMeta(t.taskText, {
48732
+ writeMode: t.writeMode,
48733
+ pathExists: (p) => {
48734
+ try {
48735
+ return pathExists(projectRoot, p);
48736
+ } catch {
48737
+ return true;
48738
+ }
48739
+ },
48740
+ isGitignoredOrUntracked: (p) => {
48741
+ try {
48742
+ return isGitignoredOrUntracked(projectRoot, p, execFile6);
48743
+ } catch {
48744
+ return false;
48745
+ }
48746
+ }
48747
+ });
48748
+ } catch {
48749
+ result = { unreadable: [], droppedOverCap: 0 };
48750
+ }
48751
+ droppedOverCap += result.droppedOverCap;
48752
+ for (const entry of result.unreadable) {
48753
+ const existing = byPath.get(entry.path);
48754
+ if (!existing) {
48755
+ byPath.set(entry.path, entry);
48756
+ } else if (existing.reason !== "gitignored_in_worktree" && entry.reason === "gitignored_in_worktree") {
48757
+ byPath.set(entry.path, entry);
48758
+ }
48759
+ }
48760
+ }
48761
+ const referenced = [...byPath.values()];
48762
+ if (referenced.length > 0) {
48763
+ const detail = referenced.map((r) => `${r.path} (${r.reason})`).join(", ");
48764
+ warnings.push(
48765
+ `[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.`
48766
+ );
48767
+ try {
48768
+ emitSignals(projectRoot, [{
48769
+ type: "pipeline",
48770
+ signal: "referenced_unreadable_path",
48771
+ agentId: "orchestrator",
48772
+ taskId,
48773
+ metadata: {
48774
+ referenced
48775
+ },
48776
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
48777
+ }]);
48778
+ } catch {
48779
+ }
48780
+ }
48781
+ if (droppedOverCap > 0) {
48782
+ warnings.push(
48783
+ `[dispatch-hygiene] ${droppedOverCap} referenced path(s) beyond the 20-path cap were not checked.`
48784
+ );
48785
+ }
48786
+ }
48787
+ } catch {
48788
+ }
48789
+ return { warnings };
48790
+ }
48791
+ var fs6, path7, import_child_process14;
48792
+ var init_orchestrator_precondition_runner = __esm({
48793
+ "apps/cli/src/handlers/orchestrator-precondition-runner.ts"() {
48794
+ "use strict";
48795
+ fs6 = __toESM(require("fs"));
48796
+ path7 = __toESM(require("path"));
48797
+ import_child_process14 = require("child_process");
48798
+ init_src4();
48799
+ init_src4();
48800
+ }
48801
+ });
48802
+
48247
48803
  // apps/cli/src/handlers/relay-cross-review.ts
48248
48804
  var relay_cross_review_exports = {};
48249
48805
  __export(relay_cross_review_exports, {
@@ -48274,11 +48830,11 @@ async function synthesizeTimeoutRound(snapshot, consensusId, missingAgents, llm,
48274
48830
  );
48275
48831
  try {
48276
48832
  const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45 } = require("fs");
48277
- const { join: join91 } = require("path");
48278
- const reportsDir = join91(projectRoot, ".gossip", "consensus-reports");
48833
+ const { join: join93 } = require("path");
48834
+ const reportsDir = join93(projectRoot, ".gossip", "consensus-reports");
48279
48835
  mkdirSync45(reportsDir, { recursive: true });
48280
48836
  const topic = snapshot.allResults?.find((r) => r.task)?.task?.slice(0, 500) || "";
48281
- writeFileSync38(join91(reportsDir, `${consensusId}.json`), JSON.stringify({
48837
+ writeFileSync38(join93(reportsDir, `${consensusId}.json`), JSON.stringify({
48282
48838
  id: consensusId,
48283
48839
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
48284
48840
  topic,
@@ -48313,6 +48869,7 @@ function startConsensusTimeout(consensusId) {
48313
48869
  return;
48314
48870
  }
48315
48871
  const missingAgents = [...current.pendingNativeAgents];
48872
+ const roundStartShaForMidFlight = current.roundStartSha;
48316
48873
  const snapshot = { allResults: current.allResults, relayCrossReviewEntries: current.relayCrossReviewEntries, relayCrossReviewSkipped: current.relayCrossReviewSkipped, nativeCrossReviewEntries: [...current.nativeCrossReviewEntries], resolutionRoots: current.resolutionRoots, roundContext: current.roundContext };
48317
48874
  seedRecentConsensusAgentIds(Array.from(current.participatingNativeAgents), RECENT_CONSENSUS_TASK_TTL_MS);
48318
48875
  ctx.pendingConsensusRounds.delete(consensusId);
@@ -48342,6 +48899,18 @@ function startConsensusTimeout(consensusId) {
48342
48899
  const { report } = await synthesizeTimeoutRound(snapshot, consensusId, missingAgents, timeoutLlm);
48343
48900
  process.stderr.write(`[gossipcat] \u{1F52E} Timeout synthesis complete: ${report.confirmed.length} confirmed, ${report.disputed.length} disputed
48344
48901
  `);
48902
+ try {
48903
+ const midFlightResult = await runMidFlightCheck({
48904
+ projectRoot: process.cwd(),
48905
+ consensusId,
48906
+ roundStartSha: roundStartShaForMidFlight
48907
+ });
48908
+ for (const warn of midFlightResult.warnings) {
48909
+ process.stderr.write(`[gossipcat] ${warn}
48910
+ `);
48911
+ }
48912
+ } catch {
48913
+ }
48345
48914
  } catch (err) {
48346
48915
  process.stderr.write(`[gossipcat] \u274C Timeout synthesis failed: ${err.message}
48347
48916
  `);
@@ -48452,6 +49021,7 @@ async function handleRelayCrossReview(consensus_id, agent_id, result) {
48452
49021
  }]
48453
49022
  };
48454
49023
  }
49024
+ const completionRoundStartSha = round.roundStartSha;
48455
49025
  const synthSnapshot = {
48456
49026
  allResults: round.allResults,
48457
49027
  relayCrossReviewEntries: round.relayCrossReviewEntries,
@@ -48497,10 +49067,10 @@ async function handleRelayCrossReview(consensus_id, agent_id, result) {
48497
49067
  );
48498
49068
  try {
48499
49069
  const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45 } = require("fs");
48500
- const { join: join91 } = require("path");
48501
- const reportsDir = join91(process.cwd(), ".gossip", "consensus-reports");
49070
+ const { join: join93 } = require("path");
49071
+ const reportsDir = join93(process.cwd(), ".gossip", "consensus-reports");
48502
49072
  mkdirSync45(reportsDir, { recursive: true });
48503
- const reportPath = join91(reportsDir, `${consensus_id}.json`);
49073
+ const reportPath = join93(reportsDir, `${consensus_id}.json`);
48504
49074
  const topic = synthSnapshot.allResults?.find((r) => r.task)?.task?.slice(0, 500) || "";
48505
49075
  writeFileSync38(reportPath, JSON.stringify({
48506
49076
  id: consensus_id,
@@ -48527,6 +49097,18 @@ async function handleRelayCrossReview(consensus_id, agent_id, result) {
48527
49097
  }
48528
49098
  } catch {
48529
49099
  }
49100
+ try {
49101
+ const midFlightResult = await runMidFlightCheck({
49102
+ projectRoot: process.cwd(),
49103
+ consensusId: synthSnapshot.consensusId,
49104
+ roundStartSha: completionRoundStartSha
49105
+ });
49106
+ for (const warn of midFlightResult.warnings) {
49107
+ process.stderr.write(`[gossipcat] ${warn}
49108
+ `);
49109
+ }
49110
+ } catch {
49111
+ }
48530
49112
  return {
48531
49113
  content: [{
48532
49114
  type: "text",
@@ -48600,8 +49182,8 @@ function persistPendingConsensus() {
48600
49182
  const projectRoot = ctx.mainAgent?.projectRoot;
48601
49183
  if (!projectRoot) return;
48602
49184
  const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45 } = require("fs");
48603
- const { join: join91 } = require("path");
48604
- const dir = join91(projectRoot, ".gossip");
49185
+ const { join: join93 } = require("path");
49186
+ const dir = join93(projectRoot, ".gossip");
48605
49187
  mkdirSync45(dir, { recursive: true });
48606
49188
  const rounds = {};
48607
49189
  for (const [id, round] of ctx.pendingConsensusRounds) {
@@ -48636,7 +49218,7 @@ function persistPendingConsensus() {
48636
49218
  } : void 0
48637
49219
  };
48638
49220
  }
48639
- writeFileSync38(join91(dir, CONSENSUS_FILE), JSON.stringify(rounds));
49221
+ writeFileSync38(join93(dir, CONSENSUS_FILE), JSON.stringify(rounds));
48640
49222
  } catch (err) {
48641
49223
  process.stderr.write(`[gossipcat] persistPendingConsensus failed: ${err.message}
48642
49224
  `);
@@ -48644,11 +49226,11 @@ function persistPendingConsensus() {
48644
49226
  }
48645
49227
  function restorePendingConsensus(projectRoot) {
48646
49228
  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"));
49229
+ const { existsSync: existsSync74, readFileSync: readFileSync70, unlinkSync: unlinkSync16 } = require("fs");
49230
+ const { join: join93 } = require("path");
49231
+ const filePath = join93(projectRoot, ".gossip", CONSENSUS_FILE);
49232
+ if (!existsSync74(filePath)) return;
49233
+ const raw = JSON.parse(readFileSync70(filePath, "utf-8"));
48652
49234
  const now = Date.now();
48653
49235
  for (const [id, data] of Object.entries(raw)) {
48654
49236
  if (now > data.deadline + 3e5) {
@@ -48674,6 +49256,8 @@ function restorePendingConsensus(projectRoot) {
48674
49256
  createdAt: data.createdAt,
48675
49257
  nativePrompts: data.nativePrompts || [],
48676
49258
  resolutionRoots: Array.isArray(data.resolutionRoots) && data.resolutionRoots.length > 0 ? data.resolutionRoots : void 0,
49259
+ // UNIT 3: restore roundStartSha from persisted data (back-compat: undefined for old rounds).
49260
+ roundStartSha: typeof data.roundStartSha === "string" ? data.roundStartSha : void 0,
48677
49261
  // Spec §3.2 disk back-compat: prefer the embedded roundContext; fall
48678
49262
  // back per-field to the old flat shape (mirrors the
48679
49263
  // participatingNativeAgents back-compat pattern above). Old pre-PR-A
@@ -48695,6 +49279,7 @@ var init_relay_cross_review = __esm({
48695
49279
  "use strict";
48696
49280
  init_mcp_context();
48697
49281
  init_native_tasks();
49282
+ init_orchestrator_precondition_runner();
48698
49283
  CONSENSUS_FILE = "pending-consensus.json";
48699
49284
  }
48700
49285
  });
@@ -48779,10 +49364,10 @@ function taskWasInConsensusRound(taskId, agentId, rounds, recentTaskIds, recentA
48779
49364
  function appendRelayWarning(projectRoot, entry) {
48780
49365
  try {
48781
49366
  const { appendFileSync: appendFileSync22, mkdirSync: mkdirSync45 } = require("fs");
48782
- const { join: join91 } = require("path");
48783
- const dir = join91(projectRoot, ".gossip");
49367
+ const { join: join93 } = require("path");
49368
+ const dir = join93(projectRoot, ".gossip");
48784
49369
  mkdirSync45(dir, { recursive: true });
48785
- appendFileSync22(join91(dir, RELAY_WARNINGS_FILE), JSON.stringify(entry) + "\n", "utf8");
49370
+ appendFileSync22(join93(dir, RELAY_WARNINGS_FILE), JSON.stringify(entry) + "\n", "utf8");
48786
49371
  } catch (err) {
48787
49372
  process.stderr.write(`[gossipcat] append relay-warning failed: ${err.message}
48788
49373
  `);
@@ -48791,8 +49376,8 @@ function appendRelayWarning(projectRoot, entry) {
48791
49376
  function checkWorktreeEngaged(startedAt, projectRoot = process.cwd()) {
48792
49377
  try {
48793
49378
  const { readdirSync: readdirSync22, statSync: statSync36 } = require("fs");
48794
- const { join: join91 } = require("path");
48795
- const wtDir = join91(projectRoot, ".claude", "worktrees");
49379
+ const { join: join93 } = require("path");
49380
+ const wtDir = join93(projectRoot, ".claude", "worktrees");
48796
49381
  let entries;
48797
49382
  try {
48798
49383
  entries = readdirSync22(wtDir);
@@ -48803,7 +49388,7 @@ function checkWorktreeEngaged(startedAt, projectRoot = process.cwd()) {
48803
49388
  for (const entry of entries) {
48804
49389
  if (!entry.startsWith("agent-")) continue;
48805
49390
  try {
48806
- const st = statSync36(join91(wtDir, entry));
49391
+ const st = statSync36(join93(wtDir, entry));
48807
49392
  if (st.isDirectory() && st.mtimeMs >= startedAt - 2e3) return true;
48808
49393
  } catch {
48809
49394
  }
@@ -49684,7 +50269,7 @@ function computeSkillFingerprint(paths) {
49684
50269
  const pairs = [];
49685
50270
  for (const p of paths) {
49686
50271
  try {
49687
- const st = (0, import_fs77.statSync)(p);
50272
+ const st = (0, import_fs78.statSync)(p);
49688
50273
  pairs.push(`${p}:${st.mtimeMs}`);
49689
50274
  } catch {
49690
50275
  }
@@ -49719,7 +50304,7 @@ function setCachedPrompt(k, e) {
49719
50304
  const evicted = promptCache.get(oldestKey);
49720
50305
  promptCache.delete(oldestKey);
49721
50306
  try {
49722
- (0, import_fs77.unlinkSync)(evicted.skillsSectionPath);
50307
+ (0, import_fs78.unlinkSync)(evicted.skillsSectionPath);
49723
50308
  } catch {
49724
50309
  }
49725
50310
  const evictedAgentId = oldestKey.split("|")[0] ?? "_system";
@@ -49733,7 +50318,7 @@ function invalidateAgent(agentId) {
49733
50318
  if (k.startsWith(`${agentId}|`)) {
49734
50319
  promptCache.delete(k);
49735
50320
  try {
49736
- (0, import_fs77.unlinkSync)(v.skillsSectionPath);
50321
+ (0, import_fs78.unlinkSync)(v.skillsSectionPath);
49737
50322
  } catch {
49738
50323
  }
49739
50324
  emitCacheEvictedSignal(agentId, "invalidation");
@@ -49746,7 +50331,7 @@ function invalidateAll() {
49746
50331
  const n = promptCache.size;
49747
50332
  for (const v of promptCache.values()) {
49748
50333
  try {
49749
- (0, import_fs77.unlinkSync)(v.skillsSectionPath);
50334
+ (0, import_fs78.unlinkSync)(v.skillsSectionPath);
49750
50335
  } catch {
49751
50336
  }
49752
50337
  }
@@ -49793,29 +50378,29 @@ function writeCachedSkillsSection(projectRoot, fingerprint2, skillsSection) {
49793
50378
  if (!/^[a-f0-9]{64}$/.test(fingerprint2)) {
49794
50379
  throw new Error(`writeCachedSkillsSection: invalid fingerprint ${JSON.stringify(fingerprint2).slice(0, 32)}`);
49795
50380
  }
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`);
50381
+ const dir = (0, import_path85.join)(projectRoot, ".gossip", "dispatch-prompts", "cache");
50382
+ (0, import_fs78.mkdirSync)(dir, { recursive: true });
50383
+ const finalPath = (0, import_path85.join)(dir, `skills-${fingerprint2}.txt`);
50384
+ const tmpPath = (0, import_path85.join)(dir, `skills-${fingerprint2}.txt.${(0, import_crypto33.randomUUID)().slice(0, 8)}.tmp`);
49800
50385
  try {
49801
- (0, import_fs77.writeFileSync)(tmpPath, skillsSection, "utf8");
49802
- (0, import_fs77.renameSync)(tmpPath, finalPath);
50386
+ (0, import_fs78.writeFileSync)(tmpPath, skillsSection, "utf8");
50387
+ (0, import_fs78.renameSync)(tmpPath, finalPath);
49803
50388
  } catch (err) {
49804
50389
  try {
49805
- (0, import_fs77.unlinkSync)(tmpPath);
50390
+ (0, import_fs78.unlinkSync)(tmpPath);
49806
50391
  } catch {
49807
50392
  }
49808
50393
  throw err;
49809
50394
  }
49810
- return (0, import_path84.resolve)(finalPath);
50395
+ return (0, import_path85.resolve)(finalPath);
49811
50396
  }
49812
- var import_crypto32, import_fs77, import_path84, import_crypto33, DISPATCH_PROMPT_CACHE_MAX_ENTRIES, promptCache;
50397
+ var import_crypto32, import_fs78, import_path85, import_crypto33, DISPATCH_PROMPT_CACHE_MAX_ENTRIES, promptCache;
49813
50398
  var init_dispatch_prompt_cache = __esm({
49814
50399
  "apps/cli/src/handlers/dispatch-prompt-cache.ts"() {
49815
50400
  "use strict";
49816
50401
  import_crypto32 = require("crypto");
49817
- import_fs77 = require("fs");
49818
- import_path84 = require("path");
50402
+ import_fs78 = require("fs");
50403
+ import_path85 = require("path");
49819
50404
  import_crypto33 = require("crypto");
49820
50405
  DISPATCH_PROMPT_CACHE_MAX_ENTRIES = 64;
49821
50406
  promptCache = /* @__PURE__ */ new Map();
@@ -49842,7 +50427,7 @@ function drainLifecycleTasks(maxMs = 8e3) {
49842
50427
  const snapshot = [...inFlight];
49843
50428
  return Promise.race([
49844
50429
  Promise.allSettled(snapshot).then(() => void 0),
49845
- new Promise((resolve32) => setTimeout(resolve32, maxMs).unref?.())
50430
+ new Promise((resolve33) => setTimeout(resolve33, maxMs).unref?.())
49846
50431
  ]).then(() => void 0);
49847
50432
  }
49848
50433
  function installLifecycleDrainHandlers() {
@@ -49885,31 +50470,31 @@ __export(check_effectiveness_runner_exports, {
49885
50470
  runCheckEffectivenessForAllSkills: () => runCheckEffectivenessForAllSkills
49886
50471
  });
49887
50472
  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");
50473
+ const dir = (0, import_path88.join)(projectRoot, ".gossip");
50474
+ const finalPath = (0, import_path88.join)(dir, "skill-runner-health.json");
49890
50475
  const tmpPath = finalPath + ".tmp";
49891
50476
  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);
50477
+ (0, import_fs82.mkdirSync)(dir, { recursive: true });
50478
+ (0, import_fs82.writeFileSync)(tmpPath, JSON.stringify(record2, null, 2));
50479
+ (0, import_fs82.renameSync)(tmpPath, finalPath);
49895
50480
  } catch (e) {
49896
50481
  process.stderr.write(`[gossipcat] checkEffectiveness: health write failed: ${e.message}
49897
50482
  `);
49898
50483
  try {
49899
- if ((0, import_fs80.existsSync)(tmpPath)) (0, import_fs80.unlinkSync)(tmpPath);
50484
+ if ((0, import_fs82.existsSync)(tmpPath)) (0, import_fs82.unlinkSync)(tmpPath);
49900
50485
  } catch {
49901
50486
  }
49902
50487
  }
49903
50488
  }
49904
50489
  async function runCheckEffectivenessForAllSkills(opts) {
49905
50490
  const startedAt = Date.now();
49906
- const baseDir = (0, import_path86.join)(opts.projectRoot, ".gossip", "agents");
50491
+ const baseDir = (0, import_path88.join)(opts.projectRoot, ".gossip", "agents");
49907
50492
  let agentDirs = [];
49908
50493
  let canonicalBaseDir;
49909
- if ((0, import_fs80.existsSync)(baseDir)) {
50494
+ if ((0, import_fs82.existsSync)(baseDir)) {
49910
50495
  try {
49911
- canonicalBaseDir = (0, import_fs80.realpathSync)(baseDir);
49912
- agentDirs = (0, import_fs80.readdirSync)(canonicalBaseDir);
50496
+ canonicalBaseDir = (0, import_fs82.realpathSync)(baseDir);
50497
+ agentDirs = (0, import_fs82.readdirSync)(canonicalBaseDir);
49913
50498
  } catch {
49914
50499
  }
49915
50500
  }
@@ -49928,11 +50513,11 @@ async function runCheckEffectivenessForAllSkills(opts) {
49928
50513
  for (const agentId of agentDirs) {
49929
50514
  if (agentId.startsWith("_")) continue;
49930
50515
  if (!SAFE_NAME2.test(agentId)) continue;
49931
- const skillsDir = (0, import_path86.join)(canonicalBaseDir, agentId, "skills");
49932
- if (!(0, import_fs80.existsSync)(skillsDir)) continue;
50516
+ const skillsDir = (0, import_path88.join)(canonicalBaseDir, agentId, "skills");
50517
+ if (!(0, import_fs82.existsSync)(skillsDir)) continue;
49933
50518
  let canonicalSkillsDir;
49934
50519
  try {
49935
- canonicalSkillsDir = (0, import_fs80.realpathSync)(skillsDir);
50520
+ canonicalSkillsDir = (0, import_fs82.realpathSync)(skillsDir);
49936
50521
  } catch {
49937
50522
  continue;
49938
50523
  }
@@ -49943,7 +50528,7 @@ async function runCheckEffectivenessForAllSkills(opts) {
49943
50528
  }
49944
50529
  const role = opts.registryGet(agentId)?.role;
49945
50530
  if (role === "implementer") continue;
49946
- const files = (0, import_fs80.readdirSync)(canonicalSkillsDir).filter((f) => f.endsWith(".md"));
50531
+ const files = (0, import_fs82.readdirSync)(canonicalSkillsDir).filter((f) => f.endsWith(".md"));
49947
50532
  for (const file2 of files) {
49948
50533
  const category = file2.replace(/\.md$/, "");
49949
50534
  if (!SAFE_NAME2.test(category)) continue;
@@ -49990,12 +50575,12 @@ async function runCheckEffectivenessForAllSkills(opts) {
49990
50575
  last_error: lastError
49991
50576
  });
49992
50577
  }
49993
- var import_fs80, import_path86, SAFE_NAME2;
50578
+ var import_fs82, import_path88, SAFE_NAME2;
49994
50579
  var init_check_effectiveness_runner = __esm({
49995
50580
  "apps/cli/src/handlers/check-effectiveness-runner.ts"() {
49996
50581
  "use strict";
49997
- import_fs80 = require("fs");
49998
- import_path86 = require("path");
50582
+ import_fs82 = require("fs");
50583
+ import_path88 = require("path");
49999
50584
  init_dispatch_prompt_cache();
50000
50585
  SAFE_NAME2 = /^(?!.*\.\.)[a-zA-Z0-9._-]+$/;
50001
50586
  }
@@ -50008,20 +50593,20 @@ __export(skill_develop_audit_exports, {
50008
50593
  });
50009
50594
  function appendSkillDevelopAudit(entry) {
50010
50595
  try {
50011
- const gossipDir = (0, import_path87.join)(process.cwd(), ".gossip");
50012
- (0, import_fs81.mkdirSync)(gossipDir, { recursive: true });
50596
+ const gossipDir = (0, import_path89.join)(process.cwd(), ".gossip");
50597
+ (0, import_fs83.mkdirSync)(gossipDir, { recursive: true });
50013
50598
  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);
50599
+ (0, import_fs83.appendFileSync)((0, import_path89.join)(gossipDir, AUDIT_FILE2), line);
50600
+ (0, import_fs83.appendFileSync)((0, import_path89.join)(gossipDir, LEGACY_FILE), line);
50016
50601
  } catch {
50017
50602
  }
50018
50603
  }
50019
- var import_fs81, import_path87, AUDIT_FILE2, LEGACY_FILE;
50604
+ var import_fs83, import_path89, AUDIT_FILE2, LEGACY_FILE;
50020
50605
  var init_skill_develop_audit = __esm({
50021
50606
  "apps/cli/src/handlers/skill-develop-audit.ts"() {
50022
50607
  "use strict";
50023
- import_fs81 = require("fs");
50024
- import_path87 = require("path");
50608
+ import_fs83 = require("fs");
50609
+ import_path89 = require("path");
50025
50610
  AUDIT_FILE2 = "skill-develop-audit.jsonl";
50026
50611
  LEGACY_FILE = "forced-skill-develops.jsonl";
50027
50612
  }
@@ -50079,14 +50664,14 @@ var keychain_exports = {};
50079
50664
  __export(keychain_exports, {
50080
50665
  Keychain: () => Keychain
50081
50666
  });
50082
- var import_child_process14, import_os6, import_fs85, import_path91, import_crypto35, DEFAULT_SERVICE_NAME, VALID_PROVIDERS3, ENCRYPTED_FILE, ALGO, Keychain;
50667
+ var import_child_process15, import_os6, import_fs87, import_path93, import_crypto35, DEFAULT_SERVICE_NAME, VALID_PROVIDERS3, ENCRYPTED_FILE, ALGO, Keychain;
50083
50668
  var init_keychain = __esm({
50084
50669
  "apps/cli/src/keychain.ts"() {
50085
50670
  "use strict";
50086
- import_child_process14 = require("child_process");
50671
+ import_child_process15 = require("child_process");
50087
50672
  import_os6 = require("os");
50088
- import_fs85 = require("fs");
50089
- import_path91 = require("path");
50673
+ import_fs87 = require("fs");
50674
+ import_path93 = require("path");
50090
50675
  import_crypto35 = require("crypto");
50091
50676
  DEFAULT_SERVICE_NAME = "gossip-mesh";
50092
50677
  VALID_PROVIDERS3 = /^[a-zA-Z0-9_-]{1,32}$/;
@@ -50130,10 +50715,10 @@ var init_keychain = __esm({
50130
50715
  return (0, import_crypto35.pbkdf2Sync)(seed, salt, 6e5, 32, "sha256");
50131
50716
  }
50132
50717
  loadEncryptedFile() {
50133
- const filePath = (0, import_path91.join)(process.cwd(), ENCRYPTED_FILE);
50134
- if (!(0, import_fs85.existsSync)(filePath)) return;
50718
+ const filePath = (0, import_path93.join)(process.cwd(), ENCRYPTED_FILE);
50719
+ if (!(0, import_fs87.existsSync)(filePath)) return;
50135
50720
  try {
50136
- const raw = (0, import_fs85.readFileSync)(filePath);
50721
+ const raw = (0, import_fs87.readFileSync)(filePath);
50137
50722
  if (raw.length < 61) return;
50138
50723
  const salt = raw.subarray(0, 32);
50139
50724
  const iv = raw.subarray(32, 44);
@@ -50151,9 +50736,9 @@ var init_keychain = __esm({
50151
50736
  }
50152
50737
  }
50153
50738
  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 });
50739
+ const filePath = (0, import_path93.join)(process.cwd(), ENCRYPTED_FILE);
50740
+ const dir = (0, import_path93.join)(process.cwd(), ".gossip");
50741
+ if (!(0, import_fs87.existsSync)(dir)) (0, import_fs87.mkdirSync)(dir, { recursive: true });
50157
50742
  const data = JSON.stringify(Object.fromEntries(this.inMemoryStore));
50158
50743
  const salt = (0, import_crypto35.randomBytes)(32);
50159
50744
  const iv = (0, import_crypto35.randomBytes)(12);
@@ -50161,12 +50746,12 @@ var init_keychain = __esm({
50161
50746
  const cipher = (0, import_crypto35.createCipheriv)(ALGO, key, iv);
50162
50747
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
50163
50748
  const tag = cipher.getAuthTag();
50164
- (0, import_fs85.writeFileSync)(filePath, Buffer.concat([salt, iv, tag, encrypted]), { mode: 384 });
50749
+ (0, import_fs87.writeFileSync)(filePath, Buffer.concat([salt, iv, tag, encrypted]), { mode: 384 });
50165
50750
  }
50166
50751
  isKeychainAvailable() {
50167
50752
  if ((0, import_os6.platform)() === "darwin") {
50168
50753
  try {
50169
- (0, import_child_process14.execFileSync)("security", ["help"], { stdio: "pipe" });
50754
+ (0, import_child_process15.execFileSync)("security", ["help"], { stdio: "pipe" });
50170
50755
  return true;
50171
50756
  } catch {
50172
50757
  return false;
@@ -50174,7 +50759,7 @@ var init_keychain = __esm({
50174
50759
  }
50175
50760
  if ((0, import_os6.platform)() === "linux") {
50176
50761
  try {
50177
- (0, import_child_process14.execFileSync)("which", ["secret-tool"], { stdio: "pipe" });
50762
+ (0, import_child_process15.execFileSync)("which", ["secret-tool"], { stdio: "pipe" });
50178
50763
  return true;
50179
50764
  } catch {
50180
50765
  return false;
@@ -50190,7 +50775,7 @@ var init_keychain = __esm({
50190
50775
  readFromKeychain(provider) {
50191
50776
  this.validateProvider(provider);
50192
50777
  if ((0, import_os6.platform)() === "darwin") {
50193
- return (0, import_child_process14.execFileSync)("security", [
50778
+ return (0, import_child_process15.execFileSync)("security", [
50194
50779
  "find-generic-password",
50195
50780
  "-s",
50196
50781
  this.serviceName,
@@ -50200,7 +50785,7 @@ var init_keychain = __esm({
50200
50785
  ], { stdio: "pipe" }).toString().trim();
50201
50786
  }
50202
50787
  if ((0, import_os6.platform)() === "linux") {
50203
- return (0, import_child_process14.execFileSync)("secret-tool", [
50788
+ return (0, import_child_process15.execFileSync)("secret-tool", [
50204
50789
  "lookup",
50205
50790
  "service",
50206
50791
  this.serviceName,
@@ -50214,7 +50799,7 @@ var init_keychain = __esm({
50214
50799
  this.validateProvider(provider);
50215
50800
  if ((0, import_os6.platform)() === "darwin") {
50216
50801
  try {
50217
- (0, import_child_process14.execFileSync)("security", [
50802
+ (0, import_child_process15.execFileSync)("security", [
50218
50803
  "delete-generic-password",
50219
50804
  "-s",
50220
50805
  this.serviceName,
@@ -50223,7 +50808,7 @@ var init_keychain = __esm({
50223
50808
  ], { stdio: "pipe" });
50224
50809
  } catch {
50225
50810
  }
50226
- (0, import_child_process14.execFileSync)("security", [
50811
+ (0, import_child_process15.execFileSync)("security", [
50227
50812
  "add-generic-password",
50228
50813
  "-s",
50229
50814
  this.serviceName,
@@ -50235,7 +50820,7 @@ var init_keychain = __esm({
50235
50820
  return;
50236
50821
  }
50237
50822
  if ((0, import_os6.platform)() === "linux") {
50238
- (0, import_child_process14.execFileSync)("secret-tool", [
50823
+ (0, import_child_process15.execFileSync)("secret-tool", [
50239
50824
  "store",
50240
50825
  "--label",
50241
50826
  `Gossip Mesh ${provider}`,
@@ -50254,12 +50839,13 @@ var init_keychain = __esm({
50254
50839
  // apps/cli/src/code-launch.ts
50255
50840
  var code_launch_exports = {};
50256
50841
  __export(code_launch_exports, {
50842
+ detectServerName: () => detectServerName,
50257
50843
  runCodeCommand: () => runCodeCommand
50258
50844
  });
50259
50845
  function safeReadJson(filePath) {
50260
50846
  try {
50261
- if (!(0, import_fs86.existsSync)(filePath)) return null;
50262
- const raw = (0, import_fs86.readFileSync)(filePath, "utf-8");
50847
+ if (!(0, import_fs88.existsSync)(filePath)) return null;
50848
+ const raw = (0, import_fs88.readFileSync)(filePath, "utf-8");
50263
50849
  return JSON.parse(raw);
50264
50850
  } catch {
50265
50851
  return null;
@@ -50276,21 +50862,23 @@ function isGossipMcpEntry(entry) {
50276
50862
  return false;
50277
50863
  }
50278
50864
  function detectServerName(cwd) {
50865
+ const cwdPath = (0, import_path94.join)(cwd, ".mcp.json");
50866
+ const homePath = (0, import_path94.join)((0, import_os7.homedir)(), ".claude.json");
50279
50867
  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"))]
50868
+ [cwdPath, safeReadJson(cwdPath)],
50869
+ [homePath, safeReadJson(homePath)]
50282
50870
  ];
50283
- for (const [filePath, data] of candidates) {
50284
- if (!data || typeof data !== "object") continue;
50871
+ function extractName(data, filePath) {
50872
+ if (!data || typeof data !== "object") return null;
50285
50873
  const root = data;
50286
50874
  const mcpServers = root["mcpServers"];
50287
- if (!mcpServers || typeof mcpServers !== "object") continue;
50875
+ if (!mcpServers || typeof mcpServers !== "object") return null;
50288
50876
  const servers = mcpServers;
50289
50877
  for (const [name, entry] of Object.entries(servers)) {
50290
50878
  if (!entry || typeof entry !== "object") continue;
50291
50879
  if (isGossipMcpEntry(entry)) {
50292
50880
  if (SAFE_SERVER_NAME_RE.test(name)) {
50293
- return [name, false];
50881
+ return name;
50294
50882
  }
50295
50883
  process.stderr.write(
50296
50884
  `[gossipcat code] Warning: found gossipcat MCP entry in ${filePath} but server name "${name}" contains unsafe characters; falling back to "gossipcat".
@@ -50298,11 +50886,30 @@ function detectServerName(cwd) {
50298
50886
  );
50299
50887
  }
50300
50888
  }
50889
+ return null;
50890
+ }
50891
+ const cwdName = extractName(candidates[0][1], cwdPath);
50892
+ const homeName = extractName(candidates[1][1], homePath);
50893
+ if (cwdName !== null) {
50894
+ process.stderr.write(
50895
+ `[gossipcat code] Using channel server "${cwdName}" from ${cwdPath} (cwd-local config \u2014 only run this in repos you trust).
50896
+ `
50897
+ );
50898
+ if (homeName !== null && homeName !== cwdName) {
50899
+ process.stderr.write(
50900
+ `[gossipcat code] Warning: gossipcat server name differs between ${cwdPath} ("${cwdName}") and ${homePath} ("${homeName}"); using "${cwdName}" (cwd takes precedence).
50901
+ `
50902
+ );
50903
+ }
50904
+ return [cwdName, false];
50905
+ }
50906
+ if (homeName !== null) {
50907
+ return [homeName, false];
50301
50908
  }
50302
50909
  return ["gossipcat", true];
50303
50910
  }
50304
50911
  function isChannelAllowlisted(cwd) {
50305
- const configPath = (0, import_path92.join)(cwd, ".gossip", "config.json");
50912
+ const configPath = (0, import_path94.join)(cwd, ".gossip", "config.json");
50306
50913
  try {
50307
50914
  const data = safeReadJson(configPath);
50308
50915
  if (!data || typeof data !== "object") return false;
@@ -50334,7 +50941,7 @@ function runCodeCommand(argv) {
50334
50941
  );
50335
50942
  claudeArgs = ["--dangerously-load-development-channels", `server:${serverName}`, ...argv];
50336
50943
  }
50337
- const child = (0, import_child_process15.spawn)("claude", claudeArgs, { stdio: "inherit" });
50944
+ const child = (0, import_child_process16.spawn)("claude", claudeArgs, { stdio: "inherit" });
50338
50945
  child.on("error", (err) => {
50339
50946
  if (err.code === "ENOENT") {
50340
50947
  process.stderr.write(
@@ -50355,14 +50962,14 @@ function runCodeCommand(argv) {
50355
50962
  }
50356
50963
  });
50357
50964
  }
50358
- var import_fs86, import_path92, import_os7, import_child_process15, SAFE_SERVER_NAME_RE;
50965
+ var import_fs88, import_path94, import_os7, import_child_process16, SAFE_SERVER_NAME_RE;
50359
50966
  var init_code_launch = __esm({
50360
50967
  "apps/cli/src/code-launch.ts"() {
50361
50968
  "use strict";
50362
- import_fs86 = require("fs");
50363
- import_path92 = require("path");
50969
+ import_fs88 = require("fs");
50970
+ import_path94 = require("path");
50364
50971
  import_os7 = require("os");
50365
- import_child_process15 = require("child_process");
50972
+ import_child_process16 = require("child_process");
50366
50973
  SAFE_SERVER_NAME_RE = /^[a-zA-Z0-9._-]{1,64}$/;
50367
50974
  }
50368
50975
  });
@@ -50377,23 +50984,23 @@ __export(identity_exports, {
50377
50984
  normalizeGitUrl: () => normalizeGitUrl
50378
50985
  });
50379
50986
  function getOrCreateSalt(projectRoot) {
50380
- const saltPath = (0, import_path93.join)(projectRoot, ".gossip", "local-salt");
50987
+ const saltPath = (0, import_path95.join)(projectRoot, ".gossip", "local-salt");
50381
50988
  try {
50382
- return (0, import_fs87.readFileSync)(saltPath, "utf-8").trim();
50989
+ return (0, import_fs89.readFileSync)(saltPath, "utf-8").trim();
50383
50990
  } catch {
50384
50991
  const salt = (0, import_crypto36.randomBytes)(16).toString("hex");
50385
- (0, import_fs87.mkdirSync)((0, import_path93.join)(projectRoot, ".gossip"), { recursive: true });
50992
+ (0, import_fs89.mkdirSync)((0, import_path95.join)(projectRoot, ".gossip"), { recursive: true });
50386
50993
  try {
50387
- (0, import_fs87.writeFileSync)(saltPath, salt, { flag: "wx" });
50994
+ (0, import_fs89.writeFileSync)(saltPath, salt, { flag: "wx" });
50388
50995
  return salt;
50389
50996
  } catch {
50390
- return (0, import_fs87.readFileSync)(saltPath, "utf-8").trim();
50997
+ return (0, import_fs89.readFileSync)(saltPath, "utf-8").trim();
50391
50998
  }
50392
50999
  }
50393
51000
  }
50394
51001
  function getUserId(projectRoot) {
50395
51002
  try {
50396
- const email3 = (0, import_child_process16.execFileSync)("git", ["config", "user.email"], { stdio: "pipe" }).toString().trim();
51003
+ const email3 = (0, import_child_process17.execFileSync)("git", ["config", "user.email"], { stdio: "pipe" }).toString().trim();
50397
51004
  const salt = getOrCreateSalt(projectRoot);
50398
51005
  return (0, import_crypto36.createHash)("sha256").update(email3 + projectRoot + salt).digest("hex").slice(0, 16);
50399
51006
  } catch {
@@ -50416,7 +51023,7 @@ function getTeamUserId(email3, teamSalt) {
50416
51023
  }
50417
51024
  function getGitEmail() {
50418
51025
  try {
50419
- const email3 = (0, import_child_process16.execFileSync)("git", ["config", "user.email"], { stdio: "pipe" }).toString().trim();
51026
+ const email3 = (0, import_child_process17.execFileSync)("git", ["config", "user.email"], { stdio: "pipe" }).toString().trim();
50420
51027
  return email3 || null;
50421
51028
  } catch {
50422
51029
  return null;
@@ -50424,7 +51031,7 @@ function getGitEmail() {
50424
51031
  }
50425
51032
  function getProjectId(projectRoot) {
50426
51033
  try {
50427
- const remoteUrl = (0, import_child_process16.execFileSync)(
51034
+ const remoteUrl = (0, import_child_process17.execFileSync)(
50428
51035
  "git",
50429
51036
  ["config", "--get", "remote.origin.url"],
50430
51037
  { cwd: projectRoot, stdio: "pipe" }
@@ -50437,14 +51044,14 @@ function getProjectId(projectRoot) {
50437
51044
  }
50438
51045
  return (0, import_crypto36.createHash)("sha256").update(projectRoot).digest("hex").slice(0, 16);
50439
51046
  }
50440
- var import_fs87, import_path93, import_crypto36, import_child_process16;
51047
+ var import_fs89, import_path95, import_crypto36, import_child_process17;
50441
51048
  var init_identity = __esm({
50442
51049
  "apps/cli/src/identity.ts"() {
50443
51050
  "use strict";
50444
- import_fs87 = require("fs");
50445
- import_path93 = require("path");
51051
+ import_fs89 = require("fs");
51052
+ import_path95 = require("path");
50446
51053
  import_crypto36 = require("crypto");
50447
- import_child_process16 = require("child_process");
51054
+ import_child_process17 = require("child_process");
50448
51055
  }
50449
51056
  });
50450
51057
 
@@ -50511,9 +51118,9 @@ async function getLatestVersion() {
50511
51118
  return data.version;
50512
51119
  }
50513
51120
  function detectInstallMethod() {
50514
- const packageRoot = (0, import_path94.resolve)(__dirname, "..", "..", "..", "..");
51121
+ const packageRoot = (0, import_path96.resolve)(__dirname, "..", "..", "..", "..");
50515
51122
  if (process.env.npm_config_global === "true") return "global";
50516
- if ((0, import_fs88.existsSync)((0, import_path94.join)(packageRoot, ".git"))) return "git-clone";
51123
+ if ((0, import_fs90.existsSync)((0, import_path96.join)(packageRoot, ".git"))) return "git-clone";
50517
51124
  return "local";
50518
51125
  }
50519
51126
  function updateCommand(method, version2) {
@@ -50566,9 +51173,9 @@ Check your internet connection or visit https://www.npmjs.com/package/gossipcat
50566
51173
  if (/^GOSSIPCAT_/i.test(key)) delete scrubbedEnv[key];
50567
51174
  }
50568
51175
  try {
50569
- (0, import_child_process17.execSync)(command, {
51176
+ (0, import_child_process18.execSync)(command, {
50570
51177
  stdio: "inherit",
50571
- cwd: method === "git-clone" ? (0, import_path94.resolve)(__dirname, "..", "..", "..", "..") : process.cwd(),
51178
+ cwd: method === "git-clone" ? (0, import_path96.resolve)(__dirname, "..", "..", "..", "..") : process.cwd(),
50572
51179
  env: scrubbedEnv
50573
51180
  });
50574
51181
  } catch (err) {
@@ -50591,13 +51198,13 @@ Run /mcp reconnect in Claude Code to load the new version.`
50591
51198
  }]
50592
51199
  };
50593
51200
  }
50594
- var import_child_process17, import_fs88, import_path94;
51201
+ var import_child_process18, import_fs90, import_path96;
50595
51202
  var init_gossip_update = __esm({
50596
51203
  "apps/cli/src/handlers/gossip-update.ts"() {
50597
51204
  "use strict";
50598
- import_child_process17 = require("child_process");
50599
- import_fs88 = require("fs");
50600
- import_path94 = require("path");
51205
+ import_child_process18 = require("child_process");
51206
+ import_fs90 = require("fs");
51207
+ import_path96 = require("path");
50601
51208
  init_version();
50602
51209
  }
50603
51210
  });
@@ -50810,8 +51417,8 @@ __export(mcp_server_sdk_exports, {
50810
51417
  resolveHookAction: () => resolveHookAction
50811
51418
  });
50812
51419
  module.exports = __toCommonJS(mcp_server_sdk_exports);
50813
- var import_fs89 = require("fs");
50814
- var import_path95 = require("path");
51420
+ var import_fs91 = require("fs");
51421
+ var import_path97 = require("path");
50815
51422
 
50816
51423
  // apps/cli/src/hook-run.ts
50817
51424
  var import_fs = require("fs");
@@ -50894,10 +51501,10 @@ var RELAY_PORT_FILE = "relay.port";
50894
51501
  var AUTH_MAX_READ = 64 * 1024;
50895
51502
  var CURL_MAX_TIME = "2";
50896
51503
  function readDashboardKey(cwd) {
50897
- const path7 = (0, import_path2.join)(cwd, ".gossip", AUTH_FILE_NAME);
51504
+ const path8 = (0, import_path2.join)(cwd, ".gossip", AUTH_FILE_NAME);
50898
51505
  let fd = null;
50899
51506
  try {
50900
- fd = (0, import_fs2.openSync)(path7, "r");
51507
+ fd = (0, import_fs2.openSync)(path8, "r");
50901
51508
  const st = (0, import_fs2.fstatSync)(fd);
50902
51509
  if (!st.isFile()) return null;
50903
51510
  if ((st.mode & 63) !== 0) return null;
@@ -50994,7 +51601,7 @@ function resolveCwd(payloadCwd) {
50994
51601
  return process.cwd();
50995
51602
  }
50996
51603
  function readStdin() {
50997
- return new Promise((resolve32) => {
51604
+ return new Promise((resolve33) => {
50998
51605
  let data = "";
50999
51606
  try {
51000
51607
  const stdin = process.stdin;
@@ -51002,11 +51609,11 @@ function readStdin() {
51002
51609
  stdin.on("data", (chunk) => {
51003
51610
  data += chunk;
51004
51611
  });
51005
- stdin.on("end", () => resolve32(data));
51006
- stdin.on("error", () => resolve32(data));
51007
- if (stdin.isTTY) resolve32("");
51612
+ stdin.on("end", () => resolve33(data));
51613
+ stdin.on("error", () => resolve33(data));
51614
+ if (stdin.isTTY) resolve33("");
51008
51615
  } catch {
51009
- resolve32("");
51616
+ resolve33("");
51010
51617
  }
51011
51618
  });
51012
51619
  }
@@ -51243,9 +51850,9 @@ function getLastKnownLatest(cwd = process.cwd()) {
51243
51850
  async function checkForUpgrade(cwd = process.cwd()) {
51244
51851
  try {
51245
51852
  if (process.env.GOSSIP_DISABLE_UPGRADE_CHECK === "1") return;
51246
- const path7 = cachePath(cwd);
51853
+ const path8 = cachePath(cwd);
51247
51854
  try {
51248
- const raw = (0, import_fs4.readFileSync)(path7, "utf8");
51855
+ const raw = (0, import_fs4.readFileSync)(path8, "utf8");
51249
51856
  const data = JSON.parse(raw);
51250
51857
  if (typeof data.checkedAt === "string") {
51251
51858
  const checkedMs = new Date(data.checkedAt).getTime();
@@ -51262,13 +51869,13 @@ async function checkForUpgrade(cwd = process.cwd()) {
51262
51869
  latestVersion: json2.version
51263
51870
  };
51264
51871
  try {
51265
- (0, import_fs4.mkdirSync)((0, import_path3.dirname)(path7), { recursive: true });
51872
+ (0, import_fs4.mkdirSync)((0, import_path3.dirname)(path8), { recursive: true });
51266
51873
  } catch {
51267
51874
  }
51268
- const tmp = `${path7}.${process.pid}.tmp`;
51875
+ const tmp = `${path8}.${process.pid}.tmp`;
51269
51876
  (0, import_fs4.writeFileSync)(tmp, JSON.stringify(cache3), "utf8");
51270
51877
  try {
51271
- (0, import_fs4.renameSync)(tmp, path7);
51878
+ (0, import_fs4.renameSync)(tmp, path8);
51272
51879
  } catch (err) {
51273
51880
  try {
51274
51881
  (0, import_fs4.unlinkSync)(tmp);
@@ -51659,8 +52266,8 @@ function getErrorMap() {
51659
52266
 
51660
52267
  // node_modules/zod/v3/helpers/parseUtil.js
51661
52268
  var makeIssue = (params) => {
51662
- const { data, path: path7, errorMaps, issueData } = params;
51663
- const fullPath = [...path7, ...issueData.path || []];
52269
+ const { data, path: path8, errorMaps, issueData } = params;
52270
+ const fullPath = [...path8, ...issueData.path || []];
51664
52271
  const fullIssue = {
51665
52272
  ...issueData,
51666
52273
  path: fullPath
@@ -51775,11 +52382,11 @@ var errorUtil;
51775
52382
 
51776
52383
  // node_modules/zod/v3/types.js
51777
52384
  var ParseInputLazyPath = class {
51778
- constructor(parent, value, path7, key) {
52385
+ constructor(parent, value, path8, key) {
51779
52386
  this._cachedPath = [];
51780
52387
  this.parent = parent;
51781
52388
  this.data = value;
51782
- this._path = path7;
52389
+ this._path = path8;
51783
52390
  this._key = key;
51784
52391
  }
51785
52392
  get path() {
@@ -55699,10 +56306,10 @@ function mergeDefs(...defs) {
55699
56306
  function cloneDef(schema) {
55700
56307
  return mergeDefs(schema._zod.def);
55701
56308
  }
55702
- function getElementAtPath(obj, path7) {
55703
- if (!path7)
56309
+ function getElementAtPath(obj, path8) {
56310
+ if (!path8)
55704
56311
  return obj;
55705
- return path7.reduce((acc, key) => acc?.[key], obj);
56312
+ return path8.reduce((acc, key) => acc?.[key], obj);
55706
56313
  }
55707
56314
  function promiseAllObject(promisesObj) {
55708
56315
  const keys = Object.keys(promisesObj);
@@ -56111,11 +56718,11 @@ function explicitlyAborted(x, startIndex = 0) {
56111
56718
  }
56112
56719
  return false;
56113
56720
  }
56114
- function prefixIssues(path7, issues) {
56721
+ function prefixIssues(path8, issues) {
56115
56722
  return issues.map((iss) => {
56116
56723
  var _a3;
56117
56724
  (_a3 = iss).path ?? (_a3.path = []);
56118
- iss.path.unshift(path7);
56725
+ iss.path.unshift(path8);
56119
56726
  return iss;
56120
56727
  });
56121
56728
  }
@@ -56262,16 +56869,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
56262
56869
  }
56263
56870
  function formatError(error51, mapper = (issue2) => issue2.message) {
56264
56871
  const fieldErrors = { _errors: [] };
56265
- const processError = (error52, path7 = []) => {
56872
+ const processError = (error52, path8 = []) => {
56266
56873
  for (const issue2 of error52.issues) {
56267
56874
  if (issue2.code === "invalid_union" && issue2.errors.length) {
56268
- issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
56875
+ issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
56269
56876
  } else if (issue2.code === "invalid_key") {
56270
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
56877
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
56271
56878
  } else if (issue2.code === "invalid_element") {
56272
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
56879
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
56273
56880
  } else {
56274
- const fullpath = [...path7, ...issue2.path];
56881
+ const fullpath = [...path8, ...issue2.path];
56275
56882
  if (fullpath.length === 0) {
56276
56883
  fieldErrors._errors.push(mapper(issue2));
56277
56884
  } else {
@@ -56298,17 +56905,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
56298
56905
  }
56299
56906
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
56300
56907
  const result = { errors: [] };
56301
- const processError = (error52, path7 = []) => {
56908
+ const processError = (error52, path8 = []) => {
56302
56909
  var _a3, _b;
56303
56910
  for (const issue2 of error52.issues) {
56304
56911
  if (issue2.code === "invalid_union" && issue2.errors.length) {
56305
- issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
56912
+ issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
56306
56913
  } else if (issue2.code === "invalid_key") {
56307
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
56914
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
56308
56915
  } else if (issue2.code === "invalid_element") {
56309
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
56916
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
56310
56917
  } else {
56311
- const fullpath = [...path7, ...issue2.path];
56918
+ const fullpath = [...path8, ...issue2.path];
56312
56919
  if (fullpath.length === 0) {
56313
56920
  result.errors.push(mapper(issue2));
56314
56921
  continue;
@@ -56340,8 +56947,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
56340
56947
  }
56341
56948
  function toDotPath(_path) {
56342
56949
  const segs = [];
56343
- const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
56344
- for (const seg of path7) {
56950
+ const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
56951
+ for (const seg of path8) {
56345
56952
  if (typeof seg === "number")
56346
56953
  segs.push(`[${seg}]`);
56347
56954
  else if (typeof seg === "symbol")
@@ -69466,13 +70073,13 @@ function resolveRef(ref, ctx2) {
69466
70073
  if (!ref.startsWith("#")) {
69467
70074
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
69468
70075
  }
69469
- const path7 = ref.slice(1).split("/").filter(Boolean);
69470
- if (path7.length === 0) {
70076
+ const path8 = ref.slice(1).split("/").filter(Boolean);
70077
+ if (path8.length === 0) {
69471
70078
  return ctx2.rootSchema;
69472
70079
  }
69473
70080
  const defsKey = ctx2.version === "draft-2020-12" ? "$defs" : "definitions";
69474
- if (path7[0] === defsKey) {
69475
- const key = path7[1];
70081
+ if (path8[0] === defsKey) {
70082
+ const key = path8[1];
69476
70083
  if (!key || !ctx2.defs[key]) {
69477
70084
  throw new Error(`Reference not found: ${ref}`);
69478
70085
  }
@@ -73244,7 +73851,7 @@ var Protocol = class {
73244
73851
  return;
73245
73852
  }
73246
73853
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
73247
- await new Promise((resolve32) => setTimeout(resolve32, pollInterval));
73854
+ await new Promise((resolve33) => setTimeout(resolve33, pollInterval));
73248
73855
  options?.signal?.throwIfAborted();
73249
73856
  }
73250
73857
  } catch (error51) {
@@ -73261,7 +73868,7 @@ var Protocol = class {
73261
73868
  */
73262
73869
  request(request, resultSchema, options) {
73263
73870
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
73264
- return new Promise((resolve32, reject) => {
73871
+ return new Promise((resolve33, reject) => {
73265
73872
  const earlyReject = (error51) => {
73266
73873
  reject(error51);
73267
73874
  };
@@ -73339,7 +73946,7 @@ var Protocol = class {
73339
73946
  if (!parseResult.success) {
73340
73947
  reject(parseResult.error);
73341
73948
  } else {
73342
- resolve32(parseResult.data);
73949
+ resolve33(parseResult.data);
73343
73950
  }
73344
73951
  } catch (error51) {
73345
73952
  reject(error51);
@@ -73600,12 +74207,12 @@ var Protocol = class {
73600
74207
  }
73601
74208
  } catch {
73602
74209
  }
73603
- return new Promise((resolve32, reject) => {
74210
+ return new Promise((resolve33, reject) => {
73604
74211
  if (signal.aborted) {
73605
74212
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
73606
74213
  return;
73607
74214
  }
73608
- const timeoutId = setTimeout(resolve32, interval);
74215
+ const timeoutId = setTimeout(resolve33, interval);
73609
74216
  signal.addEventListener("abort", () => {
73610
74217
  clearTimeout(timeoutId);
73611
74218
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -74705,7 +75312,7 @@ var McpServer = class {
74705
75312
  let task = createTaskResult.task;
74706
75313
  const pollInterval = task.pollInterval ?? 5e3;
74707
75314
  while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
74708
- await new Promise((resolve32) => setTimeout(resolve32, pollInterval));
75315
+ await new Promise((resolve33) => setTimeout(resolve33, pollInterval));
74709
75316
  const updatedTask = await extra.taskStore.getTask(taskId);
74710
75317
  if (!updatedTask) {
74711
75318
  throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
@@ -75408,12 +76015,12 @@ var StdioServerTransport = class {
75408
76015
  this.onclose?.();
75409
76016
  }
75410
76017
  send(message) {
75411
- return new Promise((resolve32) => {
76018
+ return new Promise((resolve33) => {
75412
76019
  const json2 = serializeMessage(message);
75413
76020
  if (this._stdout.write(json2)) {
75414
- resolve32();
76021
+ resolve33();
75415
76022
  } else {
75416
- this._stdout.once("drain", resolve32);
76023
+ this._stdout.once("drain", resolve33);
75417
76024
  }
75418
76025
  });
75419
76026
  }
@@ -75912,7 +76519,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
75912
76519
  });
75913
76520
  if (!chunk) {
75914
76521
  if (i === 1) {
75915
- await new Promise((resolve32) => setTimeout(resolve32));
76522
+ await new Promise((resolve33) => setTimeout(resolve33));
75916
76523
  maxReadCount = 3;
75917
76524
  continue;
75918
76525
  }
@@ -76412,9 +77019,9 @@ data:
76412
77019
  const initRequest = messages.find((m) => isInitializeRequest(m));
76413
77020
  const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
76414
77021
  if (this._enableJsonResponse) {
76415
- return new Promise((resolve32) => {
77022
+ return new Promise((resolve33) => {
76416
77023
  this._streamMapping.set(streamId, {
76417
- resolveJson: resolve32,
77024
+ resolveJson: resolve33,
76418
77025
  cleanup: () => {
76419
77026
  this._streamMapping.delete(streamId);
76420
77027
  }
@@ -76799,8 +77406,8 @@ init_native_tasks();
76799
77406
 
76800
77407
  // apps/cli/src/handlers/dispatch.ts
76801
77408
  var import_crypto34 = require("crypto");
76802
- var import_fs78 = require("fs");
76803
- var import_path85 = require("path");
77409
+ var import_fs79 = require("fs");
77410
+ var import_path86 = require("path");
76804
77411
  init_src4();
76805
77412
  init_src3();
76806
77413
 
@@ -76934,10 +77541,11 @@ function nativeDispatchViaLabel(host = detectNativeHost()) {
76934
77541
 
76935
77542
  // apps/cli/src/handlers/dispatch.ts
76936
77543
  init_mcp_context();
77544
+ init_orchestrator_precondition_runner();
76937
77545
  init_native_tasks();
76938
77546
  init_dispatch_prompt_storage();
76939
77547
  init_dispatch_prompt_cache();
76940
- var import_fs79 = require("fs");
77548
+ var import_fs80 = require("fs");
76941
77549
 
76942
77550
  // apps/cli/src/handlers/relay-tasks.ts
76943
77551
  init_mcp_context();
@@ -77108,7 +77716,7 @@ function tryWarmCacheHit(liveTaskBlock, cacheKey2, promptFormat) {
77108
77716
  const cached4 = getCachedPrompt(cacheKey2);
77109
77717
  if (!cached4) return null;
77110
77718
  if (cached4.skillFingerprint !== cacheKey2.skillFingerprint) return null;
77111
- if (!(0, import_fs79.existsSync)(cached4.skillsSectionPath)) return null;
77719
+ if (!(0, import_fs80.existsSync)(cached4.skillsSectionPath)) return null;
77112
77720
  try {
77113
77721
  const skillsSection = require("fs").readFileSync(cached4.skillsSectionPath, "utf8");
77114
77722
  return skillsSection + liveTaskBlock;
@@ -77185,9 +77793,9 @@ function formatFalsifiedNote(block, verdicts) {
77185
77793
  }
77186
77794
  function writePremiseVerificationLog(projectRoot, taskId, result, opts) {
77187
77795
  try {
77188
- const logPath = (0, import_path85.join)(projectRoot, PREMISE_VERIFICATION_LOG);
77796
+ const logPath = (0, import_path86.join)(projectRoot, PREMISE_VERIFICATION_LOG);
77189
77797
  rotateIfNeeded2(logPath, MAX_PREMISE_VERIFICATION_BYTES);
77190
- (0, import_fs78.mkdirSync)((0, import_path85.join)(projectRoot, ".gossip"), { recursive: true });
77798
+ (0, import_fs79.mkdirSync)((0, import_path86.join)(projectRoot, ".gossip"), { recursive: true });
77191
77799
  const row = {
77192
77800
  ts: (/* @__PURE__ */ new Date()).toISOString(),
77193
77801
  consensus_id: null,
@@ -77201,7 +77809,7 @@ function writePremiseVerificationLog(projectRoot, taskId, result, opts) {
77201
77809
  skill_bound: opts.skill_bound
77202
77810
  };
77203
77811
  if (opts.schema_lint) row.schema_lint = opts.schema_lint;
77204
- (0, import_fs78.appendFileSync)(logPath, JSON.stringify(row) + "\n");
77812
+ (0, import_fs79.appendFileSync)(logPath, JSON.stringify(row) + "\n");
77205
77813
  } catch {
77206
77814
  }
77207
77815
  }
@@ -77313,7 +77921,7 @@ var AGENT_PROVIDER_MAP = {
77313
77921
  };
77314
77922
  function readQuotaState() {
77315
77923
  try {
77316
- const raw = (0, import_fs78.readFileSync)((0, import_path85.join)(process.cwd(), ".gossip", "quota-state.json"), "utf8");
77924
+ const raw = (0, import_fs79.readFileSync)((0, import_path86.join)(process.cwd(), ".gossip", "quota-state.json"), "utf8");
77317
77925
  return JSON.parse(raw);
77318
77926
  } catch {
77319
77927
  return {};
@@ -77379,6 +77987,19 @@ async function handleDispatchSingle(agent_id, task, write_mode, scope, timeout_m
77379
77987
  const relayToken = (0, import_crypto34.randomUUID)().slice(0, 12);
77380
77988
  const timeoutMs = timeout_ms ?? NATIVE_TASK_TTL_MS;
77381
77989
  stashDispatchWarnings([taskId], dispatchWarnings);
77990
+ runDispatchPreconditionGuard({
77991
+ projectRoot: process.cwd(),
77992
+ taskId,
77993
+ resolutionRoots,
77994
+ taskText: task,
77995
+ writeMode: write_mode
77996
+ }).then(({ warnings: precondWarnings }) => {
77997
+ for (const w of precondWarnings) {
77998
+ process.stderr.write(`[gossipcat] \u26A0\uFE0F precondition: ${w}
77999
+ `);
78000
+ }
78001
+ }).catch(() => {
78002
+ });
77382
78003
  const premiseResult = await maybeVerifyPremiseClaims(task, process.cwd(), taskId, agent_id);
77383
78004
  task = premiseResult.annotatedTask;
77384
78005
  if (premiseResult.signals.length > 0) {
@@ -77796,6 +78417,24 @@ Task: ${def.task}`;
77796
78417
  }
77797
78418
  }
77798
78419
  stashDispatchWarnings(allParallelTaskIds, dispatchWarnings);
78420
+ if (allParallelTaskIds.length > 0) {
78421
+ runDispatchPreconditionGuard({
78422
+ projectRoot: process.cwd(),
78423
+ taskId: allParallelTaskIds[0],
78424
+ resolutionRoots: effectiveResolutionRoots,
78425
+ taskText: taskDefs[0]?.task ?? "",
78426
+ writeMode: taskDefs[0]?.write_mode,
78427
+ // Bug A follow-up (Fix 1): scan ALL tasks for referenced paths, not just
78428
+ // taskDefs[0]. Stale-base/mid-flight stay one-per-dispatch above.
78429
+ additionalTasks: taskDefs.slice(1).map((d) => ({ taskText: d.task ?? "", writeMode: d.write_mode }))
78430
+ }).then(({ warnings: precondWarnings }) => {
78431
+ for (const w of precondWarnings) {
78432
+ process.stderr.write(`[gossipcat] \u26A0\uFE0F precondition: ${w}
78433
+ `);
78434
+ }
78435
+ }).catch(() => {
78436
+ });
78437
+ }
77799
78438
  const parallelHost = detectNativeHost();
77800
78439
  let msg = "";
77801
78440
  if (nativeInstructions.length > 0) {
@@ -77874,8 +78513,8 @@ async function handleDispatchConsensus(taskDefs, _utility_task_id, dispatchResol
77874
78513
  });
77875
78514
  const lenses = await Promise.race([
77876
78515
  lensPromise,
77877
- new Promise((resolve32) => {
77878
- timerId = setTimeout(() => resolve32(null), LENS_TIMEOUT_MS);
78516
+ new Promise((resolve33) => {
78517
+ timerId = setTimeout(() => resolve33(null), LENS_TIMEOUT_MS);
77879
78518
  })
77880
78519
  ]);
77881
78520
  if (timerId) clearTimeout(timerId);
@@ -78031,6 +78670,24 @@ Task: ${def.task}`;
78031
78670
  }
78032
78671
  }
78033
78672
  stashDispatchWarnings(allTaskIds, dispatchRoundWarnings);
78673
+ if (allTaskIds.length > 0) {
78674
+ runDispatchPreconditionGuard({
78675
+ projectRoot: process.cwd(),
78676
+ taskId: allTaskIds[0],
78677
+ resolutionRoots: dispatchResolutionRoots,
78678
+ taskText: taskDefs[0]?.task ?? "",
78679
+ writeMode: taskDefs[0]?.write_mode,
78680
+ // Bug A follow-up (Fix 1): scan ALL tasks for referenced paths, not just
78681
+ // taskDefs[0]. Stale-base/mid-flight stay one-per-dispatch above.
78682
+ additionalTasks: taskDefs.slice(1).map((d) => ({ taskText: d.task ?? "", writeMode: d.write_mode }))
78683
+ }).then(({ warnings: precondWarnings }) => {
78684
+ for (const w of precondWarnings) {
78685
+ process.stderr.write(`[gossipcat] \u26A0\uFE0F precondition: ${w}
78686
+ `);
78687
+ }
78688
+ }).catch(() => {
78689
+ });
78690
+ }
78034
78691
  const consensusHost = detectNativeHost();
78035
78692
  const nativeTool = nativeToolName(consensusHost);
78036
78693
  const collectCall = `gossip_collect(task_ids: [${allTaskIds.map((id) => `"${id}"`).join(", ")}], consensus: true)`;
@@ -78080,6 +78737,70 @@ ${p.prompt}` });
78080
78737
  return dispatchWarnings.length > 0 ? { content, warnings: dispatchWarnings } : { content };
78081
78738
  }
78082
78739
 
78740
+ // apps/cli/src/handlers/ask-back.ts
78741
+ var import_fs81 = require("fs");
78742
+ var import_path87 = require("path");
78743
+ var LEDGER_REL = (0, import_path87.join)(".gossip", "fabrication-introspections.jsonl");
78744
+ var MAX_INTROSPECTION_BYTES = 5 * 1024 * 1024;
78745
+ function ledgerPath(projectRoot) {
78746
+ return (0, import_path87.join)(projectRoot, LEDGER_REL);
78747
+ }
78748
+ function buildIntrospectionPrompt(claim, groundTruth) {
78749
+ return [
78750
+ "You are being asked to help improve the reliability of this review pipeline.",
78751
+ "",
78752
+ "A prior response from you was identified as a fabrication:",
78753
+ ` Claim made: ${claim}`,
78754
+ ` Ground truth: ${groundTruth}`,
78755
+ "",
78756
+ "Please reflect on the specific process failure that led to this.",
78757
+ "Do not apologize \u2014 instead, name the exact mechanism: for example,",
78758
+ '"I pattern-matched the task framing and assumed the identifier existed"',
78759
+ 'or "I cited from memory without opening the file to verify".',
78760
+ "",
78761
+ "Your answer should be one to three sentences describing the HOW and WHY",
78762
+ "of the specific reasoning step that went wrong."
78763
+ ].join("\n");
78764
+ }
78765
+ function appendIntrospection(projectRoot, record2, deps) {
78766
+ if (typeof record2.agentId !== "string" || !record2.agentId || typeof record2.status !== "string" || !record2.status) {
78767
+ return;
78768
+ }
78769
+ if (record2.status === "asked") {
78770
+ if (typeof record2.claim !== "string" || !record2.claim.trim() || typeof record2.groundTruth !== "string" || !record2.groundTruth.trim()) {
78771
+ return;
78772
+ }
78773
+ }
78774
+ const clean = {
78775
+ agentId: record2.agentId,
78776
+ claim: record2.claim,
78777
+ groundTruth: record2.groundTruth,
78778
+ status: record2.status
78779
+ };
78780
+ if (record2.askedAt !== void 0) clean["askedAt"] = record2.askedAt;
78781
+ if (record2.findingId !== void 0) clean["findingId"] = record2.findingId;
78782
+ if (record2.answer !== void 0) clean["answer"] = record2.answer;
78783
+ if (record2.answeredAt !== void 0) clean["answeredAt"] = record2.answeredAt;
78784
+ const line = JSON.stringify(clean) + "\n";
78785
+ const path8 = ledgerPath(projectRoot);
78786
+ try {
78787
+ const fsMkdir = deps?.mkdirSync ?? import_fs81.mkdirSync;
78788
+ const fsAppend = deps?.appendFileSync ?? import_fs81.appendFileSync;
78789
+ const fsStat = deps?.statSync ?? import_fs81.statSync;
78790
+ const fsRename = deps?.renameSync ?? import_fs81.renameSync;
78791
+ fsMkdir((0, import_path87.join)(projectRoot, ".gossip"), { recursive: true });
78792
+ try {
78793
+ const st = fsStat(path8);
78794
+ if (st.size >= MAX_INTROSPECTION_BYTES) {
78795
+ fsRename(path8, path8 + ".1");
78796
+ }
78797
+ } catch {
78798
+ }
78799
+ fsAppend(path8, line);
78800
+ } catch {
78801
+ }
78802
+ }
78803
+
78083
78804
  // apps/cli/src/mcp-server-sdk.ts
78084
78805
  init_dispatch_prompt_cache();
78085
78806
 
@@ -78120,6 +78841,7 @@ function discoverVerifier(agents, override) {
78120
78841
  init_src4();
78121
78842
  var import_node_fs = require("node:fs");
78122
78843
  var import_node_path = require("node:path");
78844
+ init_orchestrator_precondition_runner();
78123
78845
  function scheduleSkillRunner(c, mainAgent) {
78124
78846
  if (!c.skillEngine) return;
78125
78847
  const skillEngine = c.skillEngine;
@@ -78263,7 +78985,7 @@ Relay may be down. Check gossip_status() for connection state.` }] };
78263
78985
  process.stderr.write(`[gossipcat] \u23F3 Consensus: ${doneCount}/${pendingNativeIds.length} agents complete (${agentStatus})
78264
78986
  `);
78265
78987
  }
78266
- await new Promise((resolve32) => setTimeout(resolve32, POLL_INTERVAL));
78988
+ await new Promise((resolve33) => setTimeout(resolve33, POLL_INTERVAL));
78267
78989
  }
78268
78990
  const arrived = pendingNativeIds.filter((id) => ctx.nativeResultMap.has(id)).length;
78269
78991
  const timedOutCount = pendingNativeIds.filter((id) => {
@@ -78645,6 +79367,7 @@ ${t.skillWarnings.map((w) => ` - ${w}`).join("\n")}`;
78645
79367
  relayCrossReviewSkipped
78646
79368
  );
78647
79369
  } else {
79370
+ const roundStartSha = captureHeadSha(process.cwd());
78648
79371
  ctx.pendingConsensusRounds.set(consensusId, {
78649
79372
  consensusId,
78650
79373
  allResults: allResults.filter((r) => r.status === "completed"),
@@ -78668,7 +79391,12 @@ ${t.skillWarnings.map((w) => ` - ${w}`).join("\n")}`;
78668
79391
  // warnings + read its roots. The flat resolutionRoots above stays
78669
79392
  // populated in parallel for old-reader back-compat. PR-C: this is
78670
79393
  // always a concrete RoundContext (the engine now requires one).
78671
- roundContext: effectiveRound
79394
+ roundContext: effectiveRound,
79395
+ // UNIT 3: capture HEAD SHA at Phase 2 start for mid_flight_fixup detection.
79396
+ // Best-effort — undefined when git is unavailable (never blocks the round).
79397
+ // FIX 2: hoisted out of the set() literal so execFileSync does not block
79398
+ // the MCP handler inline inside the Map mutation.
79399
+ roundStartSha
78672
79400
  });
78673
79401
  const recentTaskIds = [
78674
79402
  ...allResults.filter((r) => r.status === "completed").map((r) => r.id)
@@ -78855,7 +79583,7 @@ ${np.user}
78855
79583
  const autoResolveEnabled = cfgPathAr?.consensus?.autoResolveOnRoundClose !== false;
78856
79584
  if (autoResolveEnabled) {
78857
79585
  const { resolveFindings: rf } = await Promise.resolve().then(() => (init_src4(), src_exports3));
78858
- const resolveResult = await rf(process.cwd(), { lineAnchored: cfgPathAr?.consensus?.resolverLineAnchored ?? false });
79586
+ const resolveResult = await rf(process.cwd(), { lineAnchored: cfgPathAr?.consensus?.resolverLineAnchored ?? true });
78859
79587
  if (resolveResult.ok) {
78860
79588
  if (resolveResult.resolved > 0) {
78861
79589
  process.stderr.write(
@@ -79158,19 +79886,19 @@ function filterWatchEvents(rawJsonl, opts) {
79158
79886
  }
79159
79887
 
79160
79888
  // apps/cli/src/stickyPort.ts
79161
- var import_fs82 = require("fs");
79162
- var import_path88 = require("path");
79889
+ var import_fs84 = require("fs");
79890
+ var import_path90 = require("path");
79163
79891
  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");
79892
+ var RELAY_STICKY_FILE = (0, import_path90.join)(".gossip", "relay.port");
79893
+ var HTTP_MCP_STICKY_FILE = (0, import_path90.join)(".gossip", "http-mcp.port");
79166
79894
  function stickyPath(filename) {
79167
- return (0, import_path88.join)(process.cwd(), filename);
79895
+ return (0, import_path90.join)(process.cwd(), filename);
79168
79896
  }
79169
79897
  function readStickyPort(filename) {
79170
79898
  const p = stickyPath(filename);
79171
- if (!(0, import_fs82.existsSync)(p)) return null;
79899
+ if (!(0, import_fs84.existsSync)(p)) return null;
79172
79900
  try {
79173
- const raw = (0, import_fs82.readFileSync)(p, "utf-8").trim();
79901
+ const raw = (0, import_fs84.readFileSync)(p, "utf-8").trim();
79174
79902
  const n = parseInt(raw, 10);
79175
79903
  if (!Number.isFinite(n) || n < 1 || n > 65535) return null;
79176
79904
  return n;
@@ -79182,13 +79910,13 @@ function writeStickyPort(filename, port) {
79182
79910
  if (!Number.isFinite(port) || port < 1 || port > 65535) return;
79183
79911
  const p = stickyPath(filename);
79184
79912
  try {
79185
- (0, import_fs82.mkdirSync)((0, import_path88.dirname)(p), { recursive: true });
79186
- (0, import_fs82.writeFileSync)(p, String(port), "utf-8");
79913
+ (0, import_fs84.mkdirSync)((0, import_path90.dirname)(p), { recursive: true });
79914
+ (0, import_fs84.writeFileSync)(p, String(port), "utf-8");
79187
79915
  } catch {
79188
79916
  }
79189
79917
  }
79190
79918
  function probePort(port, host = "127.0.0.1") {
79191
- return new Promise((resolve32) => {
79919
+ return new Promise((resolve33) => {
79192
79920
  const srv = (0, import_net.createServer)();
79193
79921
  let settled = false;
79194
79922
  const done = (ok) => {
@@ -79198,7 +79926,7 @@ function probePort(port, host = "127.0.0.1") {
79198
79926
  srv.close();
79199
79927
  } catch {
79200
79928
  }
79201
- resolve32(ok);
79929
+ resolve33(ok);
79202
79930
  };
79203
79931
  srv.once("error", () => done(false));
79204
79932
  try {
@@ -79256,20 +79984,20 @@ function mergeSetupConfig(input) {
79256
79984
  function buildMalformedConfigHint(configPath, message) {
79257
79985
  return `\u26A0\uFE0F config.json is malformed: ${message} \u2014 fix or delete ${configPath}`;
79258
79986
  }
79259
- function flushStagedAgentFileWrites(writes, fs6) {
79987
+ function flushStagedAgentFileWrites(writes, fs7) {
79260
79988
  for (const w of writes) {
79261
- fs6.mkdirSync(w.dir, { recursive: true });
79262
- fs6.writeFileSync(w.path, w.content, "utf-8");
79989
+ fs7.mkdirSync(w.dir, { recursive: true });
79990
+ fs7.writeFileSync(w.path, w.content, "utf-8");
79263
79991
  }
79264
79992
  }
79265
79993
 
79266
79994
  // apps/cli/src/native-agent-cache.ts
79267
- var import_fs83 = require("fs");
79268
- var import_path89 = require("path");
79995
+ var import_fs85 = require("fs");
79996
+ var import_path91 = require("path");
79269
79997
  var realFs = {
79270
- existsSync: import_fs83.existsSync,
79271
- readFileSync: import_fs83.readFileSync,
79272
- statSync: (p) => ({ mtimeMs: (0, import_fs83.statSync)(p).mtimeMs })
79998
+ existsSync: import_fs85.existsSync,
79999
+ readFileSync: import_fs85.readFileSync,
80000
+ statSync: (p) => ({ mtimeMs: (0, import_fs85.statSync)(p).mtimeMs })
79273
80001
  };
79274
80002
  function modelTierFromId(modelId) {
79275
80003
  if (modelId.includes("opus")) return "opus";
@@ -79277,16 +80005,16 @@ function modelTierFromId(modelId) {
79277
80005
  if (modelId.includes("fable")) return "fable";
79278
80006
  return "sonnet";
79279
80007
  }
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");
80008
+ function refreshNativeAgentFromDisk(ac, cache3, projectRoot, fs7 = realFs) {
80009
+ const claudeAgentPath = (0, import_path91.join)(projectRoot, ".claude", "agents", `${ac.id}.md`);
80010
+ const instrPath = (0, import_path91.join)(projectRoot, ".gossip", "agents", ac.id, "instructions.md");
79283
80011
  const prev = cache3.get(ac.id);
79284
80012
  let sourcePath = null;
79285
80013
  let stripFrontmatter = false;
79286
- if (fs6.existsSync(claudeAgentPath)) {
80014
+ if (fs7.existsSync(claudeAgentPath)) {
79287
80015
  sourcePath = claudeAgentPath;
79288
80016
  stripFrontmatter = true;
79289
- } else if (fs6.existsSync(instrPath)) {
80017
+ } else if (fs7.existsSync(instrPath)) {
79290
80018
  sourcePath = instrPath;
79291
80019
  stripFrontmatter = false;
79292
80020
  }
@@ -79305,7 +80033,7 @@ function refreshNativeAgentFromDisk(ac, cache3, projectRoot, fs6 = realFs) {
79305
80033
  }
79306
80034
  let currentMtimeMs;
79307
80035
  try {
79308
- currentMtimeMs = fs6.statSync(sourcePath).mtimeMs;
80036
+ currentMtimeMs = fs7.statSync(sourcePath).mtimeMs;
79309
80037
  } catch {
79310
80038
  if (prev && prev.instructions.length > 0) {
79311
80039
  return;
@@ -79321,7 +80049,7 @@ function refreshNativeAgentFromDisk(ac, cache3, projectRoot, fs6 = realFs) {
79321
80049
  if (prev && prev.cachedMtimeMs === currentMtimeMs) {
79322
80050
  return;
79323
80051
  }
79324
- let instructions = fs6.readFileSync(sourcePath, "utf-8");
80052
+ let instructions = fs7.readFileSync(sourcePath, "utf-8");
79325
80053
  if (stripFrontmatter) {
79326
80054
  instructions = instructions.replace(/^---\n[\s\S]*?\n---\n*/, "").trim();
79327
80055
  }
@@ -79338,22 +80066,22 @@ function refreshNativeAgentFromDisk(ac, cache3, projectRoot, fs6 = realFs) {
79338
80066
  }
79339
80067
 
79340
80068
  // apps/cli/src/rules-content.ts
79341
- var import_fs84 = require("fs");
79342
- var import_path90 = require("path");
80069
+ var import_fs86 = require("fs");
80070
+ var import_path92 = require("path");
79343
80071
  var AGENT_LIST_PLACEHOLDER = "{{AGENT_LIST}}";
79344
80072
  function resolveRulesPath(host = detectNativeHost()) {
79345
80073
  const fileName = host === "cursor" ? "CURSOR_RULES.md" : "RULES.md";
79346
80074
  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),
80075
+ (0, import_path92.join)(process.cwd(), "docs", fileName),
80076
+ (0, import_path92.join)(__dirname, "..", "docs", fileName),
80077
+ (0, import_path92.join)(__dirname, "docs", fileName),
79350
80078
  // Fallback: bundled RULES.md when CURSOR_RULES.md not yet shipped
79351
80079
  ...host === "cursor" ? [
79352
- (0, import_path90.join)(process.cwd(), "docs", "RULES.md"),
79353
- (0, import_path90.join)(__dirname, "..", "docs", "RULES.md")
80080
+ (0, import_path92.join)(process.cwd(), "docs", "RULES.md"),
80081
+ (0, import_path92.join)(__dirname, "..", "docs", "RULES.md")
79354
80082
  ] : []
79355
80083
  ];
79356
- return candidates.find((p) => (0, import_fs84.existsSync)(p)) ?? null;
80084
+ return candidates.find((p) => (0, import_fs86.existsSync)(p)) ?? null;
79357
80085
  }
79358
80086
  function generateRulesContent(agentList, host) {
79359
80087
  const resolvedHost = host ?? detectNativeHost();
@@ -79363,7 +80091,7 @@ function generateRulesContent(agentList, host) {
79363
80091
  `[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
80092
  );
79365
80093
  }
79366
- let template = (0, import_fs84.readFileSync)(rulesPath, "utf-8");
80094
+ let template = (0, import_fs86.readFileSync)(rulesPath, "utf-8");
79367
80095
  if (resolvedHost === "cursor" && rulesPath.endsWith("RULES.md")) {
79368
80096
  template = template.replace(/Agent\(\)/g, "Task()").replace(/Agent\(/g, "Task(").replace(/Claude Code/g, "Cursor");
79369
80097
  }
@@ -79463,7 +80191,7 @@ var __argvShimHandled = (() => {
79463
80191
  }
79464
80192
  if (kind === "help") {
79465
80193
  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"
80194
+ "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
80195
  );
79468
80196
  process.exit(0);
79469
80197
  }
@@ -79511,15 +80239,15 @@ var __argvShimHandled = (() => {
79511
80239
  function readSecretFromStdin() {
79512
80240
  const stdin = process.stdin;
79513
80241
  if (!stdin.isTTY) {
79514
- return new Promise((resolve32, reject) => {
80242
+ return new Promise((resolve33, reject) => {
79515
80243
  const chunks = [];
79516
80244
  stdin.on("data", (c) => chunks.push(c));
79517
- stdin.on("end", () => resolve32(Buffer.concat(chunks).toString("utf8")));
80245
+ stdin.on("end", () => resolve33(Buffer.concat(chunks).toString("utf8")));
79518
80246
  stdin.on("error", (e) => reject(e));
79519
80247
  stdin.resume();
79520
80248
  });
79521
80249
  }
79522
- return new Promise((resolve32) => {
80250
+ return new Promise((resolve33) => {
79523
80251
  process.stderr.write("Paste the API key, then Enter: ");
79524
80252
  let buf = "";
79525
80253
  const wasRaw = stdin.isRaw === true;
@@ -79534,7 +80262,7 @@ function readSecretFromStdin() {
79534
80262
  stdin.pause();
79535
80263
  stdin.removeListener("data", onData);
79536
80264
  process.stderr.write("\n");
79537
- resolve32(buf);
80265
+ resolve33(buf);
79538
80266
  return;
79539
80267
  } else if (code === 3) {
79540
80268
  stdin.setRawMode(wasRaw);
@@ -79553,12 +80281,12 @@ function readSecretFromStdin() {
79553
80281
  });
79554
80282
  }
79555
80283
  if (process.env.GOSSIPCAT_MCP_NO_MAIN !== "1" && !__argvShimHandled) {
79556
- const gossipDir = (0, import_path95.join)(process.cwd(), ".gossip");
80284
+ const gossipDir = (0, import_path97.join)(process.cwd(), ".gossip");
79557
80285
  try {
79558
- (0, import_fs89.mkdirSync)(gossipDir, { recursive: true });
80286
+ (0, import_fs91.mkdirSync)(gossipDir, { recursive: true });
79559
80287
  } catch {
79560
80288
  }
79561
- const logStream = (0, import_fs89.createWriteStream)((0, import_path95.join)(gossipDir, "mcp.log"), { flags: "a", mode: 384 });
80289
+ const logStream = (0, import_fs91.createWriteStream)((0, import_path97.join)(gossipDir, "mcp.log"), { flags: "a", mode: 384 });
79562
80290
  process.stderr.write = ((chunk, ...args) => {
79563
80291
  return logStream.write(chunk, ...args);
79564
80292
  });
@@ -79569,7 +80297,7 @@ try {
79569
80297
  } catch {
79570
80298
  }
79571
80299
  function memoryDirForProject(cwd) {
79572
- return (0, import_path95.join)((0, import_os8.homedir)(), ".claude", "projects", cwd.replaceAll("/", "-"), "memory");
80300
+ return (0, import_path97.join)((0, import_os8.homedir)(), ".claude", "projects", cwd.replaceAll("/", "-"), "memory");
79573
80301
  }
79574
80302
  function dashboardClickableUrl(url2, key) {
79575
80303
  if (!key) return url2;
@@ -79644,14 +80372,14 @@ var _pendingPlanData = /* @__PURE__ */ new Map();
79644
80372
  var _utilityGuardSnapshots = /* @__PURE__ */ new Map();
79645
80373
  var _modules = null;
79646
80374
  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;
80375
+ const { existsSync: existsSync74, readdirSync: readdirSync22, readFileSync: readFileSync70 } = require("fs");
80376
+ const { join: join93 } = require("path");
80377
+ const reportsDir = join93(projectRoot, ".gossip", "consensus-reports");
80378
+ if (!existsSync74(reportsDir)) return null;
79651
80379
  try {
79652
80380
  const files = readdirSync22(reportsDir).filter((f) => f.endsWith(".json"));
79653
80381
  for (const file2 of files) {
79654
- const report = JSON.parse(readFileSync69(join91(reportsDir, file2), "utf-8"));
80382
+ const report = JSON.parse(readFileSync70(join93(reportsDir, file2), "utf-8"));
79655
80383
  for (const bucket of ["confirmed", "disputed", "unverified", "unique"]) {
79656
80384
  for (const finding of report[bucket] || []) {
79657
80385
  if (finding.id === findingId && finding.severity) {
@@ -79750,7 +80478,7 @@ async function doBoot() {
79750
80478
  const agentConfigs = m.configToAgentConfigs(config2);
79751
80479
  ctx.keychain = new m.Keychain();
79752
80480
  const { existsSync: pidExists, readFileSync: readPid, writeFileSync: writePid, unlinkSync: delPid } = require("fs");
79753
- const pidFile = (0, import_path95.join)(process.cwd(), ".gossip", "relay.pid");
80481
+ const pidFile = (0, import_path97.join)(process.cwd(), ".gossip", "relay.pid");
79754
80482
  if (pidExists(pidFile)) {
79755
80483
  const oldPid = parseInt(readPid(pidFile, "utf-8").trim(), 10);
79756
80484
  if (!isNaN(oldPid) && oldPid !== process.pid) {
@@ -79872,10 +80600,10 @@ async function doBoot() {
79872
80600
  { id: ac.id, provider: ac.provider, model: ac.model, base_url: ac.base_url, key_ref: ac.key_ref },
79873
80601
  (s) => ctx.keychain.getKey(s)
79874
80602
  );
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") : "";
80603
+ const { existsSync: existsSync74, readFileSync: readFileSync70 } = require("fs");
80604
+ const { join: join93 } = require("path");
80605
+ const instructionsPath = join93(process.cwd(), ".gossip", "agents", ac.id, "instructions.md");
80606
+ const baseInstructions = existsSync74(instructionsPath) ? readFileSync70(instructionsPath, "utf-8") : "";
79879
80607
  const identity = ctx.identityRegistry.get(ac.id);
79880
80608
  const identityBlock = identity ? m.formatIdentityBlock(identity) + "\n" : "";
79881
80609
  const instructions = (identityBlock + baseInstructions).trim() || void 0;
@@ -80804,6 +81532,70 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
80804
81532
  };
80805
81533
  }
80806
81534
  );
81535
+ server.tool(
81536
+ "gossip_ask_back",
81537
+ `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.`,
81538
+ {
81539
+ action: external_exports.enum(["ask", "record"]).default("ask").describe(`"ask" (default): dispatch an introspection prompt to the agent. "record": store the agent's answer.`),
81540
+ agent_id: external_exports.string().describe("The agent that produced the fabrication."),
81541
+ claim: external_exports.string().optional().describe('Required for action:"ask". The fabricated claim the agent made.'),
81542
+ ground_truth: external_exports.string().optional().describe('Required for action:"ask". What the code/evidence actually shows.'),
81543
+ finding_id: external_exports.string().optional().describe("Optional consensus finding_id (format: <consensus_id>:<agent:fN>) to link the introspection to a specific finding."),
81544
+ answer: external_exports.string().optional().describe(`Required for action:"record". The agent's root-cause explanation.`)
81545
+ },
81546
+ async ({ action, agent_id, claim, ground_truth, finding_id, answer }) => {
81547
+ const projectRoot = process.cwd();
81548
+ const now = (/* @__PURE__ */ new Date()).toISOString();
81549
+ if (action === "ask") {
81550
+ if (!claim || !ground_truth) {
81551
+ return {
81552
+ content: [{ type: "text", text: 'gossip_ask_back error: action:"ask" requires both claim and ground_truth.' }],
81553
+ isError: true
81554
+ };
81555
+ }
81556
+ appendIntrospection(projectRoot, {
81557
+ agentId: agent_id,
81558
+ findingId: finding_id,
81559
+ claim,
81560
+ groundTruth: ground_truth,
81561
+ status: "asked",
81562
+ askedAt: now
81563
+ });
81564
+ const prompt = buildIntrospectionPrompt(claim, ground_truth);
81565
+ const dispatchResult = await handleDispatchSingle(agent_id, prompt);
81566
+ 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.
81567
+
81568
+ `;
81569
+ const dispatchText = dispatchResult.content.filter((c) => c.type === "text").map((c) => c.text).join("\n");
81570
+ return {
81571
+ content: [{ type: "text", text: instruction + dispatchText }]
81572
+ };
81573
+ }
81574
+ if (!answer) {
81575
+ return {
81576
+ content: [{ type: "text", text: 'gossip_ask_back error: action:"record" requires answer.' }],
81577
+ isError: true
81578
+ };
81579
+ }
81580
+ appendIntrospection(projectRoot, {
81581
+ agentId: agent_id,
81582
+ findingId: finding_id,
81583
+ claim: claim ?? "",
81584
+ groundTruth: ground_truth ?? "",
81585
+ answer,
81586
+ status: "answered",
81587
+ answeredAt: now
81588
+ });
81589
+ const ledgerPath2 = `${projectRoot}/.gossip/fabrication-introspections.jsonl`;
81590
+ return {
81591
+ content: [{
81592
+ type: "text",
81593
+ text: `Introspection recorded for ${agent_id}${finding_id ? ` (finding: ${finding_id})` : ""}.
81594
+ Ledger: ${ledgerPath2}`
81595
+ }]
81596
+ };
81597
+ }
81598
+ );
80807
81599
  server.tool(
80808
81600
  "gossip_status",
80809
81601
  "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 +81653,7 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
80861
81653
  }
80862
81654
  try {
80863
81655
  const { readFileSync: rfHealth } = await import("fs");
80864
- const healthPath = (0, import_path95.join)(process.cwd(), ".gossip", "skill-runner-health.json");
81656
+ const healthPath = (0, import_path97.join)(process.cwd(), ".gossip", "skill-runner-health.json");
80865
81657
  const raw = rfHealth(healthPath, "utf8");
80866
81658
  const h = JSON.parse(raw);
80867
81659
  const lastMs = h.last_run_at ? new Date(h.last_run_at).getTime() : NaN;
@@ -80877,9 +81669,9 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
80877
81669
  lines.push(" Skill graduation: never run since session start (expected after first gossip_collect)");
80878
81670
  }
80879
81671
  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");
81672
+ const { readFileSync: readFileSync70 } = await import("fs");
81673
+ const quotaPath = (0, import_path97.join)(process.cwd(), ".gossip", "quota-state.json");
81674
+ const quotaRaw = readFileSync70(quotaPath, "utf8");
80883
81675
  const quotaState = JSON.parse(quotaRaw);
80884
81676
  for (const [provider, state] of Object.entries(quotaState)) {
80885
81677
  const now = Date.now();
@@ -80931,7 +81723,7 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
80931
81723
  }
80932
81724
  try {
80933
81725
  const { existsSync: hookExists } = await import("fs");
80934
- const hookScriptPath = (0, import_path95.join)(process.cwd(), ".claude", "hooks", "worktree-sandbox.sh");
81726
+ const hookScriptPath = (0, import_path97.join)(process.cwd(), ".claude", "hooks", "worktree-sandbox.sh");
80935
81727
  const { isWorktreeSandboxHookRegistered: isWorktreeSandboxHookRegistered2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
80936
81728
  if (hookExists(hookScriptPath) && !isWorktreeSandboxHookRegistered2(process.cwd())) {
80937
81729
  lines.push(" \u26A0\uFE0F Sandbox: worktree-sandbox hook installed but UNREGISTERED \u2014 run gossip_setup to re-register");
@@ -80939,21 +81731,21 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
80939
81731
  } catch {
80940
81732
  }
80941
81733
  try {
80942
- const { readdirSync: readdirSync22, statSync: statSync36, readFileSync: readFileSync69 } = await import("fs");
81734
+ const { readdirSync: readdirSync22, statSync: statSync36, readFileSync: readFileSync70 } = await import("fs");
80943
81735
  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");
81736
+ const reportsDir = (0, import_path97.join)(process.cwd(), ".gossip", "consensus-reports");
81737
+ const perfPath = (0, import_path97.join)(process.cwd(), ".gossip", "agent-performance.jsonl");
80946
81738
  const WINDOW_MS3 = 24 * 60 * 60 * 1e3;
80947
81739
  const now = Date.now();
80948
81740
  const recentReports = [];
80949
81741
  try {
80950
81742
  for (const fname of readdirSync22(reportsDir)) {
80951
81743
  if (!fname.endsWith(".json")) continue;
80952
- const fpath = (0, import_path95.join)(reportsDir, fname);
81744
+ const fpath = (0, import_path97.join)(reportsDir, fname);
80953
81745
  const st = statSync36(fpath);
80954
81746
  if (now - st.mtimeMs > WINDOW_MS3) continue;
80955
81747
  try {
80956
- const report = JSON.parse(readFileSync69(fpath, "utf8"));
81748
+ const report = JSON.parse(readFileSync70(fpath, "utf8"));
80957
81749
  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
81750
  if (isEmpty) continue;
80959
81751
  } catch {
@@ -81327,8 +82119,8 @@ ${body}`
81327
82119
  }
81328
82120
  return { content: [{ type: "text", text: results.join("\n") }] };
81329
82121
  }
81330
- const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45, existsSync: existsSync73 } = require("fs");
81331
- const { join: join91 } = require("path");
82122
+ const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45, existsSync: existsSync74 } = require("fs");
82123
+ const { join: join93 } = require("path");
81332
82124
  const root = process.cwd();
81333
82125
  const CLAUDE_MODEL_MAP2 = {
81334
82126
  opus: { provider: "anthropic", model: "claude-opus-4-6" },
@@ -81344,8 +82136,8 @@ ${body}`
81344
82136
  let existingConfig = {};
81345
82137
  let existingAgents = {};
81346
82138
  try {
81347
- const { readFileSync: readFileSync69 } = require("fs");
81348
- const existing = JSON.parse(readFileSync69(join91(root, ".gossip", "config.json"), "utf-8"));
82139
+ const { readFileSync: readFileSync70 } = require("fs");
82140
+ const existing = JSON.parse(readFileSync70(join93(root, ".gossip", "config.json"), "utf-8"));
81349
82141
  if (existing && typeof existing === "object" && !Array.isArray(existing)) {
81350
82142
  existingConfig = existing;
81351
82143
  if (mode === "merge") existingAgents = existing.agents || {};
@@ -81379,8 +82171,8 @@ ${body}`
81379
82171
  body
81380
82172
  ].join("\n");
81381
82173
  pendingAgentFileWrites.push({
81382
- dir: join91(root, ".claude", "agents"),
81383
- path: join91(root, ".claude", "agents", `${agent.id}.md`),
82174
+ dir: join93(root, ".claude", "agents"),
82175
+ path: join93(root, ".claude", "agents", `${agent.id}.md`),
81384
82176
  content: md
81385
82177
  });
81386
82178
  nativeCreated.push(agent.id);
@@ -81401,8 +82193,8 @@ ${body}`
81401
82193
  errors.push(`${agent.id}: custom agent requires "custom_model" field`);
81402
82194
  continue;
81403
82195
  }
81404
- const nativeFile = join91(root, ".claude", "agents", `${agent.id}.md`);
81405
- const wasNative = existingAgents[agent.id]?.native || configAgents[agent.id]?.native || existsSync73(nativeFile);
82196
+ const nativeFile = join93(root, ".claude", "agents", `${agent.id}.md`);
82197
+ const wasNative = existingAgents[agent.id]?.native || configAgents[agent.id]?.native || existsSync74(nativeFile);
81406
82198
  if (wasNative) {
81407
82199
  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
82200
  continue;
@@ -81417,10 +82209,10 @@ ${body}`
81417
82209
  };
81418
82210
  customCreated.push(agent.id);
81419
82211
  if (agent.instructions) {
81420
- const instrDir = join91(root, ".gossip", "agents", agent.id);
82212
+ const instrDir = join93(root, ".gossip", "agents", agent.id);
81421
82213
  pendingAgentFileWrites.push({
81422
82214
  dir: instrDir,
81423
- path: join91(instrDir, "instructions.md"),
82215
+ path: join93(instrDir, "instructions.md"),
81424
82216
  content: agent.instructions
81425
82217
  });
81426
82218
  }
@@ -81439,8 +82231,8 @@ ${body}`
81439
82231
  return { content: [{ type: "text", text: `Invalid config: ${err.message}` }] };
81440
82232
  }
81441
82233
  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));
82234
+ mkdirSync45(join93(root, ".gossip"), { recursive: true });
82235
+ writeFileSync38(join93(root, ".gossip", "config.json"), JSON.stringify(config2, null, 2));
81444
82236
  let hookSummary = "";
81445
82237
  try {
81446
82238
  const { installWorktreeSandboxHook: installWorktreeSandboxHook2, writeOrchestratorRoleMarker: writeOrchestratorRoleMarker2 } = (init_src4(), __toCommonJS(src_exports3));
@@ -81543,8 +82335,8 @@ ${body}`
81543
82335
  }
81544
82336
  }
81545
82337
  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);
82338
+ const rulesDir = join93(root, env.rulesDir);
82339
+ const rulesFile = join93(root, env.rulesFile);
81548
82340
  mkdirSync45(rulesDir, { recursive: true });
81549
82341
  writeFileSync38(rulesFile, generateRulesContent(
81550
82342
  agentList,
@@ -81853,11 +82645,11 @@ The original signal remains in the audit log but will be excluded from scoring.`
81853
82645
  const fid = finding_id.trim();
81854
82646
  const cwd = process.cwd();
81855
82647
  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)) {
82648
+ const { readFileSync: readFileSync70, existsSync: existsSync74, writeFileSync: writeFileSync38, renameSync: renameSync18 } = require("fs");
82649
+ if (!existsSync74(findingsPath)) {
81858
82650
  return { content: [{ type: "text", text: `No implementation-findings.jsonl found at ${findingsPath}` }] };
81859
82651
  }
81860
- const lines = readFileSync69(findingsPath, "utf-8").split("\n");
82652
+ const lines = readFileSync70(findingsPath, "utf-8").split("\n");
81861
82653
  let matched = false;
81862
82654
  let alreadyTarget = false;
81863
82655
  let matchedEntry = null;
@@ -81945,18 +82737,18 @@ The original signal remains in the audit log but will be excluded from scoring.`
81945
82737
  return { content: [{ type: "text", text: "Error: consensus_id is required for bulk_from_consensus." }] };
81946
82738
  }
81947
82739
  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`);
82740
+ const { readFileSync: readFileSync70 } = await import("fs");
82741
+ const { join: join93 } = await import("path");
82742
+ const reportPath = join93(process.cwd(), ".gossip", "consensus-reports", `${consensus_id}.json`);
81951
82743
  let report;
81952
82744
  try {
81953
- report = JSON.parse(readFileSync69(reportPath, "utf-8"));
82745
+ report = JSON.parse(readFileSync70(reportPath, "utf-8"));
81954
82746
  } catch {
81955
82747
  return { content: [{ type: "text", text: `Error: consensus report not found: ${consensus_id}` }] };
81956
82748
  }
81957
82749
  const existingFindingIds = /* @__PURE__ */ new Set();
81958
82750
  try {
81959
- const perfPath = join91(process.cwd(), ".gossip", "agent-performance.jsonl");
82751
+ const perfPath = join93(process.cwd(), ".gossip", "agent-performance.jsonl");
81960
82752
  const { readJsonlWithRotated: readJsonlRotated2570 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
81961
82753
  const lines = readJsonlRotated2570(perfPath).split("\n").filter(Boolean);
81962
82754
  for (const line of lines) {
@@ -82571,7 +83363,7 @@ These will influence future agent selection via dispatch weighting.`;
82571
83363
  return null;
82572
83364
  }
82573
83365
  })();
82574
- const result = await resolveFindings2(process.cwd(), { full, sinceSha, lineAnchored: cfg?.consensus?.resolverLineAnchored ?? false });
83366
+ const result = await resolveFindings2(process.cwd(), { full, sinceSha, lineAnchored: cfg?.consensus?.resolverLineAnchored ?? true });
82575
83367
  if (!result.ok) {
82576
83368
  return { content: [{ type: "text", text: `Resolver skipped: ${result.reason} (another resolver run in progress; try again in a moment).` }] };
82577
83369
  }
@@ -82591,7 +83383,7 @@ These will influence future agent selection via dispatch weighting.`;
82591
83383
  if (nonZeroSkips.length > 0) {
82592
83384
  lines.push(` skipped: ${nonZeroSkips.map(([k, n]) => `${k}=${n}`).join(", ")}`);
82593
83385
  if ((result.skipReasons?.lineAnchoredOff ?? 0) > 0) {
82594
- lines.push(` (lineAnchoredOff: enable consensus.resolverLineAnchored to resolve present-elsewhere findings as stale_anchor)`);
83386
+ 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
83387
  }
82596
83388
  }
82597
83389
  return { content: [{ type: "text", text: lines.join("\n") }] };
@@ -83004,16 +83796,16 @@ ${preview}` }]
83004
83796
  const { SkillGapTracker: SkillGapTracker2, parseSkillFrontmatter: parseSkillFrontmatter2, normalizeSkillName: normalizeSkillName2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
83005
83797
  const tracker = new SkillGapTracker2(process.cwd());
83006
83798
  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");
83799
+ const { writeFileSync: writeFileSync38, mkdirSync: mkdirSync45, existsSync: existsSync74, readFileSync: readFileSync70 } = require("fs");
83800
+ const { join: join93 } = require("path");
83801
+ const dir = join93(process.cwd(), ".gossip", "skills");
83010
83802
  mkdirSync45(dir, { recursive: true });
83011
83803
  const results = [];
83012
83804
  for (const sk of skills) {
83013
83805
  const name = normalizeSkillName2(sk.name);
83014
- const filePath = join91(dir, `${name}.md`);
83015
- if (existsSync73(filePath)) {
83016
- const existing = readFileSync69(filePath, "utf-8");
83806
+ const filePath = join93(dir, `${name}.md`);
83807
+ if (existsSync74(filePath)) {
83808
+ const existing = readFileSync70(filePath, "utf-8");
83017
83809
  const fm = parseSkillFrontmatter2(existing);
83018
83810
  if (fm) {
83019
83811
  if (fm.generated_by === "manual") {
@@ -83737,7 +84529,8 @@ Paste this entire block into any Agent() prompt that should produce parseable fi
83737
84529
  { 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
84530
  { name: "gossip_reload", desc: "Terminate MCP server so Claude Code respawns with fresh bundle. Use after npm run build:mcp." },
83739
84531
  { 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." }
84532
+ { name: "gossip_bug_feedback", desc: "File a GitHub issue on the gossipcat repo from an in-session bug report. Dedupes against open issues." },
84533
+ { 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
84534
  ];
83742
84535
  const list = tools.map((t) => `- ${t.name}: ${t.desc}`).join("\n");
83743
84536
  return { content: [{ type: "text", text: `Gossipcat Tools (${tools.length}):
@@ -83853,9 +84646,9 @@ ${p.user}
83853
84646
  max_events: external_exports.number().int().positive().max(WATCH_MAX_EVENTS).optional().describe(`Cap events returned (default ${WATCH_MAX_EVENTS}).`)
83854
84647
  },
83855
84648
  async ({ cursor, max_events }) => {
83856
- const { join: join91 } = await import("node:path");
84649
+ const { join: join93 } = await import("node:path");
83857
84650
  const { readJsonlWithRotated: readJsonlWithRotated2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
83858
- const perfPath = join91(process.cwd(), ".gossip", "agent-performance.jsonl");
84651
+ const perfPath = join93(process.cwd(), ".gossip", "agent-performance.jsonl");
83859
84652
  const raw = readJsonlWithRotated2(perfPath);
83860
84653
  const result = filterWatchEvents(raw, { cursor, maxEvents: max_events });
83861
84654
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
@@ -84002,10 +84795,10 @@ async function startHttpMcpTransport() {
84002
84795
  }
84003
84796
  let body;
84004
84797
  if (req.method === "POST") {
84005
- const raw = await new Promise((resolve32, reject) => {
84798
+ const raw = await new Promise((resolve33, reject) => {
84006
84799
  const chunks = [];
84007
84800
  req.on("data", (c) => chunks.push(c));
84008
- req.on("end", () => resolve32(Buffer.concat(chunks).toString("utf-8")));
84801
+ req.on("end", () => resolve33(Buffer.concat(chunks).toString("utf-8")));
84009
84802
  req.on("error", reject);
84010
84803
  });
84011
84804
  try {