gossipcat 0.4.30 → 0.5.2

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.
@@ -734,8 +734,8 @@ var init_agent_registry = __esm({
734
734
  setPerformanceReader(reader) {
735
735
  this.perfReader = reader;
736
736
  }
737
- setSuggesterCache(cache2) {
738
- this.suggesterCache = cache2;
737
+ setSuggesterCache(cache3) {
738
+ this.suggesterCache = cache3;
739
739
  }
740
740
  getDispatchWeight(agentId) {
741
741
  if (this.perfReader?.isCircuitOpen(agentId)) return 0.3;
@@ -11407,11 +11407,11 @@ var init_performance_reader = __esm({
11407
11407
  * Returns false on any IO/parse error — recovery defaults to "no relief"
11408
11408
  * when we can't prove a skill is bound.
11409
11409
  */
11410
- hasSkillForCategory(agentId, category, cache2) {
11410
+ hasSkillForCategory(agentId, category, cache3) {
11411
11411
  if (!agentId || !category) return false;
11412
11412
  const normalizedTarget = normalizeSkillName(category);
11413
11413
  const cacheKey = agentId + "\0" + normalizedTarget;
11414
- const cached4 = cache2.get(cacheKey);
11414
+ const cached4 = cache3.get(cacheKey);
11415
11415
  if (cached4 !== void 0) return cached4;
11416
11416
  const indexMap = this.getSkillIndexEnabledMap();
11417
11417
  const agentIndex = indexMap?.[agentId];
@@ -11443,7 +11443,7 @@ var init_performance_reader = __esm({
11443
11443
  }
11444
11444
  } catch {
11445
11445
  }
11446
- cache2.set(cacheKey, result);
11446
+ cache3.set(cacheKey, result);
11447
11447
  return result;
11448
11448
  }
11449
11449
  /**
@@ -12776,9 +12776,9 @@ function deriveAggregateKey(signal, projectRoot, boundAtCache) {
12776
12776
  timestampMs: ts2
12777
12777
  };
12778
12778
  }
12779
- function resolveBoundAtMs(agentId, category, projectRoot, cache2, fallbackMs) {
12779
+ function resolveBoundAtMs(agentId, category, projectRoot, cache3, fallbackMs) {
12780
12780
  const key = agentId + "\0" + category;
12781
- const cached4 = cache2.get(key);
12781
+ const cached4 = cache3.get(key);
12782
12782
  if (cached4 !== void 0) {
12783
12783
  return cached4 === boundAtMissSentinel ? fallbackMs : cached4;
12784
12784
  }
@@ -12787,13 +12787,13 @@ function resolveBoundAtMs(agentId, category, projectRoot, cache2, fallbackMs) {
12787
12787
  if (typeof boundAt === "string" && boundAt.length > 0) {
12788
12788
  const ms = new Date(boundAt).getTime();
12789
12789
  if (isFinite(ms) && ms > 0) {
12790
- cache2.set(key, ms);
12790
+ cache3.set(key, ms);
12791
12791
  return ms;
12792
12792
  }
12793
12793
  }
12794
12794
  } catch {
12795
12795
  }
12796
- cache2.set(key, boundAtMissSentinel);
12796
+ cache3.set(key, boundAtMissSentinel);
12797
12797
  return fallbackMs;
12798
12798
  }
12799
12799
  var import_fs14, import_path15, loggedCounterErrors, MAX_TELEMETRY_BYTES, VALID_CONSENSUS_SIGNALS, VALID_IMPL_SIGNALS, VALID_META_SIGNALS, VALID_PIPELINE_SIGNALS, SYSTEM_SENTINEL_AGENT_ID, rowsWrittenSinceCheck, DRIFT_SAMPLE_INTERVAL, INTERNAL, boundAtMissSentinel, PerformanceWriter;
@@ -17366,9 +17366,9 @@ function getRuntimeFlag(key, defaultValue, registry2 = RUNTIME_FLAG_REGISTRY) {
17366
17366
  if (envVal !== void 0 && envVal !== "") {
17367
17367
  return envVal;
17368
17368
  }
17369
- const cache2 = ensureLoaded(registry2);
17370
- if (Object.prototype.hasOwnProperty.call(cache2, key)) {
17371
- return cache2[key];
17369
+ const cache3 = ensureLoaded(registry2);
17370
+ if (Object.prototype.hasOwnProperty.call(cache3, key)) {
17371
+ return cache3[key];
17372
17372
  }
17373
17373
  if (defaultValue !== void 0) {
17374
17374
  return defaultValue;
@@ -17568,10 +17568,10 @@ async function unsetRuntimeFlag(key, source, reason, registry2 = RUNTIME_FLAG_RE
17568
17568
  }
17569
17569
  }
17570
17570
  function listRuntimeFlags(registry2 = RUNTIME_FLAG_REGISTRY) {
17571
- const cache2 = ensureLoaded(registry2);
17571
+ const cache3 = ensureLoaded(registry2);
17572
17572
  return Object.entries(registry2).map(([key, spec]) => {
17573
17573
  const envVal = process.env[key];
17574
- const fileVal = Object.prototype.hasOwnProperty.call(cache2, key) ? cache2[key] : void 0;
17574
+ const fileVal = Object.prototype.hasOwnProperty.call(cache3, key) ? cache3[key] : void 0;
17575
17575
  let value;
17576
17576
  let from;
17577
17577
  if (envVal !== void 0 && envVal !== "") {
@@ -23823,8 +23823,8 @@ message: Your question?
23823
23823
  }
23824
23824
  /** Start all worker agents (connect to relay) */
23825
23825
  async start() {
23826
- const { existsSync: existsSync69, readFileSync: readFileSync62 } = await import("fs");
23827
- const { join: join82 } = await import("path");
23826
+ const { existsSync: existsSync70, readFileSync: readFileSync64 } = await import("fs");
23827
+ const { join: join83 } = await import("path");
23828
23828
  for (const config2 of this.registry.getAll()) {
23829
23829
  if (config2.native) continue;
23830
23830
  if (this.workers.has(config2.id)) continue;
@@ -23833,8 +23833,8 @@ message: Your question?
23833
23833
  apiKey = await this.keyProviderFn(config2.provider) ?? void 0;
23834
23834
  }
23835
23835
  const llm = createProvider(config2.provider, config2.model, apiKey);
23836
- const instructionsPath = join82(this.projectRoot, ".gossip", "agents", config2.id, "instructions.md");
23837
- const instructions = existsSync69(instructionsPath) ? readFileSync62(instructionsPath, "utf-8") : void 0;
23836
+ const instructionsPath = join83(this.projectRoot, ".gossip", "agents", config2.id, "instructions.md");
23837
+ const instructions = existsSync70(instructionsPath) ? readFileSync64(instructionsPath, "utf-8") : void 0;
23838
23838
  const enableWebSearch = config2.preset === "researcher" || config2.skills.includes("research");
23839
23839
  const worker = new WorkerAgent(config2.id, llm, this.relayUrl, ALL_TOOLS, instructions, enableWebSearch, this.relayApiKey);
23840
23840
  await worker.start();
@@ -24031,8 +24031,8 @@ message: Your question?
24031
24031
  this.registry.register(config2);
24032
24032
  }
24033
24033
  async syncWorkers(keyProvider) {
24034
- const { existsSync: existsSync69, readFileSync: readFileSync62 } = await import("fs");
24035
- const { join: join82 } = await import("path");
24034
+ const { existsSync: existsSync70, readFileSync: readFileSync64 } = await import("fs");
24035
+ const { join: join83 } = await import("path");
24036
24036
  let added = 0;
24037
24037
  for (const ac of this.registry.getAll()) {
24038
24038
  if (ac.native) continue;
@@ -24049,8 +24049,8 @@ message: Your question?
24049
24049
  this.workers.delete(ac.id);
24050
24050
  }
24051
24051
  const llm = createProvider(ac.provider, ac.model, key ?? void 0, void 0, ac.base_url);
24052
- const instructionsPath = join82(this.projectRoot, ".gossip", "agents", ac.id, "instructions.md");
24053
- const instructions = existsSync69(instructionsPath) ? readFileSync62(instructionsPath, "utf-8") : void 0;
24052
+ const instructionsPath = join83(this.projectRoot, ".gossip", "agents", ac.id, "instructions.md");
24053
+ const instructions = existsSync70(instructionsPath) ? readFileSync64(instructionsPath, "utf-8") : void 0;
24054
24054
  const enableWebSearch = ac.preset === "researcher" || ac.skills.includes("research");
24055
24055
  const worker = new WorkerAgent(ac.id, llm, this.relayUrl, ALL_TOOLS, instructions, enableWebSearch, this.relayApiKey);
24056
24056
  await worker.start();
@@ -30051,11 +30051,18 @@ async function overviewHandler(projectRoot, ctx2) {
30051
30051
  const now = Date.now();
30052
30052
  const hourMs = 60 * 60 * 1e3;
30053
30053
  const graphPath = (0, import_path53.join)(projectRoot, ".gossip", "task-graph.jsonl");
30054
- if ((0, import_fs49.existsSync)(graphPath)) {
30054
+ const archivePath = graphPath + ".1";
30055
+ if ((0, import_fs49.existsSync)(graphPath) || (0, import_fs49.existsSync)(archivePath)) {
30055
30056
  try {
30056
30057
  const created = /* @__PURE__ */ new Map();
30057
30058
  const finished = /* @__PURE__ */ new Set();
30058
- const lines = (0, import_fs49.readFileSync)(graphPath, "utf-8").trim().split("\n").filter(Boolean);
30059
+ const lines = [];
30060
+ if ((0, import_fs49.existsSync)(archivePath)) {
30061
+ lines.push(...(0, import_fs49.readFileSync)(archivePath, "utf-8").split("\n").filter(Boolean));
30062
+ }
30063
+ if ((0, import_fs49.existsSync)(graphPath)) {
30064
+ lines.push(...(0, import_fs49.readFileSync)(graphPath, "utf-8").split("\n").filter(Boolean));
30065
+ }
30059
30066
  for (const line of lines) {
30060
30067
  try {
30061
30068
  const ev = JSON.parse(line);
@@ -30332,11 +30339,17 @@ function readForcedDevelops(projectRoot, agentId, category) {
30332
30339
  }
30333
30340
  function readTaskGraphByAgent(projectRoot) {
30334
30341
  const taskGraphPath = (0, import_path55.join)(projectRoot, ".gossip", "task-graph.jsonl");
30342
+ const archivePath = taskGraphPath + ".1";
30335
30343
  const result = /* @__PURE__ */ new Map();
30336
- if (!(0, import_fs51.existsSync)(taskGraphPath)) return result;
30337
- let lines;
30344
+ if (!(0, import_fs51.existsSync)(taskGraphPath) && !(0, import_fs51.existsSync)(archivePath)) return result;
30345
+ let lines = [];
30338
30346
  try {
30339
- lines = (0, import_fs51.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
30347
+ if ((0, import_fs51.existsSync)(archivePath)) {
30348
+ lines.push(...(0, import_fs51.readFileSync)(archivePath, "utf-8").split("\n").filter(Boolean));
30349
+ }
30350
+ if ((0, import_fs51.existsSync)(taskGraphPath)) {
30351
+ lines.push(...(0, import_fs51.readFileSync)(taskGraphPath, "utf-8").split("\n").filter(Boolean));
30352
+ }
30340
30353
  } catch {
30341
30354
  return result;
30342
30355
  }
@@ -30531,12 +30544,206 @@ var init_api_agents = __esm({
30531
30544
  function isCorrupt(projectRoot, index) {
30532
30545
  return (0, import_fs52.existsSync)((0, import_path56.join)(projectRoot, ".gossip", "skill-index.json")) && !index.exists();
30533
30546
  }
30547
+ function readSkillFrontmatter2(projectRoot, agentId, skillName) {
30548
+ try {
30549
+ const path7 = (0, import_path56.join)(projectRoot, ".gossip", "agents", agentId, "skills", `${skillName}.md`);
30550
+ if (!(0, import_fs52.existsSync)(path7)) return null;
30551
+ const raw = (0, import_fs52.readFileSync)(path7, "utf-8");
30552
+ if (!raw.startsWith("---")) return null;
30553
+ const end = raw.indexOf("\n---", 3);
30554
+ if (end === -1) return null;
30555
+ const block = raw.slice(3, end);
30556
+ const out = {};
30557
+ for (const line of block.split("\n")) {
30558
+ const m = line.match(/^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.+?)\s*$/);
30559
+ if (!m) continue;
30560
+ const key = m[1];
30561
+ let value = m[2];
30562
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
30563
+ value = value.slice(1, -1);
30564
+ }
30565
+ if (key === "status") out.status = value;
30566
+ else if (key === "bound_at") out.bound_at = value;
30567
+ else if (key === "passed_baseline_rate") {
30568
+ const n = Number(value);
30569
+ if (Number.isFinite(n)) out.passed_baseline_rate = n;
30570
+ }
30571
+ }
30572
+ return out;
30573
+ } catch {
30574
+ return null;
30575
+ }
30576
+ }
30577
+ function buildSignalIndex(projectRoot) {
30578
+ const idx = { byAgentSkill: /* @__PURE__ */ new Map() };
30579
+ const perfPath = (0, import_path56.join)(projectRoot, ".gossip", "agent-performance.jsonl");
30580
+ if (!(0, import_fs52.existsSync)(perfPath)) return idx;
30581
+ let raw;
30582
+ try {
30583
+ raw = readJsonlWithRotated(perfPath);
30584
+ } catch {
30585
+ return idx;
30586
+ }
30587
+ if (!raw) return idx;
30588
+ const retracted = /* @__PURE__ */ new Set();
30589
+ const retractedConsensusIds = /* @__PURE__ */ new Set();
30590
+ const rows = [];
30591
+ for (const line of raw.split("\n")) {
30592
+ if (!line.trim()) continue;
30593
+ try {
30594
+ rows.push(JSON.parse(line));
30595
+ } catch {
30596
+ }
30597
+ }
30598
+ for (const r of rows) {
30599
+ if (r.signal === "consensus_round_retracted") {
30600
+ const cid = r.consensus_id;
30601
+ if (typeof cid === "string" && cid.length > 0) retractedConsensusIds.add(cid);
30602
+ continue;
30603
+ }
30604
+ if (r.signal === "signal_retracted") {
30605
+ const agentId = r.agentId;
30606
+ const taskKey = r.taskId ?? r.timestamp;
30607
+ const retractedSignal = r.retractedSignal;
30608
+ if (!agentId || !taskKey) continue;
30609
+ if (typeof retractedSignal === "string") {
30610
+ retracted.add(`${agentId}:${taskKey}:${retractedSignal}`);
30611
+ } else {
30612
+ retracted.add(`${agentId}:${taskKey}:*`);
30613
+ }
30614
+ }
30615
+ }
30616
+ for (const r of rows) {
30617
+ if (r.type !== "consensus") continue;
30618
+ const signal = r.signal;
30619
+ if (!signal) continue;
30620
+ if (!CORRECT_SIGNALS.has(signal) && !HALLUC_SIGNALS.has(signal)) continue;
30621
+ const agentId = r.agentId;
30622
+ const category = r.category;
30623
+ const tsStr = r.timestamp;
30624
+ if (!agentId || !category || !tsStr) continue;
30625
+ const ts2 = new Date(tsStr).getTime();
30626
+ if (!Number.isFinite(ts2) || ts2 === 0) continue;
30627
+ const taskKey = r.taskId ?? tsStr;
30628
+ if (retracted.has(`${agentId}:${taskKey}:${signal}`)) continue;
30629
+ if (retracted.has(`${agentId}:${taskKey}:*`)) continue;
30630
+ const findingId = r.findingId;
30631
+ if (typeof findingId === "string") {
30632
+ let drop = false;
30633
+ for (const cid of retractedConsensusIds) {
30634
+ if (findingId.startsWith(cid + ":")) {
30635
+ drop = true;
30636
+ break;
30637
+ }
30638
+ }
30639
+ if (drop) continue;
30640
+ }
30641
+ const skillKey = normalizeSkillName(category);
30642
+ if (!skillKey) continue;
30643
+ let perAgent = idx.byAgentSkill.get(agentId);
30644
+ if (!perAgent) {
30645
+ perAgent = /* @__PURE__ */ new Map();
30646
+ idx.byAgentSkill.set(agentId, perAgent);
30647
+ }
30648
+ let arr = perAgent.get(skillKey);
30649
+ if (!arr) {
30650
+ arr = [];
30651
+ perAgent.set(skillKey, arr);
30652
+ }
30653
+ arr.push({ ts: ts2, signal });
30654
+ }
30655
+ for (const perAgent of idx.byAgentSkill.values()) {
30656
+ for (const arr of perAgent.values()) arr.sort((a, b) => a.ts - b.ts);
30657
+ }
30658
+ return idx;
30659
+ }
30660
+ function deriveEffectiveness(projectRoot, index, signalIdx, nowMs) {
30661
+ const out = [];
30662
+ for (const agentId of index.getAgentIds()) {
30663
+ for (const slot of index.getAgentSlots(agentId)) {
30664
+ if (!slot.enabled) continue;
30665
+ const fm = readSkillFrontmatter2(projectRoot, agentId, slot.skill);
30666
+ const boundAtIso = fm?.bound_at ?? slot.boundAt;
30667
+ const boundAtMs = new Date(boundAtIso).getTime();
30668
+ if (!Number.isFinite(boundAtMs) || boundAtMs <= 0) continue;
30669
+ const windowStartMs = Math.max(boundAtMs, nowMs - WINDOW_MS2);
30670
+ const totalSpan = Math.max(nowMs - windowStartMs, NUM_BUCKETS);
30671
+ const bucketMs = totalSpan / NUM_BUCKETS;
30672
+ const events = signalIdx.byAgentSkill.get(agentId)?.get(normalizeSkillName(slot.skill)) ?? [];
30673
+ const buckets = Array.from(
30674
+ { length: NUM_BUCKETS },
30675
+ () => ({ c: 0, h: 0 })
30676
+ );
30677
+ let n = 0;
30678
+ for (const ev of events) {
30679
+ if (ev.ts < windowStartMs) continue;
30680
+ const rel = ev.ts - windowStartMs;
30681
+ let i = Math.floor(rel / bucketMs);
30682
+ if (i < 0) i = 0;
30683
+ if (i >= NUM_BUCKETS) i = NUM_BUCKETS - 1;
30684
+ if (CORRECT_SIGNALS.has(ev.signal)) buckets[i].c++;
30685
+ else if (HALLUC_SIGNALS.has(ev.signal)) buckets[i].h++;
30686
+ n++;
30687
+ }
30688
+ const curve = buckets.map((b, i) => {
30689
+ const total = b.c + b.h;
30690
+ const t = windowStartMs + (i + 1) * bucketMs;
30691
+ return { t, value: total > 0 ? b.c / total : null };
30692
+ });
30693
+ const threshold = fm?.passed_baseline_rate ?? DEFAULT_THRESHOLD;
30694
+ const status = fm?.status ?? null;
30695
+ out.push({
30696
+ agentId,
30697
+ skill: slot.skill,
30698
+ status,
30699
+ curve,
30700
+ threshold,
30701
+ n,
30702
+ boundAt: boundAtIso
30703
+ });
30704
+ }
30705
+ }
30706
+ return out;
30707
+ }
30708
+ function jsonlMtime(projectRoot) {
30709
+ try {
30710
+ return (0, import_fs52.statSync)((0, import_path56.join)(projectRoot, ".gossip", "agent-performance.jsonl")).mtimeMs;
30711
+ } catch {
30712
+ return 0;
30713
+ }
30714
+ }
30715
+ function cacheHit(projectRoot, nowMs) {
30716
+ const entry = cache2.get(projectRoot);
30717
+ if (!entry) return null;
30718
+ if (nowMs - entry.builtAtMs > CACHE_TTL_MS) return null;
30719
+ if (entry.jsonlMtimeMs !== jsonlMtime(projectRoot)) return null;
30720
+ return entry.payload;
30721
+ }
30534
30722
  async function skillsGetHandler(projectRoot) {
30723
+ const nowMs = Date.now();
30724
+ const cached4 = cacheHit(projectRoot, nowMs);
30725
+ if (cached4) return cached4;
30535
30726
  try {
30536
30727
  const index = new SkillIndex(projectRoot);
30537
- return { index: index.getIndex(), suggestions: [] };
30728
+ let effectiveness = [];
30729
+ try {
30730
+ const signalIdx = buildSignalIndex(projectRoot);
30731
+ effectiveness = deriveEffectiveness(projectRoot, index, signalIdx, nowMs);
30732
+ } catch {
30733
+ }
30734
+ const payload = {
30735
+ index: index.getIndex(),
30736
+ suggestions: [],
30737
+ effectiveness
30738
+ };
30739
+ cache2.set(projectRoot, {
30740
+ payload,
30741
+ builtAtMs: nowMs,
30742
+ jsonlMtimeMs: jsonlMtime(projectRoot)
30743
+ });
30744
+ return payload;
30538
30745
  } catch {
30539
- return { index: {}, suggestions: [] };
30746
+ return { index: {}, suggestions: [], effectiveness: [] };
30540
30747
  }
30541
30748
  }
30542
30749
  async function skillsBindHandler(projectRoot, body) {
@@ -30553,19 +30760,33 @@ async function skillsBindHandler(projectRoot, body) {
30553
30760
  const changed = index.disable(body.agent_id, body.skill);
30554
30761
  if (!changed) return { success: false, error: "Skill not bound to agent" };
30555
30762
  }
30763
+ cache2.delete(projectRoot);
30556
30764
  return { success: true };
30557
30765
  } catch (err) {
30558
30766
  return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
30559
30767
  }
30560
30768
  }
30561
- var import_fs52, import_path56, AGENT_ID_RE2;
30769
+ var import_fs52, import_path56, AGENT_ID_RE2, NUM_BUCKETS, WINDOW_MS2, DEFAULT_THRESHOLD, CACHE_TTL_MS, CORRECT_SIGNALS, HALLUC_SIGNALS, cache2;
30562
30770
  var init_api_skills = __esm({
30563
30771
  "packages/relay/src/dashboard/api-skills.ts"() {
30564
30772
  "use strict";
30565
30773
  init_skill_index();
30774
+ init_src4();
30566
30775
  import_fs52 = require("fs");
30567
30776
  import_path56 = require("path");
30568
30777
  AGENT_ID_RE2 = /^[a-zA-Z0-9_-]{1,64}$/;
30778
+ NUM_BUCKETS = 10;
30779
+ WINDOW_MS2 = 7 * 24 * 60 * 60 * 1e3;
30780
+ DEFAULT_THRESHOLD = 0.7;
30781
+ CACHE_TTL_MS = 6e4;
30782
+ CORRECT_SIGNALS = /* @__PURE__ */ new Set([
30783
+ "agreement",
30784
+ "category_confirmed",
30785
+ "consensus_verified",
30786
+ "unique_confirmed"
30787
+ ]);
30788
+ HALLUC_SIGNALS = /* @__PURE__ */ new Set(["disagreement", "hallucination_caught"]);
30789
+ cache2 = /* @__PURE__ */ new Map();
30569
30790
  }
30570
30791
  });
30571
30792
 
@@ -30849,6 +31070,123 @@ var init_api_consensus = __esm({
30849
31070
  }
30850
31071
  });
30851
31072
 
31073
+ // packages/relay/src/dashboard/api-consensus-flow.ts
31074
+ function isValidConsensusId(id) {
31075
+ return SAFE_CONSENSUS_ID.test(id);
31076
+ }
31077
+ function familyOf(agentId) {
31078
+ if (agentId.startsWith("sonnet-")) return "sonnet";
31079
+ if (agentId.startsWith("gemini-")) return "gemini";
31080
+ if (agentId.startsWith("opus-")) return "opus";
31081
+ if (agentId.startsWith("haiku-")) return "haiku";
31082
+ return "other";
31083
+ }
31084
+ function tally(report, bucket) {
31085
+ const arr = report?.[bucket];
31086
+ return Array.isArray(arr) ? arr : [];
31087
+ }
31088
+ function consensusFlowHandler(projectRoot, query) {
31089
+ const consensusId = query?.get("consensusId")?.trim() ?? "";
31090
+ if (!consensusId) {
31091
+ return { error: "consensusId query parameter is required" };
31092
+ }
31093
+ if (!isValidConsensusId(consensusId)) {
31094
+ return { error: `invalid consensusId shape (expected xxxxxxxx-xxxxxxxx hex)` };
31095
+ }
31096
+ const reportPath = (0, import_path61.join)(projectRoot, ".gossip", "consensus-reports", `${consensusId}.json`);
31097
+ if (!(0, import_fs56.existsSync)(reportPath)) {
31098
+ return { error: `consensus ${consensusId} not found` };
31099
+ }
31100
+ let report;
31101
+ try {
31102
+ report = JSON.parse((0, import_fs56.readFileSync)(reportPath, "utf-8"));
31103
+ } catch (e) {
31104
+ return { error: `failed to parse consensus report: ${e?.message ?? "unknown error"}` };
31105
+ }
31106
+ const buckets = {
31107
+ confirmed: tally(report, "confirmed"),
31108
+ disputed: tally(report, "disputed"),
31109
+ unverified: tally(report, "unverified"),
31110
+ unique: tally(report, "unique")
31111
+ };
31112
+ const newFindings = Array.isArray(report?.newFindings) ? report.newFindings : [];
31113
+ const totalFindings = buckets.confirmed.length + buckets.disputed.length + buckets.unverified.length + buckets.unique.length + newFindings.length;
31114
+ const familyAgents = /* @__PURE__ */ new Map();
31115
+ for (const verdict of ["confirmed", "disputed", "unverified", "unique"]) {
31116
+ for (const f of buckets[verdict]) {
31117
+ const agent = f.originalAgentId;
31118
+ if (!agent) continue;
31119
+ const fam = familyOf(agent);
31120
+ if (!familyAgents.has(fam)) familyAgents.set(fam, /* @__PURE__ */ new Set());
31121
+ familyAgents.get(fam).add(agent);
31122
+ }
31123
+ }
31124
+ const modelFamilyToFindings = Array.from(familyAgents.entries()).map(([family, ids]) => ({
31125
+ family,
31126
+ agentIds: Array.from(ids).sort(),
31127
+ agentCount: ids.size
31128
+ })).sort((a, b) => a.family.localeCompare(b.family));
31129
+ const edgeCounts = /* @__PURE__ */ new Map();
31130
+ for (const verdict of ["confirmed", "disputed", "unverified", "unique"]) {
31131
+ for (const f of buckets[verdict]) {
31132
+ const agent = f.originalAgentId;
31133
+ if (!agent) continue;
31134
+ const fam = familyOf(agent);
31135
+ const key = `${fam}::${verdict}`;
31136
+ edgeCounts.set(key, (edgeCounts.get(key) ?? 0) + 1);
31137
+ }
31138
+ }
31139
+ const familyToOutcome = [];
31140
+ for (const [key, count] of edgeCounts) {
31141
+ const [fam, verdict] = key.split("::");
31142
+ const agentCount = familyAgents.get(fam)?.size ?? 0;
31143
+ familyToOutcome.push({
31144
+ from: { family: fam, agentCount },
31145
+ to: { verdict, count },
31146
+ weight: totalFindings > 0 ? count / totalFindings : 0
31147
+ });
31148
+ }
31149
+ familyToOutcome.sort((a, b) => {
31150
+ if (a.from.family !== b.from.family) return a.from.family.localeCompare(b.from.family);
31151
+ return a.to.verdict.localeCompare(b.to.verdict);
31152
+ });
31153
+ const out = {
31154
+ consensusId,
31155
+ timestamp: typeof report?.timestamp === "string" ? report.timestamp : "",
31156
+ agentCount: typeof report?.agentCount === "number" ? report.agentCount : 0,
31157
+ modelFamilyToFindings,
31158
+ familyToOutcome,
31159
+ summary: {
31160
+ totalFindings,
31161
+ confirmed: buckets.confirmed.length,
31162
+ disputed: buckets.disputed.length,
31163
+ unverified: buckets.unverified.length,
31164
+ unique: buckets.unique.length,
31165
+ newFindings: newFindings.length
31166
+ }
31167
+ };
31168
+ if (report?.crossReviewAssignments && typeof report.crossReviewAssignments === "object") {
31169
+ out.crossReviewAssignments = report.crossReviewAssignments;
31170
+ }
31171
+ if (Array.isArray(report?.crossReviewCoverage)) {
31172
+ out.crossReviewCoverage = report.crossReviewCoverage;
31173
+ }
31174
+ if (report?.partialReview === true) out.partialReview = true;
31175
+ if (report?.coverageDegraded && typeof report.coverageDegraded === "object") {
31176
+ out.coverageDegraded = report.coverageDegraded;
31177
+ }
31178
+ return out;
31179
+ }
31180
+ var import_fs56, import_path61, SAFE_CONSENSUS_ID;
31181
+ var init_api_consensus_flow = __esm({
31182
+ "packages/relay/src/dashboard/api-consensus-flow.ts"() {
31183
+ "use strict";
31184
+ import_fs56 = require("fs");
31185
+ import_path61 = require("path");
31186
+ SAFE_CONSENSUS_ID = /^[0-9a-f]{8}-[0-9a-f]{8}$/;
31187
+ }
31188
+ });
31189
+
30852
31190
  // packages/relay/src/dashboard/api-signals.ts
30853
31191
  function inferSource(entry) {
30854
31192
  const raw = typeof entry.source === "string" ? entry.source.toLowerCase() : "";
@@ -30874,7 +31212,7 @@ async function signalsHandler(projectRoot, query) {
30874
31212
  const cursor = query?.get("cursor") ?? null;
30875
31213
  const limit = Math.min(Math.max(parseInt(query?.get("limit") ?? "", 10) || DEFAULT_LIMIT, 1), MAX_LIMIT);
30876
31214
  const offset = Math.max(parseInt(query?.get("offset") ?? "", 10) || 0, 0);
30877
- const perfPath = (0, import_path61.join)(projectRoot, ".gossip", "agent-performance.jsonl");
31215
+ const perfPath = (0, import_path62.join)(projectRoot, ".gossip", "agent-performance.jsonl");
30878
31216
  const all = [];
30879
31217
  const roundRetractions = [];
30880
31218
  const signalFilterSet = signalFilters.length ? new Set(signalFilters) : null;
@@ -30936,11 +31274,11 @@ async function signalsHandler(projectRoot, query) {
30936
31274
  if (nextCursor) response.nextCursor = nextCursor;
30937
31275
  return response;
30938
31276
  }
30939
- var import_path61, MAX_LIMIT, DEFAULT_LIMIT, META_SIGNALS;
31277
+ var import_path62, MAX_LIMIT, DEFAULT_LIMIT, META_SIGNALS;
30940
31278
  var init_api_signals = __esm({
30941
31279
  "packages/relay/src/dashboard/api-signals.ts"() {
30942
31280
  "use strict";
30943
- import_path61 = require("path");
31281
+ import_path62 = require("path");
30944
31282
  init_src4();
30945
31283
  MAX_LIMIT = 500;
30946
31284
  DEFAULT_LIMIT = 50;
@@ -30953,7 +31291,7 @@ function extractCitations(findingText, projectRoot) {
30953
31291
  const out = [];
30954
31292
  let realRoot;
30955
31293
  try {
30956
- realRoot = (0, import_fs56.realpathSync)((0, import_path62.resolve)(projectRoot));
31294
+ realRoot = (0, import_fs57.realpathSync)((0, import_path63.resolve)(projectRoot));
30957
31295
  } catch {
30958
31296
  return out;
30959
31297
  }
@@ -30964,23 +31302,23 @@ function extractCitations(findingText, projectRoot) {
30964
31302
  const line = parseInt(m[2], 10);
30965
31303
  if (!Number.isFinite(line) || line < 1) continue;
30966
31304
  if (filePath.includes("\0")) continue;
30967
- const abs = (0, import_path62.resolve)(realRoot, filePath);
30968
- const preRel = (0, import_path62.relative)(realRoot, abs);
31305
+ const abs = (0, import_path63.resolve)(realRoot, filePath);
31306
+ const preRel = (0, import_path63.relative)(realRoot, abs);
30969
31307
  if (preRel === "" || preRel.startsWith("..")) continue;
30970
- if (!(0, import_fs56.existsSync)(abs)) {
31308
+ if (!(0, import_fs57.existsSync)(abs)) {
30971
31309
  out.push({ file: filePath, line, snippet: "// file not found" });
30972
31310
  continue;
30973
31311
  }
30974
31312
  let realAbs;
30975
31313
  try {
30976
- realAbs = (0, import_fs56.realpathSync)(abs);
31314
+ realAbs = (0, import_fs57.realpathSync)(abs);
30977
31315
  } catch {
30978
31316
  continue;
30979
31317
  }
30980
- const rel = (0, import_path62.relative)(realRoot, realAbs);
31318
+ const rel = (0, import_path63.relative)(realRoot, realAbs);
30981
31319
  if (rel === "" || rel.startsWith("..")) continue;
30982
31320
  try {
30983
- const lines = (0, import_fs56.readFileSync)(realAbs, "utf-8").split("\n");
31321
+ const lines = (0, import_fs57.readFileSync)(realAbs, "utf-8").split("\n");
30984
31322
  const start = Math.max(0, line - 1 - SNIPPET_CONTEXT);
30985
31323
  const end = Math.min(lines.length, line + SNIPPET_CONTEXT);
30986
31324
  out.push({ file: filePath, line, snippet: lines.slice(start, end).join("\n") });
@@ -30993,9 +31331,9 @@ function extractCitations(findingText, projectRoot) {
30993
31331
  async function findingHandler(projectRoot, consensusId, findingId) {
30994
31332
  if (!SAFE_ID.test(consensusId)) throw new Error(`consensus ${consensusId} not found`);
30995
31333
  if (!SAFE_ID.test(findingId)) throw new Error(`finding ${findingId} not found in ${consensusId}`);
30996
- const reportPath = (0, import_path62.join)(projectRoot, ".gossip", "consensus-reports", `${consensusId}.json`);
30997
- if (!(0, import_fs56.existsSync)(reportPath)) throw new Error(`consensus ${consensusId} not found`);
30998
- const report = JSON.parse((0, import_fs56.readFileSync)(reportPath, "utf-8"));
31334
+ const reportPath = (0, import_path63.join)(projectRoot, ".gossip", "consensus-reports", `${consensusId}.json`);
31335
+ if (!(0, import_fs57.existsSync)(reportPath)) throw new Error(`consensus ${consensusId} not found`);
31336
+ const report = JSON.parse((0, import_fs57.readFileSync)(reportPath, "utf-8"));
30999
31337
  const buckets = [
31000
31338
  ["confirmed", "confirmed"],
31001
31339
  ["disputed", "disputed"],
@@ -31016,7 +31354,7 @@ async function findingHandler(projectRoot, consensusId, findingId) {
31016
31354
  }
31017
31355
  if (!found) throw new Error(`finding ${findingId} not found in ${consensusId}`);
31018
31356
  const signals = [];
31019
- const perfPath = (0, import_path62.join)(projectRoot, ".gossip", "agent-performance.jsonl");
31357
+ const perfPath = (0, import_path63.join)(projectRoot, ".gossip", "agent-performance.jsonl");
31020
31358
  try {
31021
31359
  const raw = readJsonlWithRotated(perfPath);
31022
31360
  if (raw) {
@@ -31058,13 +31396,13 @@ async function findingHandler(projectRoot, consensusId, findingId) {
31058
31396
  citations
31059
31397
  };
31060
31398
  }
31061
- var import_fs56, import_path62, SAFE_ID, SNIPPET_CONTEXT, CITE_PATTERN;
31399
+ var import_fs57, import_path63, SAFE_ID, SNIPPET_CONTEXT, CITE_PATTERN;
31062
31400
  var init_api_finding = __esm({
31063
31401
  "packages/relay/src/dashboard/api-finding.ts"() {
31064
31402
  "use strict";
31065
- import_fs56 = require("fs");
31403
+ import_fs57 = require("fs");
31066
31404
  init_src4();
31067
- import_path62 = require("path");
31405
+ import_path63 = require("path");
31068
31406
  SAFE_ID = /^[\w:.\-]+$/;
31069
31407
  SNIPPET_CONTEXT = 2;
31070
31408
  CITE_PATTERN = /<cite tag="file">([^<:]+):(\d+)<\/cite>/g;
@@ -31077,13 +31415,13 @@ async function openFindingsHandler(projectRoot) {
31077
31415
  let open = 0;
31078
31416
  let resolved = 0;
31079
31417
  let staleAnchor = 0;
31080
- const findingsPath = (0, import_path63.join)(projectRoot, ".gossip", "implementation-findings.jsonl");
31081
- if (!(0, import_fs57.existsSync)(findingsPath)) {
31418
+ const findingsPath = (0, import_path64.join)(projectRoot, ".gossip", "implementation-findings.jsonl");
31419
+ if (!(0, import_fs58.existsSync)(findingsPath)) {
31082
31420
  return { rows, totals: { open: 0, resolved: 0, staleAnchor: 0 } };
31083
31421
  }
31084
31422
  let raw;
31085
31423
  try {
31086
- raw = (0, import_fs57.readFileSync)(findingsPath, "utf-8");
31424
+ raw = (0, import_fs58.readFileSync)(findingsPath, "utf-8");
31087
31425
  } catch {
31088
31426
  return { rows, totals: { open: 0, resolved: 0, staleAnchor: 0 } };
31089
31427
  }
@@ -31121,40 +31459,40 @@ async function openFindingsHandler(projectRoot) {
31121
31459
  }
31122
31460
  return { rows, totals: { open, resolved, staleAnchor } };
31123
31461
  }
31124
- var import_fs57, import_path63;
31462
+ var import_fs58, import_path64;
31125
31463
  var init_api_open_findings = __esm({
31126
31464
  "packages/relay/src/dashboard/api-open-findings.ts"() {
31127
31465
  "use strict";
31128
- import_fs57 = require("fs");
31129
- import_path63 = require("path");
31466
+ import_fs58 = require("fs");
31467
+ import_path64 = require("path");
31130
31468
  }
31131
31469
  });
31132
31470
 
31133
31471
  // packages/relay/src/dashboard/api-learnings.ts
31134
31472
  async function learningsHandler(projectRoot) {
31135
- const agentsDir = (0, import_path64.join)(projectRoot, ".gossip", "agents");
31136
- if (!(0, import_fs58.existsSync)(agentsDir)) return { learnings: [] };
31473
+ const agentsDir = (0, import_path65.join)(projectRoot, ".gossip", "agents");
31474
+ if (!(0, import_fs59.existsSync)(agentsDir)) return { learnings: [] };
31137
31475
  const all = [];
31138
31476
  let agentIds;
31139
31477
  try {
31140
- agentIds = (0, import_fs58.readdirSync)(agentsDir).filter((f) => !f.startsWith("."));
31478
+ agentIds = (0, import_fs59.readdirSync)(agentsDir).filter((f) => !f.startsWith("."));
31141
31479
  } catch {
31142
31480
  return { learnings: [] };
31143
31481
  }
31144
31482
  for (const agentId of agentIds) {
31145
- const knowledgeDir = (0, import_path64.join)(agentsDir, agentId, "memory", "knowledge");
31146
- if (!(0, import_fs58.existsSync)(knowledgeDir)) continue;
31483
+ const knowledgeDir = (0, import_path65.join)(agentsDir, agentId, "memory", "knowledge");
31484
+ if (!(0, import_fs59.existsSync)(knowledgeDir)) continue;
31147
31485
  let files;
31148
31486
  try {
31149
- files = (0, import_fs58.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md"));
31487
+ files = (0, import_fs59.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md"));
31150
31488
  } catch {
31151
31489
  continue;
31152
31490
  }
31153
31491
  for (const filename of files) {
31154
- const filepath = (0, import_path64.join)(knowledgeDir, filename);
31492
+ const filepath = (0, import_path65.join)(knowledgeDir, filename);
31155
31493
  try {
31156
- const stat4 = (0, import_fs58.statSync)(filepath);
31157
- const raw = (0, import_fs58.readFileSync)(filepath, "utf-8");
31494
+ const stat4 = (0, import_fs59.statSync)(filepath);
31495
+ const raw = (0, import_fs59.readFileSync)(filepath, "utf-8");
31158
31496
  const fm = parseFrontmatter3(raw);
31159
31497
  all.push({
31160
31498
  agentId,
@@ -31181,28 +31519,41 @@ function parseFrontmatter3(raw) {
31181
31519
  }
31182
31520
  return fm;
31183
31521
  }
31184
- var import_fs58, import_path64, MAX_LEARNINGS;
31522
+ var import_fs59, import_path65, MAX_LEARNINGS;
31185
31523
  var init_api_learnings = __esm({
31186
31524
  "packages/relay/src/dashboard/api-learnings.ts"() {
31187
31525
  "use strict";
31188
- import_fs58 = require("fs");
31189
- import_path64 = require("path");
31526
+ import_fs59 = require("fs");
31527
+ import_path65 = require("path");
31190
31528
  MAX_LEARNINGS = 10;
31191
31529
  }
31192
31530
  });
31193
31531
 
31194
31532
  // packages/relay/src/dashboard/api-tasks.ts
31533
+ function readTaskGraphLines(graphPath) {
31534
+ const out = [];
31535
+ const archive = graphPath + ".1";
31536
+ if ((0, import_fs60.existsSync)(archive)) {
31537
+ out.push(...(0, import_fs60.readFileSync)(archive, "utf-8").split("\n").filter(Boolean));
31538
+ }
31539
+ if ((0, import_fs60.existsSync)(graphPath)) {
31540
+ out.push(...(0, import_fs60.readFileSync)(graphPath, "utf-8").split("\n").filter(Boolean));
31541
+ }
31542
+ return out;
31543
+ }
31195
31544
  async function tasksHandler(projectRoot, query) {
31196
31545
  const rawLimit = parseInt(query?.get("limit") ?? "50", 10);
31197
31546
  const rawOffset = parseInt(query?.get("offset") ?? "0", 10);
31198
31547
  const limit = isNaN(rawLimit) || rawLimit < 1 ? 50 : Math.min(rawLimit, 2e3);
31199
31548
  const offset = isNaN(rawOffset) || rawOffset < 0 ? 0 : rawOffset;
31200
- const graphPath = (0, import_path65.join)(projectRoot, ".gossip", "task-graph.jsonl");
31201
- if (!(0, import_fs59.existsSync)(graphPath)) return { items: [], total: 0, offset, limit };
31549
+ const graphPath = (0, import_path66.join)(projectRoot, ".gossip", "task-graph.jsonl");
31550
+ if (!(0, import_fs60.existsSync)(graphPath) && !(0, import_fs60.existsSync)(graphPath + ".1")) {
31551
+ return { items: [], total: 0, offset, limit };
31552
+ }
31202
31553
  const created = /* @__PURE__ */ new Map();
31203
31554
  const completed = /* @__PURE__ */ new Map();
31204
31555
  try {
31205
- const lines = (0, import_fs59.readFileSync)(graphPath, "utf-8").trim().split("\n").filter(Boolean);
31556
+ const lines = readTaskGraphLines(graphPath);
31206
31557
  for (const line of lines) {
31207
31558
  try {
31208
31559
  const entry = JSON.parse(line);
@@ -31258,24 +31609,24 @@ async function tasksHandler(projectRoot, query) {
31258
31609
  tasks.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
31259
31610
  return { items: tasks.slice(offset, offset + limit), total: tasks.length, offset, limit };
31260
31611
  }
31261
- var import_fs59, import_path65;
31612
+ var import_fs60, import_path66;
31262
31613
  var init_api_tasks = __esm({
31263
31614
  "packages/relay/src/dashboard/api-tasks.ts"() {
31264
31615
  "use strict";
31265
- import_fs59 = require("fs");
31266
- import_path65 = require("path");
31616
+ import_fs60 = require("fs");
31617
+ import_path66 = require("path");
31267
31618
  init_utility_agents();
31268
31619
  }
31269
31620
  });
31270
31621
 
31271
31622
  // packages/relay/src/dashboard/api-active-tasks.ts
31272
31623
  async function activeTasksHandler(projectRoot) {
31273
- const taskGraphPath = (0, import_path66.join)(projectRoot, ".gossip", "task-graph.jsonl");
31274
- if (!(0, import_fs60.existsSync)(taskGraphPath)) return { tasks: [] };
31624
+ const taskGraphPath = (0, import_path67.join)(projectRoot, ".gossip", "task-graph.jsonl");
31625
+ if (!(0, import_fs61.existsSync)(taskGraphPath)) return { tasks: [] };
31275
31626
  const created = /* @__PURE__ */ new Map();
31276
31627
  const finished = /* @__PURE__ */ new Set();
31277
31628
  try {
31278
- const lines = (0, import_fs60.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
31629
+ const lines = (0, import_fs61.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
31279
31630
  for (const line of lines) {
31280
31631
  try {
31281
31632
  const ev = JSON.parse(line);
@@ -31303,12 +31654,12 @@ async function activeTasksHandler(projectRoot) {
31303
31654
  active.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
31304
31655
  return { tasks: active.slice(0, 10) };
31305
31656
  }
31306
- var import_fs60, import_path66;
31657
+ var import_fs61, import_path67;
31307
31658
  var init_api_active_tasks = __esm({
31308
31659
  "packages/relay/src/dashboard/api-active-tasks.ts"() {
31309
31660
  "use strict";
31310
- import_fs60 = require("fs");
31311
- import_path66 = require("path");
31661
+ import_fs61 = require("fs");
31662
+ import_path67 = require("path");
31312
31663
  init_utility_agents();
31313
31664
  }
31314
31665
  });
@@ -31322,25 +31673,25 @@ function categorize(text) {
31322
31673
  return "other";
31323
31674
  }
31324
31675
  function logsHandler(projectRoot, query) {
31325
- const logPath = (0, import_path67.join)(projectRoot, ".gossip", "mcp.log");
31326
- if (!(0, import_fs61.existsSync)(logPath)) {
31676
+ const logPath = (0, import_path68.join)(projectRoot, ".gossip", "mcp.log");
31677
+ if (!(0, import_fs62.existsSync)(logPath)) {
31327
31678
  return { entries: [], totalLines: 0, fileSize: 0 };
31328
31679
  }
31329
31680
  const filter = query?.get("filter") || void 0;
31330
31681
  const tail = parseInt(query?.get("tail") || "200", 10);
31331
31682
  const clampedTail = Math.min(Math.max(tail, 10), 2e3);
31332
- const fileSize = (0, import_fs61.statSync)(logPath).size;
31683
+ const fileSize = (0, import_fs62.statSync)(logPath).size;
31333
31684
  const MAX_READ = 512 * 1024;
31334
31685
  const readFrom = Math.max(0, fileSize - MAX_READ);
31335
31686
  const readLen = fileSize - readFrom;
31336
- const fd = (0, import_fs61.openSync)(logPath, "r");
31687
+ const fd = (0, import_fs62.openSync)(logPath, "r");
31337
31688
  let buf = Buffer.alloc(0);
31338
31689
  try {
31339
31690
  buf = Buffer.allocUnsafe(readLen);
31340
- const bytesRead = (0, import_fs61.readSync)(fd, buf, 0, readLen, readFrom);
31691
+ const bytesRead = (0, import_fs62.readSync)(fd, buf, 0, readLen, readFrom);
31341
31692
  buf = buf.subarray(0, bytesRead);
31342
31693
  } finally {
31343
- (0, import_fs61.closeSync)(fd);
31694
+ (0, import_fs62.closeSync)(fd);
31344
31695
  }
31345
31696
  let raw = buf.toString("utf-8");
31346
31697
  let lineOffset = 0;
@@ -31348,13 +31699,13 @@ function logsHandler(projectRoot, query) {
31348
31699
  const nl = raw.indexOf("\n");
31349
31700
  raw = nl >= 0 ? raw.slice(nl + 1) : raw;
31350
31701
  const SCAN_CHUNK = 64 * 1024;
31351
- const scanFd = (0, import_fs61.openSync)(logPath, "r");
31702
+ const scanFd = (0, import_fs62.openSync)(logPath, "r");
31352
31703
  try {
31353
31704
  let pos = 0;
31354
31705
  const chunk = Buffer.allocUnsafe(SCAN_CHUNK);
31355
31706
  while (pos < readFrom) {
31356
31707
  const len = Math.min(SCAN_CHUNK, readFrom - pos);
31357
- const n = (0, import_fs61.readSync)(scanFd, chunk, 0, len, pos);
31708
+ const n = (0, import_fs62.readSync)(scanFd, chunk, 0, len, pos);
31358
31709
  if (n === 0) break;
31359
31710
  for (let j = 0; j < n; j++) {
31360
31711
  if (chunk[j] === 10) lineOffset++;
@@ -31362,7 +31713,7 @@ function logsHandler(projectRoot, query) {
31362
31713
  pos += n;
31363
31714
  }
31364
31715
  } finally {
31365
- (0, import_fs61.closeSync)(scanFd);
31716
+ (0, import_fs62.closeSync)(scanFd);
31366
31717
  }
31367
31718
  }
31368
31719
  const allLines = raw.split("\n").filter(Boolean);
@@ -31380,12 +31731,12 @@ function logsHandler(projectRoot, query) {
31380
31731
  entries = entries.slice(-clampedTail);
31381
31732
  return { entries, totalLines, fileSize, filter };
31382
31733
  }
31383
- var import_fs61, import_path67, CATEGORY_PATTERNS2;
31734
+ var import_fs62, import_path68, CATEGORY_PATTERNS2;
31384
31735
  var init_api_logs = __esm({
31385
31736
  "packages/relay/src/dashboard/api-logs.ts"() {
31386
31737
  "use strict";
31387
- import_fs61 = require("fs");
31388
- import_path67 = require("path");
31738
+ import_fs62 = require("fs");
31739
+ import_path68 = require("path");
31389
31740
  CATEGORY_PATTERNS2 = [
31390
31741
  [/^\[worker:/, "worker"],
31391
31742
  [/^\[Gemini\]/, "gemini"],
@@ -31417,11 +31768,11 @@ function violationsHandler(projectRoot, query) {
31417
31768
  const page = Math.max(1, parseInt(query?.get("page") ?? "1", 10));
31418
31769
  const pageSize = Math.min(100, Math.max(1, parseInt(query?.get("pageSize") ?? "25", 10)));
31419
31770
  const agentFilter = query?.get("agentId") ?? null;
31420
- const filePath = (0, import_path68.join)(projectRoot, FILE);
31421
- if (!(0, import_fs62.existsSync)(filePath)) {
31771
+ const filePath = (0, import_path69.join)(projectRoot, FILE);
31772
+ if (!(0, import_fs63.existsSync)(filePath)) {
31422
31773
  return { items: [], total: 0, page, pageSize };
31423
31774
  }
31424
- const raw = (0, import_fs62.readFileSync)(filePath, "utf-8");
31775
+ const raw = (0, import_fs63.readFileSync)(filePath, "utf-8");
31425
31776
  const lines = raw.trim().split("\n").filter(Boolean);
31426
31777
  const entries = [];
31427
31778
  for (const line of lines) {
@@ -31441,12 +31792,12 @@ function violationsHandler(projectRoot, query) {
31441
31792
  const start = (page - 1) * pageSize;
31442
31793
  return { items: entries.slice(start, start + pageSize), total, page, pageSize };
31443
31794
  }
31444
- var import_fs62, import_path68, FILE;
31795
+ var import_fs63, import_path69, FILE;
31445
31796
  var init_api_violations = __esm({
31446
31797
  "packages/relay/src/dashboard/api-violations.ts"() {
31447
31798
  "use strict";
31448
- import_fs62 = require("fs");
31449
- import_path68 = require("path");
31799
+ import_fs63 = require("fs");
31800
+ import_path69 = require("path");
31450
31801
  FILE = ".gossip/process-violations.jsonl";
31451
31802
  }
31452
31803
  });
@@ -31454,15 +31805,15 @@ var init_api_violations = __esm({
31454
31805
  // packages/relay/src/dashboard/routes.ts
31455
31806
  function resolveDashboardRoot(projectRoot) {
31456
31807
  const candidates = [
31457
- (0, import_path69.resolve)(__dirname, "..", "dist-dashboard"),
31808
+ (0, import_path70.resolve)(__dirname, "..", "dist-dashboard"),
31458
31809
  // bundled: dist-mcp/mcp-server.js → ../dist-dashboard
31459
- (0, import_path69.resolve)(__dirname, "..", "..", "..", "..", "dist-dashboard"),
31810
+ (0, import_path70.resolve)(__dirname, "..", "..", "..", "..", "dist-dashboard"),
31460
31811
  // tsc dev: packages/relay/dist/dashboard → repo-root
31461
- (0, import_path69.join)(projectRoot, "dist-dashboard")
31812
+ (0, import_path70.join)(projectRoot, "dist-dashboard")
31462
31813
  // legacy dev fallback (git-clone running from repo root)
31463
31814
  ];
31464
31815
  for (const p of candidates) {
31465
- if ((0, import_fs63.existsSync)(p)) return p;
31816
+ if ((0, import_fs64.existsSync)(p)) return p;
31466
31817
  }
31467
31818
  return null;
31468
31819
  }
@@ -31489,7 +31840,7 @@ function readBody(req) {
31489
31840
  });
31490
31841
  });
31491
31842
  }
31492
- var import_fs63, import_path69, import_crypto25, AUTH_MAX_ATTEMPTS, AUTH_LOCKOUT_MS, DashboardRouter, MAX_BODY_SIZE;
31843
+ var import_fs64, import_path70, import_crypto25, AUTH_MAX_ATTEMPTS, AUTH_LOCKOUT_MS, DashboardRouter, MAX_BODY_SIZE;
31493
31844
  var init_routes = __esm({
31494
31845
  "packages/relay/src/dashboard/routes.ts"() {
31495
31846
  "use strict";
@@ -31502,6 +31853,7 @@ var init_routes = __esm({
31502
31853
  init_api_native_memory();
31503
31854
  init_api_gossip_memory();
31504
31855
  init_api_consensus();
31856
+ init_api_consensus_flow();
31505
31857
  init_api_signals();
31506
31858
  init_api_finding();
31507
31859
  init_api_open_findings();
@@ -31510,8 +31862,8 @@ var init_routes = __esm({
31510
31862
  init_api_active_tasks();
31511
31863
  init_api_logs();
31512
31864
  init_api_violations();
31513
- import_fs63 = require("fs");
31514
- import_path69 = require("path");
31865
+ import_fs64 = require("fs");
31866
+ import_path70 = require("path");
31515
31867
  import_crypto25 = require("crypto");
31516
31868
  AUTH_MAX_ATTEMPTS = 10;
31517
31869
  AUTH_LOCKOUT_MS = 6e4;
@@ -31574,6 +31926,11 @@ var init_routes = __esm({
31574
31926
  if (url2 === "/dashboard") {
31575
31927
  return this.serveDashboard(res);
31576
31928
  }
31929
+ if (url2 === "/" || url2 === "") {
31930
+ res.writeHead(302, { Location: "/dashboard" });
31931
+ res.end();
31932
+ return true;
31933
+ }
31577
31934
  this.json(res, 404, { error: "Not found" });
31578
31935
  return true;
31579
31936
  }
@@ -31690,6 +32047,24 @@ var init_routes = __esm({
31690
32047
  this.json(res, 200, data);
31691
32048
  return true;
31692
32049
  }
32050
+ if (url2 === "/dashboard/api/consensus-flow" && req.method === "GET") {
32051
+ const consensusId = query?.get("consensusId")?.trim() ?? "";
32052
+ if (!consensusId) {
32053
+ this.json(res, 400, { error: "consensusId query parameter is required" });
32054
+ return true;
32055
+ }
32056
+ if (!isValidConsensusId(consensusId)) {
32057
+ this.json(res, 400, { error: "invalid consensusId shape (expected xxxxxxxx-xxxxxxxx hex)" });
32058
+ return true;
32059
+ }
32060
+ const data = consensusFlowHandler(this.projectRoot, query ?? void 0);
32061
+ if ("error" in data) {
32062
+ this.json(res, 404, data);
32063
+ return true;
32064
+ }
32065
+ this.json(res, 200, data);
32066
+ return true;
32067
+ }
31693
32068
  if (url2 === "/dashboard/api/consensus-reports" && req.method === "GET") {
31694
32069
  const page = parseInt(query?.get("page") || "1", 10);
31695
32070
  const pageSize = parseInt(query?.get("pageSize") || "5", 10);
@@ -31792,13 +32167,13 @@ var init_routes = __esm({
31792
32167
  res.end("Dashboard assets not found. Reinstall gossipcat or rebuild from source.");
31793
32168
  return true;
31794
32169
  }
31795
- const htmlPath = (0, import_path69.join)(this.dashboardRoot, "index.html");
31796
- if (!(0, import_fs63.existsSync)(htmlPath)) {
32170
+ const htmlPath = (0, import_path70.join)(this.dashboardRoot, "index.html");
32171
+ if (!(0, import_fs64.existsSync)(htmlPath)) {
31797
32172
  res.writeHead(503, { "Content-Type": "text/plain" });
31798
32173
  res.end(`Dashboard index.html missing at ${this.dashboardRoot}. Reinstall gossipcat.`);
31799
32174
  return true;
31800
32175
  }
31801
- const html = (0, import_fs63.readFileSync)(htmlPath, "utf-8");
32176
+ const html = (0, import_fs64.readFileSync)(htmlPath, "utf-8");
31802
32177
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
31803
32178
  res.end(html);
31804
32179
  return true;
@@ -31824,16 +32199,16 @@ var init_routes = __esm({
31824
32199
  const ext = "." + (relativePath.split(".").pop() || "");
31825
32200
  const mime = MIME[ext];
31826
32201
  if (!mime) return false;
31827
- const filePath = (0, import_path69.join)(this.dashboardRoot, relativePath);
32202
+ const filePath = (0, import_path70.join)(this.dashboardRoot, relativePath);
31828
32203
  try {
31829
- const realFile = (0, import_fs63.realpathSync)(filePath);
31830
- const realBase = (0, import_fs63.realpathSync)(this.dashboardRoot);
32204
+ const realFile = (0, import_fs64.realpathSync)(filePath);
32205
+ const realBase = (0, import_fs64.realpathSync)(this.dashboardRoot);
31831
32206
  if (!realFile.startsWith(realBase + "/")) {
31832
32207
  res.writeHead(404);
31833
32208
  res.end();
31834
32209
  return true;
31835
32210
  }
31836
- const data = (0, import_fs63.readFileSync)(realFile);
32211
+ const data = (0, import_fs64.readFileSync)(realFile);
31837
32212
  res.writeHead(200, { "Content-Type": mime, "Cache-Control": "public, max-age=86400" });
31838
32213
  res.end(data);
31839
32214
  return true;
@@ -31848,8 +32223,8 @@ var init_routes = __esm({
31848
32223
  return match ? match[1] : null;
31849
32224
  }
31850
32225
  getConsensusReports(page = 1, pageSize = 5) {
31851
- const { readdirSync: readdirSync22, readFileSync: readFileSync62, existsSync: existsSync69 } = require("fs");
31852
- const reportsDir = (0, import_path69.join)(this.projectRoot, ".gossip", "consensus-reports");
32226
+ const { readdirSync: readdirSync22, readFileSync: readFileSync64, existsSync: existsSync70 } = require("fs");
32227
+ const reportsDir = (0, import_path70.join)(this.projectRoot, ".gossip", "consensus-reports");
31853
32228
  let retractedConsensusIds = [];
31854
32229
  let roundRetractions = [];
31855
32230
  try {
@@ -31859,13 +32234,13 @@ var init_routes = __esm({
31859
32234
  roundRetractions = reader.getRoundRetractions();
31860
32235
  } catch {
31861
32236
  }
31862
- if (!existsSync69(reportsDir)) return { reports: [], totalReports: 0, page, pageSize, retractedConsensusIds, roundRetractions };
32237
+ if (!existsSync70(reportsDir)) return { reports: [], totalReports: 0, page, pageSize, retractedConsensusIds, roundRetractions };
31863
32238
  try {
31864
- const { statSync: statSync34 } = require("fs");
32239
+ const { statSync: statSync35 } = require("fs");
31865
32240
  const allFiles = readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).sort((a, b) => {
31866
32241
  try {
31867
- const aTime = statSync34((0, import_path69.join)(reportsDir, a)).mtimeMs;
31868
- const bTime = statSync34((0, import_path69.join)(reportsDir, b)).mtimeMs;
32242
+ const aTime = statSync35((0, import_path70.join)(reportsDir, a)).mtimeMs;
32243
+ const bTime = statSync35((0, import_path70.join)(reportsDir, b)).mtimeMs;
31869
32244
  return bTime - aTime;
31870
32245
  } catch {
31871
32246
  return 0;
@@ -31876,13 +32251,13 @@ var init_routes = __esm({
31876
32251
  const clampedPage = Math.max(page, 1);
31877
32252
  const start = (clampedPage - 1) * clampedPageSize;
31878
32253
  const files = allFiles.slice(start, start + clampedPageSize);
31879
- const realReportsDir = (0, import_fs63.realpathSync)(reportsDir);
32254
+ const realReportsDir = (0, import_fs64.realpathSync)(reportsDir);
31880
32255
  const reports = files.map((f) => {
31881
32256
  try {
31882
- const filePath = (0, import_path69.join)(reportsDir, f);
31883
- const realFile = (0, import_fs63.realpathSync)(filePath);
32257
+ const filePath = (0, import_path70.join)(reportsDir, f);
32258
+ const realFile = (0, import_fs64.realpathSync)(filePath);
31884
32259
  if (!realFile.startsWith(realReportsDir + "/")) return null;
31885
- return JSON.parse(readFileSync62(realFile, "utf-8"));
32260
+ return JSON.parse(readFileSync64(realFile, "utf-8"));
31886
32261
  } catch {
31887
32262
  return null;
31888
32263
  }
@@ -31893,29 +32268,29 @@ var init_routes = __esm({
31893
32268
  }
31894
32269
  }
31895
32270
  archiveFindings() {
31896
- const { readdirSync: readdirSync22, readFileSync: readFileSync62, renameSync: renameSync15, writeFileSync: writeFileSync34, mkdirSync: mkdirSync41, existsSync: existsSync69 } = require("fs");
31897
- const reportsDir = (0, import_path69.join)(this.projectRoot, ".gossip", "consensus-reports");
31898
- const archiveDir = (0, import_path69.join)(this.projectRoot, ".gossip", "consensus-reports-archive");
32271
+ const { readdirSync: readdirSync22, readFileSync: readFileSync64, renameSync: renameSync15, writeFileSync: writeFileSync34, mkdirSync: mkdirSync41, existsSync: existsSync70 } = require("fs");
32272
+ const reportsDir = (0, import_path70.join)(this.projectRoot, ".gossip", "consensus-reports");
32273
+ const archiveDir = (0, import_path70.join)(this.projectRoot, ".gossip", "consensus-reports-archive");
31899
32274
  let archived = 0;
31900
- if (existsSync69(reportsDir)) {
32275
+ if (existsSync70(reportsDir)) {
31901
32276
  const files = readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).sort().reverse();
31902
32277
  if (files.length > 5) {
31903
32278
  mkdirSync41(archiveDir, { recursive: true });
31904
32279
  const toArchive = files.slice(5);
31905
32280
  for (const f of toArchive) {
31906
32281
  try {
31907
- renameSync15((0, import_path69.join)(reportsDir, f), (0, import_path69.join)(archiveDir, f));
32282
+ renameSync15((0, import_path70.join)(reportsDir, f), (0, import_path70.join)(archiveDir, f));
31908
32283
  archived++;
31909
32284
  } catch {
31910
32285
  }
31911
32286
  }
31912
32287
  }
31913
32288
  }
31914
- const findingsPath = (0, import_path69.join)(this.projectRoot, ".gossip", "implementation-findings.jsonl");
32289
+ const findingsPath = (0, import_path70.join)(this.projectRoot, ".gossip", "implementation-findings.jsonl");
31915
32290
  let findingsCleared = 0;
31916
- if (existsSync69(findingsPath)) {
32291
+ if (existsSync70(findingsPath)) {
31917
32292
  try {
31918
- const lines = readFileSync62(findingsPath, "utf-8").trim().split("\n").filter(Boolean);
32293
+ const lines = readFileSync64(findingsPath, "utf-8").trim().split("\n").filter(Boolean);
31919
32294
  const kept = lines.filter((line) => {
31920
32295
  try {
31921
32296
  const entry = JSON.parse(line);
@@ -31932,7 +32307,7 @@ var init_routes = __esm({
31932
32307
  } catch {
31933
32308
  }
31934
32309
  }
31935
- const remaining = existsSync69(reportsDir) ? readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).length : 0;
32310
+ const remaining = existsSync70(reportsDir) ? readdirSync22(reportsDir).filter((f) => f.endsWith(".json")).length : 0;
31936
32311
  return { archived, remaining, findingsCleared };
31937
32312
  }
31938
32313
  json(res, status, data) {
@@ -31945,14 +32320,14 @@ var init_routes = __esm({
31945
32320
  });
31946
32321
 
31947
32322
  // packages/relay/src/dashboard/ws.ts
31948
- var import_ws3, import_fs64, import_fs65, import_path70, DashboardWs;
32323
+ var import_ws3, import_fs65, import_fs66, import_path71, DashboardWs;
31949
32324
  var init_ws = __esm({
31950
32325
  "packages/relay/src/dashboard/ws.ts"() {
31951
32326
  "use strict";
31952
32327
  import_ws3 = require("ws");
31953
- import_fs64 = require("fs");
31954
32328
  import_fs65 = require("fs");
31955
- import_path70 = require("path");
32329
+ import_fs66 = require("fs");
32330
+ import_path71 = require("path");
31956
32331
  DashboardWs = class {
31957
32332
  clients = /* @__PURE__ */ new Set();
31958
32333
  logWatcher = null;
@@ -31977,15 +32352,15 @@ var init_ws = __esm({
31977
32352
  /** Start watching mcp.log for new lines and broadcasting them to connected clients. */
31978
32353
  startLogWatcher(projectRoot) {
31979
32354
  this.stopLogWatcher();
31980
- this.logPath = (0, import_path70.join)(projectRoot, ".gossip", "mcp.log");
31981
- if (!(0, import_fs64.existsSync)(this.logPath)) return;
32355
+ this.logPath = (0, import_path71.join)(projectRoot, ".gossip", "mcp.log");
32356
+ if (!(0, import_fs65.existsSync)(this.logPath)) return;
31982
32357
  try {
31983
- this.logOffset = (0, import_fs64.statSync)(this.logPath).size;
32358
+ this.logOffset = (0, import_fs65.statSync)(this.logPath).size;
31984
32359
  } catch {
31985
32360
  this.logOffset = 0;
31986
32361
  }
31987
32362
  try {
31988
- this.logWatcher = (0, import_fs65.watch)(this.logPath, () => {
32363
+ this.logWatcher = (0, import_fs66.watch)(this.logPath, () => {
31989
32364
  if (this.clients.size === 0) return;
31990
32365
  this.readNewLines();
31991
32366
  });
@@ -32002,7 +32377,7 @@ var init_ws = __esm({
32002
32377
  if (this.logReading) return;
32003
32378
  this.logReading = true;
32004
32379
  try {
32005
- const currentSize = (0, import_fs64.statSync)(this.logPath).size;
32380
+ const currentSize = (0, import_fs65.statSync)(this.logPath).size;
32006
32381
  if (currentSize < this.logOffset) {
32007
32382
  this.logOffset = 0;
32008
32383
  this.logCarry = "";
@@ -32015,7 +32390,7 @@ var init_ws = __esm({
32015
32390
  const readFrom = capped ? (this.logCarry = "", this.logCapped = true, currentSize - 65536) : (this.logCapped = false, this.logOffset);
32016
32391
  let stream;
32017
32392
  try {
32018
- stream = (0, import_fs64.createReadStream)(this.logPath, { start: readFrom, end: currentSize - 1 });
32393
+ stream = (0, import_fs65.createReadStream)(this.logPath, { start: readFrom, end: currentSize - 1 });
32019
32394
  } catch {
32020
32395
  this.logReading = false;
32021
32396
  return;
@@ -32678,14 +33053,14 @@ __export(sandbox_exports, {
32678
33053
  });
32679
33054
  function rotateIfNeeded2(filePath, maxBytes) {
32680
33055
  try {
32681
- const st = (0, import_fs66.statSync)(filePath);
33056
+ const st = (0, import_fs67.statSync)(filePath);
32682
33057
  if (st.size < maxBytes) return;
32683
33058
  const rotated = filePath + ".1";
32684
33059
  try {
32685
- if ((0, import_fs66.existsSync)(rotated)) (0, import_fs66.unlinkSync)(rotated);
33060
+ if ((0, import_fs67.existsSync)(rotated)) (0, import_fs67.unlinkSync)(rotated);
32686
33061
  } catch {
32687
33062
  }
32688
- (0, import_fs66.renameSync)(filePath, rotated);
33063
+ (0, import_fs67.renameSync)(filePath, rotated);
32689
33064
  } catch {
32690
33065
  }
32691
33066
  }
@@ -32758,9 +33133,9 @@ Tests passing is NOT sufficient verification \u2014 the 2026-04-22 incident had
32758
33133
  }
32759
33134
  function readSandboxMode(projectRoot) {
32760
33135
  try {
32761
- const p = (0, import_path71.join)(projectRoot, ".gossip", "config.json");
32762
- if (!(0, import_fs66.existsSync)(p)) return "warn";
32763
- const raw = JSON.parse((0, import_fs66.readFileSync)(p, "utf-8"));
33136
+ const p = (0, import_path72.join)(projectRoot, ".gossip", "config.json");
33137
+ if (!(0, import_fs67.existsSync)(p)) return "warn";
33138
+ const raw = JSON.parse((0, import_fs67.readFileSync)(p, "utf-8"));
32764
33139
  const mode = raw?.sandboxEnforcement;
32765
33140
  if (mode === "off" || mode === "warn" || mode === "block") return mode;
32766
33141
  return "warn";
@@ -32770,8 +33145,8 @@ function readSandboxMode(projectRoot) {
32770
33145
  }
32771
33146
  function recordDispatchMetadata(projectRoot, meta3) {
32772
33147
  try {
32773
- const dir = (0, import_path71.join)(projectRoot, ".gossip");
32774
- (0, import_fs66.mkdirSync)(dir, { recursive: true });
33148
+ const dir = (0, import_path72.join)(projectRoot, ".gossip");
33149
+ (0, import_fs67.mkdirSync)(dir, { recursive: true });
32775
33150
  const snapshotted = { ...meta3 };
32776
33151
  if (meta3.writeMode === "scoped" || meta3.writeMode === "worktree") {
32777
33152
  try {
@@ -32789,15 +33164,15 @@ function recordDispatchMetadata(projectRoot, meta3) {
32789
33164
  } catch {
32790
33165
  }
32791
33166
  }
32792
- (0, import_fs66.appendFileSync)((0, import_path71.join)(dir, METADATA_FILE), JSON.stringify(snapshotted) + "\n");
33167
+ (0, import_fs67.appendFileSync)((0, import_path72.join)(dir, METADATA_FILE), JSON.stringify(snapshotted) + "\n");
32793
33168
  } catch {
32794
33169
  }
32795
33170
  }
32796
33171
  function updateDispatchMetadata(projectRoot, taskId, patch) {
32797
33172
  try {
32798
- const p = (0, import_path71.join)(projectRoot, ".gossip", METADATA_FILE);
32799
- if (!(0, import_fs66.existsSync)(p)) return false;
32800
- const raw = (0, import_fs66.readFileSync)(p, "utf-8");
33173
+ const p = (0, import_path72.join)(projectRoot, ".gossip", METADATA_FILE);
33174
+ if (!(0, import_fs67.existsSync)(p)) return false;
33175
+ const raw = (0, import_fs67.readFileSync)(p, "utf-8");
32801
33176
  const lines = raw.split("\n");
32802
33177
  let patched = false;
32803
33178
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -32815,7 +33190,7 @@ function updateDispatchMetadata(projectRoot, taskId, patch) {
32815
33190
  }
32816
33191
  }
32817
33192
  if (!patched) return false;
32818
- (0, import_fs66.writeFileSync)(p, lines.join("\n"));
33193
+ (0, import_fs67.writeFileSync)(p, lines.join("\n"));
32819
33194
  return true;
32820
33195
  } catch {
32821
33196
  return false;
@@ -32824,14 +33199,14 @@ function updateDispatchMetadata(projectRoot, taskId, patch) {
32824
33199
  function stampTaskSentinel(projectRoot, taskId) {
32825
33200
  if (!taskId) return null;
32826
33201
  try {
32827
- const dir = (0, import_path71.join)(projectRoot, ".gossip", SENTINEL_DIR);
32828
- (0, import_fs66.mkdirSync)(dir, { recursive: true });
33202
+ const dir = (0, import_path72.join)(projectRoot, ".gossip", SENTINEL_DIR);
33203
+ (0, import_fs67.mkdirSync)(dir, { recursive: true });
32829
33204
  const slug = taskId.replace(/[^a-zA-Z0-9_-]/g, "_");
32830
- const path7 = (0, import_path71.join)(dir, `${slug}.sentinel`);
32831
- const fd = (0, import_fs66.openSync)(path7, "w");
32832
- (0, import_fs66.closeSync)(fd);
33205
+ const path7 = (0, import_path72.join)(dir, `${slug}.sentinel`);
33206
+ const fd = (0, import_fs67.openSync)(path7, "w");
33207
+ (0, import_fs67.closeSync)(fd);
32833
33208
  const stampTime = new Date(Date.now() - 2e3);
32834
- (0, import_fs66.utimesSync)(path7, stampTime, stampTime);
33209
+ (0, import_fs67.utimesSync)(path7, stampTime, stampTime);
32835
33210
  return path7;
32836
33211
  } catch {
32837
33212
  return null;
@@ -32840,15 +33215,15 @@ function stampTaskSentinel(projectRoot, taskId) {
32840
33215
  function cleanupTaskSentinel(sentinelPath) {
32841
33216
  if (!sentinelPath) return;
32842
33217
  try {
32843
- (0, import_fs66.unlinkSync)(sentinelPath);
33218
+ (0, import_fs67.unlinkSync)(sentinelPath);
32844
33219
  } catch {
32845
33220
  }
32846
33221
  }
32847
33222
  function lookupDispatchMetadata(projectRoot, taskId) {
32848
33223
  try {
32849
- const p = (0, import_path71.join)(projectRoot, ".gossip", METADATA_FILE);
32850
- if (!(0, import_fs66.existsSync)(p)) return null;
32851
- const raw = (0, import_fs66.readFileSync)(p, "utf-8");
33224
+ const p = (0, import_path72.join)(projectRoot, ".gossip", METADATA_FILE);
33225
+ if (!(0, import_fs67.existsSync)(p)) return null;
33226
+ const raw = (0, import_fs67.readFileSync)(p, "utf-8");
32852
33227
  const lines = raw.split("\n").filter(Boolean);
32853
33228
  for (let i = lines.length - 1; i >= 0; i--) {
32854
33229
  try {
@@ -32880,21 +33255,21 @@ function parseGitStatus(porcelain) {
32880
33255
  function normalizeScope(scope, projectRoot) {
32881
33256
  let s = scope.trim();
32882
33257
  if (!s) return "";
32883
- if ((0, import_path71.isAbsolute)(s)) {
32884
- s = (0, import_path71.relative)(projectRoot, s);
33258
+ if ((0, import_path72.isAbsolute)(s)) {
33259
+ s = (0, import_path72.relative)(projectRoot, s);
32885
33260
  } else if (s.startsWith("./")) {
32886
33261
  s = s.slice(2);
32887
33262
  }
32888
- s = (0, import_path71.normalize)(s).replace(/\/+$/, "");
33263
+ s = (0, import_path72.normalize)(s).replace(/\/+$/, "");
32889
33264
  if (s === "." || s === "") return "";
32890
33265
  return s;
32891
33266
  }
32892
33267
  function isInsideScope(filePath, scope) {
32893
33268
  if (!scope) return true;
32894
- const f = (0, import_path71.normalize)(filePath).replace(/^\.\//, "");
33269
+ const f = (0, import_path72.normalize)(filePath).replace(/^\.\//, "");
32895
33270
  const s = scope.replace(/^\.\//, "").replace(/\/+$/, "");
32896
33271
  if (f === s) return true;
32897
- return f.startsWith(s + "/") || f.startsWith(s + import_path71.sep);
33272
+ return f.startsWith(s + "/") || f.startsWith(s + import_path72.sep);
32898
33273
  }
32899
33274
  function detectBoundaryEscapes(meta3, modifiedFiles, projectRoot) {
32900
33275
  const mode = meta3.writeMode;
@@ -32955,8 +33330,8 @@ function recordBoundaryEscape(projectRoot, meta3, violations, mode) {
32955
33330
  } catch {
32956
33331
  }
32957
33332
  try {
32958
- const dir = (0, import_path71.join)(projectRoot, ".gossip");
32959
- (0, import_fs66.mkdirSync)(dir, { recursive: true });
33333
+ const dir = (0, import_path72.join)(projectRoot, ".gossip");
33334
+ (0, import_fs67.mkdirSync)(dir, { recursive: true });
32960
33335
  const line = {
32961
33336
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
32962
33337
  taskId: meta3.taskId,
@@ -32967,15 +33342,15 @@ function recordBoundaryEscape(projectRoot, meta3, violations, mode) {
32967
33342
  action: mode
32968
33343
  // "warn" or "block"
32969
33344
  };
32970
- const escapeFile = (0, import_path71.join)(dir, BOUNDARY_ESCAPE_FILE);
33345
+ const escapeFile = (0, import_path72.join)(dir, BOUNDARY_ESCAPE_FILE);
32971
33346
  rotateIfNeeded2(escapeFile, MAX_BOUNDARY_ESCAPE_BYTES);
32972
- (0, import_fs66.appendFileSync)(escapeFile, JSON.stringify(line) + "\n");
33347
+ (0, import_fs67.appendFileSync)(escapeFile, JSON.stringify(line) + "\n");
32973
33348
  } catch {
32974
33349
  }
32975
33350
  }
32976
33351
  function canonicalize(p) {
32977
33352
  try {
32978
- return (0, import_path71.resolve)(p).replace(/\/+$/, "") || "/";
33353
+ return (0, import_path72.resolve)(p).replace(/\/+$/, "") || "/";
32979
33354
  } catch {
32980
33355
  return p.replace(/\/+$/, "") || "/";
32981
33356
  }
@@ -33186,7 +33561,7 @@ function buildAuditExclusions(projectRoot, ownWorktree, scope) {
33186
33561
  for (const v of expandTmpVariants(wt)) excl.add(v);
33187
33562
  }
33188
33563
  if (scope) {
33189
- const s = canonicalize((0, import_path71.join)(projectRoot, scope));
33564
+ const s = canonicalize((0, import_path72.join)(projectRoot, scope));
33190
33565
  for (const v of expandTmpVariants(s)) excl.add(v);
33191
33566
  }
33192
33567
  return Array.from(excl);
@@ -33240,12 +33615,12 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
33240
33615
  return { violations: [], skipped: "win32" };
33241
33616
  }
33242
33617
  const sentinel = meta3.sentinelPath;
33243
- if (!sentinel || !(0, import_fs66.existsSync)(sentinel)) {
33618
+ if (!sentinel || !(0, import_fs67.existsSync)(sentinel)) {
33244
33619
  return { violations: [], skipped: "sentinel missing" };
33245
33620
  }
33246
33621
  let sentinelMtimeMs = 0;
33247
33622
  try {
33248
- sentinelMtimeMs = (0, import_fs66.statSync)(sentinel).mtimeMs;
33623
+ sentinelMtimeMs = (0, import_fs67.statSync)(sentinel).mtimeMs;
33249
33624
  } catch {
33250
33625
  }
33251
33626
  if (sentinelMtimeMs === 0) {
@@ -33257,11 +33632,11 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
33257
33632
  );
33258
33633
  const exclusions = buildAuditExclusions(projectRoot, meta3.worktreePath, options.scope);
33259
33634
  const findBin = options.findBinary ?? "find";
33260
- const sentinelDir = canonicalize((0, import_path71.join)(projectRoot, ".gossip", SENTINEL_DIR));
33635
+ const sentinelDir = canonicalize((0, import_path72.join)(projectRoot, ".gossip", SENTINEL_DIR));
33261
33636
  const mainSet = /* @__PURE__ */ new Set();
33262
33637
  const sensitiveSet = /* @__PURE__ */ new Set();
33263
33638
  for (const root of scanRoots) {
33264
- if (!(0, import_fs66.existsSync)(root)) continue;
33639
+ if (!(0, import_fs67.existsSync)(root)) continue;
33265
33640
  const canonRoot = canonicalize(root);
33266
33641
  const allExcl = [...exclusions, ...expandTmpVariants(sentinelDir)];
33267
33642
  const args = buildFindPruneArgs(canonRoot, allExcl, sentinel);
@@ -33297,7 +33672,7 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
33297
33672
  }
33298
33673
  const sensitiveTargets = buildSensitiveTargets(platform2);
33299
33674
  for (const target of sensitiveTargets) {
33300
- if (!(0, import_fs66.existsSync)(target.path)) continue;
33675
+ if (!(0, import_fs67.existsSync)(target.path)) continue;
33301
33676
  const canonTarget = canonicalize(target.path);
33302
33677
  const args = buildSensitiveFindArgs(
33303
33678
  canonTarget,
@@ -33353,8 +33728,8 @@ function auditFilesystemSinceSentinel(projectRoot, meta3, options = {}) {
33353
33728
  }
33354
33729
  function recordLayer3Violations(projectRoot, meta3, violations, source) {
33355
33730
  try {
33356
- const dir = (0, import_path71.join)(projectRoot, ".gossip");
33357
- (0, import_fs66.mkdirSync)(dir, { recursive: true });
33731
+ const dir = (0, import_path72.join)(projectRoot, ".gossip");
33732
+ (0, import_fs67.mkdirSync)(dir, { recursive: true });
33358
33733
  const ts2 = (/* @__PURE__ */ new Date()).toISOString();
33359
33734
  const lines = violations.map(
33360
33735
  (path7) => JSON.stringify({
@@ -33365,9 +33740,9 @@ function recordLayer3Violations(projectRoot, meta3, violations, source) {
33365
33740
  source
33366
33741
  })
33367
33742
  );
33368
- const escapeFile = (0, import_path71.join)(dir, BOUNDARY_ESCAPE_FILE);
33743
+ const escapeFile = (0, import_path72.join)(dir, BOUNDARY_ESCAPE_FILE);
33369
33744
  rotateIfNeeded2(escapeFile, MAX_BOUNDARY_ESCAPE_BYTES);
33370
- (0, import_fs66.appendFileSync)(escapeFile, lines.join("\n") + "\n");
33745
+ (0, import_fs67.appendFileSync)(escapeFile, lines.join("\n") + "\n");
33371
33746
  } catch {
33372
33747
  }
33373
33748
  if (source === "layer3-sensitive" && violations.length > 0) {
@@ -33424,14 +33799,14 @@ function runLayer3Audit(projectRoot, taskId) {
33424
33799
  }
33425
33800
  return { blockError, warnPrefix };
33426
33801
  }
33427
- var import_child_process10, import_fs66, import_os5, import_path71, 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, __test__;
33802
+ var import_child_process10, import_fs67, import_os5, import_path72, 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, __test__;
33428
33803
  var init_sandbox2 = __esm({
33429
33804
  "apps/cli/src/sandbox.ts"() {
33430
33805
  "use strict";
33431
33806
  import_child_process10 = require("child_process");
33432
- import_fs66 = require("fs");
33807
+ import_fs67 = require("fs");
33433
33808
  import_os5 = require("os");
33434
- import_path71 = require("path");
33809
+ import_path72 = require("path");
33435
33810
  METADATA_FILE = "dispatch-metadata.jsonl";
33436
33811
  BOUNDARY_ESCAPE_FILE = "boundary-escapes.jsonl";
33437
33812
  SENTINEL_DIR = "sentinels";
@@ -33502,7 +33877,7 @@ __export(dispatch_prompt_storage_exports, {
33502
33877
  writeDispatchPrompt: () => writeDispatchPrompt
33503
33878
  });
33504
33879
  function dispatchPromptsDir(projectRoot) {
33505
- return (0, import_path72.join)(projectRoot, ".gossip", DISPATCH_PROMPTS_SUBDIR);
33880
+ return (0, import_path73.join)(projectRoot, ".gossip", DISPATCH_PROMPTS_SUBDIR);
33506
33881
  }
33507
33882
  function assertSafeTaskId(taskId) {
33508
33883
  if (typeof taskId !== "string" || taskId.length === 0) {
@@ -33515,35 +33890,35 @@ function assertSafeTaskId(taskId) {
33515
33890
  function writeDispatchPrompt(projectRoot, taskId, body) {
33516
33891
  assertSafeTaskId(taskId);
33517
33892
  const dir = dispatchPromptsDir(projectRoot);
33518
- (0, import_fs67.mkdirSync)(dir, { recursive: true });
33519
- const finalPath = (0, import_path72.join)(dir, `${taskId}.txt`);
33520
- const tmpPath = (0, import_path72.join)(dir, `${taskId}.txt.${(0, import_crypto27.randomUUID)().slice(0, 8)}.tmp`);
33893
+ (0, import_fs68.mkdirSync)(dir, { recursive: true });
33894
+ const finalPath = (0, import_path73.join)(dir, `${taskId}.txt`);
33895
+ const tmpPath = (0, import_path73.join)(dir, `${taskId}.txt.${(0, import_crypto27.randomUUID)().slice(0, 8)}.tmp`);
33521
33896
  try {
33522
- (0, import_fs67.writeFileSync)(tmpPath, body, "utf8");
33523
- (0, import_fs67.renameSync)(tmpPath, finalPath);
33897
+ (0, import_fs68.writeFileSync)(tmpPath, body, "utf8");
33898
+ (0, import_fs68.renameSync)(tmpPath, finalPath);
33524
33899
  } catch (err) {
33525
33900
  try {
33526
- (0, import_fs67.unlinkSync)(tmpPath);
33901
+ (0, import_fs68.unlinkSync)(tmpPath);
33527
33902
  } catch {
33528
33903
  }
33529
33904
  throw err;
33530
33905
  }
33531
- return (0, import_path72.resolve)(finalPath);
33906
+ return (0, import_path73.resolve)(finalPath);
33532
33907
  }
33533
33908
  function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TTL_MS, capBytes = DISPATCH_PROMPT_CAP_BYTES) {
33534
33909
  const dir = dispatchPromptsDir(projectRoot);
33535
- if (!(0, import_fs67.existsSync)(dir)) return { evictedAge: 0, evictedCap: 0 };
33910
+ if (!(0, import_fs68.existsSync)(dir)) return { evictedAge: 0, evictedCap: 0 };
33536
33911
  const now = Date.now();
33537
33912
  let entries = [];
33538
33913
  try {
33539
- for (const name of (0, import_fs67.readdirSync)(dir)) {
33540
- const path7 = (0, import_path72.join)(dir, name);
33914
+ for (const name of (0, import_fs68.readdirSync)(dir)) {
33915
+ const path7 = (0, import_path73.join)(dir, name);
33541
33916
  try {
33542
- const st = (0, import_fs67.statSync)(path7);
33917
+ const st = (0, import_fs68.statSync)(path7);
33543
33918
  if (!st.isFile()) continue;
33544
33919
  entries.push({ name, path: path7, mtimeMs: st.mtimeMs, size: st.size });
33545
33920
  } catch (err) {
33546
- process.stderr.write(`[gossipcat] dispatch-prompt stat failed for ${(0, import_path72.basename)(path7)}: ${err.message}
33921
+ process.stderr.write(`[gossipcat] dispatch-prompt stat failed for ${(0, import_path73.basename)(path7)}: ${err.message}
33547
33922
  `);
33548
33923
  }
33549
33924
  }
@@ -33557,7 +33932,7 @@ function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TT
33557
33932
  for (const e of entries) {
33558
33933
  if (now - e.mtimeMs > maxAgeMs) {
33559
33934
  try {
33560
- (0, import_fs67.unlinkSync)(e.path);
33935
+ (0, import_fs68.unlinkSync)(e.path);
33561
33936
  evictedAge++;
33562
33937
  } catch (err) {
33563
33938
  process.stderr.write(`[gossipcat] dispatch-prompt unlink failed for ${e.name}: ${err.message}
@@ -33574,7 +33949,7 @@ function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TT
33574
33949
  for (const e of survivors) {
33575
33950
  if (totalBytes <= capBytes) break;
33576
33951
  try {
33577
- (0, import_fs67.unlinkSync)(e.path);
33952
+ (0, import_fs68.unlinkSync)(e.path);
33578
33953
  totalBytes -= e.size;
33579
33954
  evictedCap++;
33580
33955
  } catch (err) {
@@ -33587,18 +33962,18 @@ function cleanupExpiredDispatchPrompts(projectRoot, maxAgeMs = DEFAULT_PROMPT_TT
33587
33962
  }
33588
33963
  function pruneOrphanDispatchPrompts(projectRoot, knownTaskIds, maxAgeMs = DEFAULT_PROMPT_TTL_MS) {
33589
33964
  const dir = dispatchPromptsDir(projectRoot);
33590
- if (!(0, import_fs67.existsSync)(dir)) return { orphans: 0, aged: 0 };
33965
+ if (!(0, import_fs68.existsSync)(dir)) return { orphans: 0, aged: 0 };
33591
33966
  const now = Date.now();
33592
33967
  let orphans = 0;
33593
33968
  let aged = 0;
33594
33969
  try {
33595
- for (const name of (0, import_fs67.readdirSync)(dir)) {
33970
+ for (const name of (0, import_fs68.readdirSync)(dir)) {
33596
33971
  if (!name.endsWith(".txt")) continue;
33597
33972
  const taskId = name.slice(0, -4);
33598
- const path7 = (0, import_path72.join)(dir, name);
33973
+ const path7 = (0, import_path73.join)(dir, name);
33599
33974
  let mtimeMs = 0;
33600
33975
  try {
33601
- mtimeMs = (0, import_fs67.statSync)(path7).mtimeMs;
33976
+ mtimeMs = (0, import_fs68.statSync)(path7).mtimeMs;
33602
33977
  } catch {
33603
33978
  continue;
33604
33979
  }
@@ -33606,7 +33981,7 @@ function pruneOrphanDispatchPrompts(projectRoot, knownTaskIds, maxAgeMs = DEFAUL
33606
33981
  const orphaned = !knownTaskIds.has(taskId);
33607
33982
  if (tooOld || orphaned) {
33608
33983
  try {
33609
- (0, import_fs67.unlinkSync)(path7);
33984
+ (0, import_fs68.unlinkSync)(path7);
33610
33985
  if (orphaned) orphans++;
33611
33986
  if (tooOld) aged++;
33612
33987
  } catch (err) {
@@ -33623,14 +33998,14 @@ function pruneOrphanDispatchPrompts(projectRoot, knownTaskIds, maxAgeMs = DEFAUL
33623
33998
  }
33624
33999
  function dispatchPromptPath(projectRoot, taskId) {
33625
34000
  assertSafeTaskId(taskId);
33626
- return (0, import_path72.resolve)((0, import_path72.join)(dispatchPromptsDir(projectRoot), `${taskId}.txt`));
34001
+ return (0, import_path73.resolve)((0, import_path73.join)(dispatchPromptsDir(projectRoot), `${taskId}.txt`));
33627
34002
  }
33628
- var import_fs67, import_path72, import_crypto27, SAFE_TASK_ID, DISPATCH_PROMPT_CAP_BYTES, DEFAULT_PROMPT_TTL_MS, DISPATCH_PROMPTS_SUBDIR;
34003
+ var import_fs68, import_path73, import_crypto27, SAFE_TASK_ID, DISPATCH_PROMPT_CAP_BYTES, DEFAULT_PROMPT_TTL_MS, DISPATCH_PROMPTS_SUBDIR;
33629
34004
  var init_dispatch_prompt_storage = __esm({
33630
34005
  "apps/cli/src/handlers/dispatch-prompt-storage.ts"() {
33631
34006
  "use strict";
33632
- import_fs67 = require("fs");
33633
- import_path72 = require("path");
34007
+ import_fs68 = require("fs");
34008
+ import_path73 = require("path");
33634
34009
  import_crypto27 = require("crypto");
33635
34010
  SAFE_TASK_ID = /^(?!.*\.\.)[A-Za-z0-9._-]{1,64}$/;
33636
34011
  DISPATCH_PROMPT_CAP_BYTES = 100 * 1024 * 1024;
@@ -33684,9 +34059,9 @@ function getCommitRange(preSha, postSha) {
33684
34059
  function appendViolationRecord(record2) {
33685
34060
  try {
33686
34061
  const projectRoot = process.cwd();
33687
- (0, import_fs68.mkdirSync)((0, import_path73.join)(projectRoot, ".gossip"), { recursive: true });
33688
- const logPath = (0, import_path73.join)(projectRoot, PROCESS_VIOLATIONS_FILE);
33689
- (0, import_fs68.appendFileSync)(logPath, JSON.stringify(record2) + "\n", "utf8");
34062
+ (0, import_fs69.mkdirSync)((0, import_path74.join)(projectRoot, ".gossip"), { recursive: true });
34063
+ const logPath = (0, import_path74.join)(projectRoot, PROCESS_VIOLATIONS_FILE);
34064
+ (0, import_fs69.appendFileSync)(logPath, JSON.stringify(record2) + "\n", "utf8");
33690
34065
  } catch (err) {
33691
34066
  process.stderr.write(`[gossipcat] ref-allowlist: failed to append violation record: ${err.message}
33692
34067
  `);
@@ -33736,12 +34111,12 @@ Full audit trail at .gossip/process-violations.jsonl
33736
34111
  `
33737
34112
  );
33738
34113
  }
33739
- var import_fs68, import_path73, import_child_process11, PROCESS_VIOLATIONS_FILE;
34114
+ var import_fs69, import_path74, import_child_process11, PROCESS_VIOLATIONS_FILE;
33740
34115
  var init_ref_allowlist_detection = __esm({
33741
34116
  "apps/cli/src/handlers/ref-allowlist-detection.ts"() {
33742
34117
  "use strict";
33743
- import_fs68 = require("fs");
33744
- import_path73 = require("path");
34118
+ import_fs69 = require("fs");
34119
+ import_path74 = require("path");
33745
34120
  import_child_process11 = require("child_process");
33746
34121
  PROCESS_VIOLATIONS_FILE = ".gossip/process-violations.jsonl";
33747
34122
  }
@@ -33827,10 +34202,10 @@ function taskWasInConsensusRound(taskId, agentId, rounds, recentTaskIds, recentA
33827
34202
  function appendRelayWarning(projectRoot, entry) {
33828
34203
  try {
33829
34204
  const { appendFileSync: appendFileSync21, mkdirSync: mkdirSync41 } = require("fs");
33830
- const { join: join82 } = require("path");
33831
- const dir = join82(projectRoot, ".gossip");
34205
+ const { join: join83 } = require("path");
34206
+ const dir = join83(projectRoot, ".gossip");
33832
34207
  mkdirSync41(dir, { recursive: true });
33833
- appendFileSync21(join82(dir, RELAY_WARNINGS_FILE), JSON.stringify(entry) + "\n", "utf8");
34208
+ appendFileSync21(join83(dir, RELAY_WARNINGS_FILE), JSON.stringify(entry) + "\n", "utf8");
33834
34209
  } catch (err) {
33835
34210
  process.stderr.write(`[gossipcat] append relay-warning failed: ${err.message}
33836
34211
  `);
@@ -34557,7 +34932,7 @@ function computeSkillFingerprint(paths) {
34557
34932
  const pairs = [];
34558
34933
  for (const p of paths) {
34559
34934
  try {
34560
- const st = (0, import_fs69.statSync)(p);
34935
+ const st = (0, import_fs70.statSync)(p);
34561
34936
  pairs.push(`${p}:${st.mtimeMs}`);
34562
34937
  } catch {
34563
34938
  }
@@ -34592,7 +34967,7 @@ function setCachedPrompt(k, e) {
34592
34967
  const evicted = promptCache.get(oldestKey);
34593
34968
  promptCache.delete(oldestKey);
34594
34969
  try {
34595
- (0, import_fs69.unlinkSync)(evicted.skillsSectionPath);
34970
+ (0, import_fs70.unlinkSync)(evicted.skillsSectionPath);
34596
34971
  } catch {
34597
34972
  }
34598
34973
  const evictedAgentId = oldestKey.split("|")[0] ?? "_system";
@@ -34606,7 +34981,7 @@ function invalidateAgent(agentId) {
34606
34981
  if (k.startsWith(`${agentId}|`)) {
34607
34982
  promptCache.delete(k);
34608
34983
  try {
34609
- (0, import_fs69.unlinkSync)(v.skillsSectionPath);
34984
+ (0, import_fs70.unlinkSync)(v.skillsSectionPath);
34610
34985
  } catch {
34611
34986
  }
34612
34987
  emitCacheEvictedSignal(agentId, "invalidation");
@@ -34619,7 +34994,7 @@ function invalidateAll() {
34619
34994
  const n = promptCache.size;
34620
34995
  for (const v of promptCache.values()) {
34621
34996
  try {
34622
- (0, import_fs69.unlinkSync)(v.skillsSectionPath);
34997
+ (0, import_fs70.unlinkSync)(v.skillsSectionPath);
34623
34998
  } catch {
34624
34999
  }
34625
35000
  }
@@ -34666,29 +35041,29 @@ function writeCachedSkillsSection(projectRoot, fingerprint2, skillsSection) {
34666
35041
  if (!/^[a-f0-9]{64}$/.test(fingerprint2)) {
34667
35042
  throw new Error(`writeCachedSkillsSection: invalid fingerprint ${JSON.stringify(fingerprint2).slice(0, 32)}`);
34668
35043
  }
34669
- const dir = (0, import_path74.join)(projectRoot, ".gossip", "dispatch-prompts", "cache");
34670
- (0, import_fs69.mkdirSync)(dir, { recursive: true });
34671
- const finalPath = (0, import_path74.join)(dir, `skills-${fingerprint2}.txt`);
34672
- const tmpPath = (0, import_path74.join)(dir, `skills-${fingerprint2}.txt.${(0, import_crypto30.randomUUID)().slice(0, 8)}.tmp`);
35044
+ const dir = (0, import_path75.join)(projectRoot, ".gossip", "dispatch-prompts", "cache");
35045
+ (0, import_fs70.mkdirSync)(dir, { recursive: true });
35046
+ const finalPath = (0, import_path75.join)(dir, `skills-${fingerprint2}.txt`);
35047
+ const tmpPath = (0, import_path75.join)(dir, `skills-${fingerprint2}.txt.${(0, import_crypto30.randomUUID)().slice(0, 8)}.tmp`);
34673
35048
  try {
34674
- (0, import_fs69.writeFileSync)(tmpPath, skillsSection, "utf8");
34675
- (0, import_fs69.renameSync)(tmpPath, finalPath);
35049
+ (0, import_fs70.writeFileSync)(tmpPath, skillsSection, "utf8");
35050
+ (0, import_fs70.renameSync)(tmpPath, finalPath);
34676
35051
  } catch (err) {
34677
35052
  try {
34678
- (0, import_fs69.unlinkSync)(tmpPath);
35053
+ (0, import_fs70.unlinkSync)(tmpPath);
34679
35054
  } catch {
34680
35055
  }
34681
35056
  throw err;
34682
35057
  }
34683
- return (0, import_path74.resolve)(finalPath);
35058
+ return (0, import_path75.resolve)(finalPath);
34684
35059
  }
34685
- var import_crypto29, import_fs69, import_path74, import_crypto30, DISPATCH_PROMPT_CACHE_MAX_ENTRIES, promptCache;
35060
+ var import_crypto29, import_fs70, import_path75, import_crypto30, DISPATCH_PROMPT_CACHE_MAX_ENTRIES, promptCache;
34686
35061
  var init_dispatch_prompt_cache = __esm({
34687
35062
  "apps/cli/src/handlers/dispatch-prompt-cache.ts"() {
34688
35063
  "use strict";
34689
35064
  import_crypto29 = require("crypto");
34690
- import_fs69 = require("fs");
34691
- import_path74 = require("path");
35065
+ import_fs70 = require("fs");
35066
+ import_path75 = require("path");
34692
35067
  import_crypto30 = require("crypto");
34693
35068
  DISPATCH_PROMPT_CACHE_MAX_ENTRIES = 64;
34694
35069
  promptCache = /* @__PURE__ */ new Map();
@@ -34711,18 +35086,18 @@ __export(config_exports, {
34711
35086
  function findConfigPath(projectRoot) {
34712
35087
  const root = projectRoot || process.cwd();
34713
35088
  const candidates = [
34714
- (0, import_path75.resolve)(root, ".gossip", "config.json"),
34715
- (0, import_path75.resolve)(root, "gossip.agents.json"),
34716
- (0, import_path75.resolve)(root, "gossip.agents.yaml"),
34717
- (0, import_path75.resolve)(root, "gossip.agents.yml")
35089
+ (0, import_path76.resolve)(root, ".gossip", "config.json"),
35090
+ (0, import_path76.resolve)(root, "gossip.agents.json"),
35091
+ (0, import_path76.resolve)(root, "gossip.agents.yaml"),
35092
+ (0, import_path76.resolve)(root, "gossip.agents.yml")
34718
35093
  ];
34719
35094
  for (const p of candidates) {
34720
- if ((0, import_fs70.existsSync)(p)) return p;
35095
+ if ((0, import_fs71.existsSync)(p)) return p;
34721
35096
  }
34722
35097
  return null;
34723
35098
  }
34724
35099
  function loadConfig(configPath) {
34725
- const raw = (0, import_fs70.readFileSync)(configPath, "utf-8");
35100
+ const raw = (0, import_fs71.readFileSync)(configPath, "utf-8");
34726
35101
  let parsed;
34727
35102
  try {
34728
35103
  parsed = JSON.parse(raw);
@@ -34812,19 +35187,19 @@ function configToAgentConfigs(config2) {
34812
35187
  }
34813
35188
  function loadClaudeSubagents(projectRoot, existingIds) {
34814
35189
  const root = projectRoot || process.cwd();
34815
- const agentsDir = (0, import_path75.join)(root, ".claude", "agents");
34816
- if (!(0, import_fs70.existsSync)(agentsDir)) return [];
35190
+ const agentsDir = (0, import_path76.join)(root, ".claude", "agents");
35191
+ if (!(0, import_fs71.existsSync)(agentsDir)) return [];
34817
35192
  let files;
34818
35193
  try {
34819
- files = (0, import_fs70.readdirSync)(agentsDir).filter((f) => f.endsWith(".md"));
35194
+ files = (0, import_fs71.readdirSync)(agentsDir).filter((f) => f.endsWith(".md"));
34820
35195
  } catch {
34821
35196
  return [];
34822
35197
  }
34823
35198
  const agents = [];
34824
35199
  for (const file2 of files) {
34825
- const filePath = (0, import_path75.join)(agentsDir, file2);
35200
+ const filePath = (0, import_path76.join)(agentsDir, file2);
34826
35201
  try {
34827
- const content = (0, import_fs70.readFileSync)(filePath, "utf-8");
35202
+ const content = (0, import_fs71.readFileSync)(filePath, "utf-8");
34828
35203
  const frontmatter = content.match(/^---\n([\s\S]*?)\n---/);
34829
35204
  if (!frontmatter) continue;
34830
35205
  const fm = frontmatter[1];
@@ -34879,12 +35254,12 @@ function inferSkills(description, name) {
34879
35254
  if (skills.length === 0) skills.push("general");
34880
35255
  return skills;
34881
35256
  }
34882
- var import_fs70, import_path75, VALID_PROVIDERS, VALID_MAIN_PROVIDERS, CLAUDE_MODEL_MAP;
35257
+ var import_fs71, import_path76, VALID_PROVIDERS, VALID_MAIN_PROVIDERS, CLAUDE_MODEL_MAP;
34883
35258
  var init_config = __esm({
34884
35259
  "apps/cli/src/config.ts"() {
34885
35260
  "use strict";
34886
- import_fs70 = require("fs");
34887
- import_path75 = require("path");
35261
+ import_fs71 = require("fs");
35262
+ import_path76 = require("path");
34888
35263
  VALID_PROVIDERS = ["anthropic", "openai", "openclaw", "google", "local", "native", "none"];
34889
35264
  VALID_MAIN_PROVIDERS = VALID_PROVIDERS.filter((p) => p !== "native");
34890
35265
  CLAUDE_MODEL_MAP = {
@@ -34954,11 +35329,11 @@ function startConsensusTimeout(consensusId) {
34954
35329
  const report = await engine.synthesizeWithCrossReview(snapshot.allResults, allEntries, consensusId, snapshot.relayCrossReviewSkipped);
34955
35330
  try {
34956
35331
  const { writeFileSync: writeFileSync34, mkdirSync: mkdirSync41 } = require("fs");
34957
- const { join: join82 } = require("path");
34958
- const reportsDir = join82(process.cwd(), ".gossip", "consensus-reports");
35332
+ const { join: join83 } = require("path");
35333
+ const reportsDir = join83(process.cwd(), ".gossip", "consensus-reports");
34959
35334
  mkdirSync41(reportsDir, { recursive: true });
34960
35335
  const topic = snapshot.allResults?.find((r) => r.task)?.task?.slice(0, 500) || "";
34961
- writeFileSync34(join82(reportsDir, `${consensusId}.json`), JSON.stringify({
35336
+ writeFileSync34(join83(reportsDir, `${consensusId}.json`), JSON.stringify({
34962
35337
  id: consensusId,
34963
35338
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
34964
35339
  topic,
@@ -35126,10 +35501,10 @@ async function handleRelayCrossReview(consensus_id, agent_id, result) {
35126
35501
  );
35127
35502
  try {
35128
35503
  const { writeFileSync: writeFileSync34, mkdirSync: mkdirSync41 } = require("fs");
35129
- const { join: join82 } = require("path");
35130
- const reportsDir = join82(process.cwd(), ".gossip", "consensus-reports");
35504
+ const { join: join83 } = require("path");
35505
+ const reportsDir = join83(process.cwd(), ".gossip", "consensus-reports");
35131
35506
  mkdirSync41(reportsDir, { recursive: true });
35132
- const reportPath = join82(reportsDir, `${consensus_id}.json`);
35507
+ const reportPath = join83(reportsDir, `${consensus_id}.json`);
35133
35508
  const topic = synthSnapshot.allResults?.find((r) => r.task)?.task?.slice(0, 500) || "";
35134
35509
  writeFileSync34(reportPath, JSON.stringify({
35135
35510
  id: consensus_id,
@@ -35175,8 +35550,8 @@ function persistPendingConsensus() {
35175
35550
  const projectRoot = ctx.mainAgent?.projectRoot;
35176
35551
  if (!projectRoot) return;
35177
35552
  const { writeFileSync: writeFileSync34, mkdirSync: mkdirSync41 } = require("fs");
35178
- const { join: join82 } = require("path");
35179
- const dir = join82(projectRoot, ".gossip");
35553
+ const { join: join83 } = require("path");
35554
+ const dir = join83(projectRoot, ".gossip");
35180
35555
  mkdirSync41(dir, { recursive: true });
35181
35556
  const rounds = {};
35182
35557
  for (const [id, round] of ctx.pendingConsensusRounds) {
@@ -35202,7 +35577,7 @@ function persistPendingConsensus() {
35202
35577
  resolutionRoots: round.resolutionRoots ? [...round.resolutionRoots] : void 0
35203
35578
  };
35204
35579
  }
35205
- writeFileSync34(join82(dir, CONSENSUS_FILE), JSON.stringify(rounds));
35580
+ writeFileSync34(join83(dir, CONSENSUS_FILE), JSON.stringify(rounds));
35206
35581
  } catch (err) {
35207
35582
  process.stderr.write(`[gossipcat] persistPendingConsensus failed: ${err.message}
35208
35583
  `);
@@ -35210,11 +35585,11 @@ function persistPendingConsensus() {
35210
35585
  }
35211
35586
  function restorePendingConsensus(projectRoot) {
35212
35587
  try {
35213
- const { existsSync: existsSync69, readFileSync: readFileSync62, unlinkSync: unlinkSync13 } = require("fs");
35214
- const { join: join82 } = require("path");
35215
- const filePath = join82(projectRoot, ".gossip", CONSENSUS_FILE);
35216
- if (!existsSync69(filePath)) return;
35217
- const raw = JSON.parse(readFileSync62(filePath, "utf-8"));
35588
+ const { existsSync: existsSync70, readFileSync: readFileSync64, unlinkSync: unlinkSync13 } = require("fs");
35589
+ const { join: join83 } = require("path");
35590
+ const filePath = join83(projectRoot, ".gossip", CONSENSUS_FILE);
35591
+ if (!existsSync70(filePath)) return;
35592
+ const raw = JSON.parse(readFileSync64(filePath, "utf-8"));
35218
35593
  const now = Date.now();
35219
35594
  for (const [id, data] of Object.entries(raw)) {
35220
35595
  if (now > data.deadline + 3e5) {
@@ -35322,31 +35697,31 @@ __export(check_effectiveness_runner_exports, {
35322
35697
  runCheckEffectivenessForAllSkills: () => runCheckEffectivenessForAllSkills
35323
35698
  });
35324
35699
  function writeHealthAtomic(projectRoot, record2) {
35325
- const dir = (0, import_path77.join)(projectRoot, ".gossip");
35326
- const finalPath = (0, import_path77.join)(dir, "skill-runner-health.json");
35700
+ const dir = (0, import_path78.join)(projectRoot, ".gossip");
35701
+ const finalPath = (0, import_path78.join)(dir, "skill-runner-health.json");
35327
35702
  const tmpPath = finalPath + ".tmp";
35328
35703
  try {
35329
- (0, import_fs73.mkdirSync)(dir, { recursive: true });
35330
- (0, import_fs73.writeFileSync)(tmpPath, JSON.stringify(record2, null, 2));
35331
- (0, import_fs73.renameSync)(tmpPath, finalPath);
35704
+ (0, import_fs74.mkdirSync)(dir, { recursive: true });
35705
+ (0, import_fs74.writeFileSync)(tmpPath, JSON.stringify(record2, null, 2));
35706
+ (0, import_fs74.renameSync)(tmpPath, finalPath);
35332
35707
  } catch (e) {
35333
35708
  process.stderr.write(`[gossipcat] checkEffectiveness: health write failed: ${e.message}
35334
35709
  `);
35335
35710
  try {
35336
- if ((0, import_fs73.existsSync)(tmpPath)) (0, import_fs73.unlinkSync)(tmpPath);
35711
+ if ((0, import_fs74.existsSync)(tmpPath)) (0, import_fs74.unlinkSync)(tmpPath);
35337
35712
  } catch {
35338
35713
  }
35339
35714
  }
35340
35715
  }
35341
35716
  async function runCheckEffectivenessForAllSkills(opts) {
35342
35717
  const startedAt = Date.now();
35343
- const baseDir = (0, import_path77.join)(opts.projectRoot, ".gossip", "agents");
35718
+ const baseDir = (0, import_path78.join)(opts.projectRoot, ".gossip", "agents");
35344
35719
  let agentDirs = [];
35345
35720
  let canonicalBaseDir;
35346
- if ((0, import_fs73.existsSync)(baseDir)) {
35721
+ if ((0, import_fs74.existsSync)(baseDir)) {
35347
35722
  try {
35348
- canonicalBaseDir = (0, import_fs73.realpathSync)(baseDir);
35349
- agentDirs = (0, import_fs73.readdirSync)(canonicalBaseDir);
35723
+ canonicalBaseDir = (0, import_fs74.realpathSync)(baseDir);
35724
+ agentDirs = (0, import_fs74.readdirSync)(canonicalBaseDir);
35350
35725
  } catch {
35351
35726
  }
35352
35727
  }
@@ -35365,11 +35740,11 @@ async function runCheckEffectivenessForAllSkills(opts) {
35365
35740
  for (const agentId of agentDirs) {
35366
35741
  if (agentId.startsWith("_")) continue;
35367
35742
  if (!SAFE_NAME2.test(agentId)) continue;
35368
- const skillsDir = (0, import_path77.join)(canonicalBaseDir, agentId, "skills");
35369
- if (!(0, import_fs73.existsSync)(skillsDir)) continue;
35743
+ const skillsDir = (0, import_path78.join)(canonicalBaseDir, agentId, "skills");
35744
+ if (!(0, import_fs74.existsSync)(skillsDir)) continue;
35370
35745
  let canonicalSkillsDir;
35371
35746
  try {
35372
- canonicalSkillsDir = (0, import_fs73.realpathSync)(skillsDir);
35747
+ canonicalSkillsDir = (0, import_fs74.realpathSync)(skillsDir);
35373
35748
  } catch {
35374
35749
  continue;
35375
35750
  }
@@ -35380,7 +35755,7 @@ async function runCheckEffectivenessForAllSkills(opts) {
35380
35755
  }
35381
35756
  const role = opts.registryGet(agentId)?.role;
35382
35757
  if (role === "implementer") continue;
35383
- const files = (0, import_fs73.readdirSync)(canonicalSkillsDir).filter((f) => f.endsWith(".md"));
35758
+ const files = (0, import_fs74.readdirSync)(canonicalSkillsDir).filter((f) => f.endsWith(".md"));
35384
35759
  for (const file2 of files) {
35385
35760
  const category = file2.replace(/\.md$/, "");
35386
35761
  if (!SAFE_NAME2.test(category)) continue;
@@ -35427,12 +35802,12 @@ async function runCheckEffectivenessForAllSkills(opts) {
35427
35802
  last_error: lastError
35428
35803
  });
35429
35804
  }
35430
- var import_fs73, import_path77, SAFE_NAME2;
35805
+ var import_fs74, import_path78, SAFE_NAME2;
35431
35806
  var init_check_effectiveness_runner = __esm({
35432
35807
  "apps/cli/src/handlers/check-effectiveness-runner.ts"() {
35433
35808
  "use strict";
35434
- import_fs73 = require("fs");
35435
- import_path77 = require("path");
35809
+ import_fs74 = require("fs");
35810
+ import_path78 = require("path");
35436
35811
  init_dispatch_prompt_cache();
35437
35812
  SAFE_NAME2 = /^(?!.*\.\.)[a-zA-Z0-9._-]+$/;
35438
35813
  }
@@ -35445,20 +35820,20 @@ __export(skill_develop_audit_exports, {
35445
35820
  });
35446
35821
  function appendSkillDevelopAudit(entry) {
35447
35822
  try {
35448
- const gossipDir = (0, import_path78.join)(process.cwd(), ".gossip");
35449
- (0, import_fs74.mkdirSync)(gossipDir, { recursive: true });
35823
+ const gossipDir = (0, import_path79.join)(process.cwd(), ".gossip");
35824
+ (0, import_fs75.mkdirSync)(gossipDir, { recursive: true });
35450
35825
  const line = JSON.stringify(entry) + "\n";
35451
- (0, import_fs74.appendFileSync)((0, import_path78.join)(gossipDir, AUDIT_FILE2), line);
35452
- (0, import_fs74.appendFileSync)((0, import_path78.join)(gossipDir, LEGACY_FILE), line);
35826
+ (0, import_fs75.appendFileSync)((0, import_path79.join)(gossipDir, AUDIT_FILE2), line);
35827
+ (0, import_fs75.appendFileSync)((0, import_path79.join)(gossipDir, LEGACY_FILE), line);
35453
35828
  } catch {
35454
35829
  }
35455
35830
  }
35456
- var import_fs74, import_path78, AUDIT_FILE2, LEGACY_FILE;
35831
+ var import_fs75, import_path79, AUDIT_FILE2, LEGACY_FILE;
35457
35832
  var init_skill_develop_audit = __esm({
35458
35833
  "apps/cli/src/handlers/skill-develop-audit.ts"() {
35459
35834
  "use strict";
35460
- import_fs74 = require("fs");
35461
- import_path78 = require("path");
35835
+ import_fs75 = require("fs");
35836
+ import_path79 = require("path");
35462
35837
  AUDIT_FILE2 = "skill-develop-audit.jsonl";
35463
35838
  LEGACY_FILE = "forced-skill-develops.jsonl";
35464
35839
  }
@@ -35469,14 +35844,14 @@ var keychain_exports = {};
35469
35844
  __export(keychain_exports, {
35470
35845
  Keychain: () => Keychain
35471
35846
  });
35472
- var import_child_process12, import_os6, import_fs78, import_path82, import_crypto32, DEFAULT_SERVICE_NAME, VALID_PROVIDERS2, ENCRYPTED_FILE, ALGO, Keychain;
35847
+ var import_child_process12, import_os6, import_fs79, import_path83, import_crypto32, DEFAULT_SERVICE_NAME, VALID_PROVIDERS2, ENCRYPTED_FILE, ALGO, Keychain;
35473
35848
  var init_keychain = __esm({
35474
35849
  "apps/cli/src/keychain.ts"() {
35475
35850
  "use strict";
35476
35851
  import_child_process12 = require("child_process");
35477
35852
  import_os6 = require("os");
35478
- import_fs78 = require("fs");
35479
- import_path82 = require("path");
35853
+ import_fs79 = require("fs");
35854
+ import_path83 = require("path");
35480
35855
  import_crypto32 = require("crypto");
35481
35856
  DEFAULT_SERVICE_NAME = "gossip-mesh";
35482
35857
  VALID_PROVIDERS2 = /^[a-zA-Z0-9_-]{1,32}$/;
@@ -35520,10 +35895,10 @@ var init_keychain = __esm({
35520
35895
  return (0, import_crypto32.pbkdf2Sync)(seed, salt, 6e5, 32, "sha256");
35521
35896
  }
35522
35897
  loadEncryptedFile() {
35523
- const filePath = (0, import_path82.join)(process.cwd(), ENCRYPTED_FILE);
35524
- if (!(0, import_fs78.existsSync)(filePath)) return;
35898
+ const filePath = (0, import_path83.join)(process.cwd(), ENCRYPTED_FILE);
35899
+ if (!(0, import_fs79.existsSync)(filePath)) return;
35525
35900
  try {
35526
- const raw = (0, import_fs78.readFileSync)(filePath);
35901
+ const raw = (0, import_fs79.readFileSync)(filePath);
35527
35902
  if (raw.length < 61) return;
35528
35903
  const salt = raw.subarray(0, 32);
35529
35904
  const iv = raw.subarray(32, 44);
@@ -35541,9 +35916,9 @@ var init_keychain = __esm({
35541
35916
  }
35542
35917
  }
35543
35918
  saveEncryptedFile() {
35544
- const filePath = (0, import_path82.join)(process.cwd(), ENCRYPTED_FILE);
35545
- const dir = (0, import_path82.join)(process.cwd(), ".gossip");
35546
- if (!(0, import_fs78.existsSync)(dir)) (0, import_fs78.mkdirSync)(dir, { recursive: true });
35919
+ const filePath = (0, import_path83.join)(process.cwd(), ENCRYPTED_FILE);
35920
+ const dir = (0, import_path83.join)(process.cwd(), ".gossip");
35921
+ if (!(0, import_fs79.existsSync)(dir)) (0, import_fs79.mkdirSync)(dir, { recursive: true });
35547
35922
  const data = JSON.stringify(Object.fromEntries(this.inMemoryStore));
35548
35923
  const salt = (0, import_crypto32.randomBytes)(32);
35549
35924
  const iv = (0, import_crypto32.randomBytes)(12);
@@ -35551,7 +35926,7 @@ var init_keychain = __esm({
35551
35926
  const cipher = (0, import_crypto32.createCipheriv)(ALGO, key, iv);
35552
35927
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
35553
35928
  const tag = cipher.getAuthTag();
35554
- (0, import_fs78.writeFileSync)(filePath, Buffer.concat([salt, iv, tag, encrypted]), { mode: 384 });
35929
+ (0, import_fs79.writeFileSync)(filePath, Buffer.concat([salt, iv, tag, encrypted]), { mode: 384 });
35555
35930
  }
35556
35931
  isKeychainAvailable() {
35557
35932
  if ((0, import_os6.platform)() === "darwin") {
@@ -35651,17 +36026,17 @@ __export(identity_exports, {
35651
36026
  normalizeGitUrl: () => normalizeGitUrl
35652
36027
  });
35653
36028
  function getOrCreateSalt(projectRoot) {
35654
- const saltPath = (0, import_path83.join)(projectRoot, ".gossip", "local-salt");
36029
+ const saltPath = (0, import_path84.join)(projectRoot, ".gossip", "local-salt");
35655
36030
  try {
35656
- return (0, import_fs79.readFileSync)(saltPath, "utf-8").trim();
36031
+ return (0, import_fs80.readFileSync)(saltPath, "utf-8").trim();
35657
36032
  } catch {
35658
36033
  const salt = (0, import_crypto33.randomBytes)(16).toString("hex");
35659
- (0, import_fs79.mkdirSync)((0, import_path83.join)(projectRoot, ".gossip"), { recursive: true });
36034
+ (0, import_fs80.mkdirSync)((0, import_path84.join)(projectRoot, ".gossip"), { recursive: true });
35660
36035
  try {
35661
- (0, import_fs79.writeFileSync)(saltPath, salt, { flag: "wx" });
36036
+ (0, import_fs80.writeFileSync)(saltPath, salt, { flag: "wx" });
35662
36037
  return salt;
35663
36038
  } catch {
35664
- return (0, import_fs79.readFileSync)(saltPath, "utf-8").trim();
36039
+ return (0, import_fs80.readFileSync)(saltPath, "utf-8").trim();
35665
36040
  }
35666
36041
  }
35667
36042
  }
@@ -35711,12 +36086,12 @@ function getProjectId(projectRoot) {
35711
36086
  }
35712
36087
  return (0, import_crypto33.createHash)("sha256").update(projectRoot).digest("hex").slice(0, 16);
35713
36088
  }
35714
- var import_fs79, import_path83, import_crypto33, import_child_process13;
36089
+ var import_fs80, import_path84, import_crypto33, import_child_process13;
35715
36090
  var init_identity = __esm({
35716
36091
  "apps/cli/src/identity.ts"() {
35717
36092
  "use strict";
35718
- import_fs79 = require("fs");
35719
- import_path83 = require("path");
36093
+ import_fs80 = require("fs");
36094
+ import_path84 = require("path");
35720
36095
  import_crypto33 = require("crypto");
35721
36096
  import_child_process13 = require("child_process");
35722
36097
  }
@@ -35738,9 +36113,9 @@ async function getLatestVersion() {
35738
36113
  return data.version;
35739
36114
  }
35740
36115
  function detectInstallMethod() {
35741
- const packageRoot = (0, import_path84.resolve)(__dirname, "..", "..", "..", "..");
36116
+ const packageRoot = (0, import_path85.resolve)(__dirname, "..", "..", "..", "..");
35742
36117
  if (process.env.npm_config_global === "true") return "global";
35743
- if ((0, import_fs80.existsSync)((0, import_path84.join)(packageRoot, ".git"))) return "git-clone";
36118
+ if ((0, import_fs81.existsSync)((0, import_path85.join)(packageRoot, ".git"))) return "git-clone";
35744
36119
  return "local";
35745
36120
  }
35746
36121
  function updateCommand(method, version2) {
@@ -35795,7 +36170,7 @@ Check your internet connection or visit https://www.npmjs.com/package/gossipcat
35795
36170
  try {
35796
36171
  (0, import_child_process14.execSync)(command, {
35797
36172
  stdio: "inherit",
35798
- cwd: method === "git-clone" ? (0, import_path84.resolve)(__dirname, "..", "..", "..", "..") : process.cwd(),
36173
+ cwd: method === "git-clone" ? (0, import_path85.resolve)(__dirname, "..", "..", "..", "..") : process.cwd(),
35799
36174
  env: scrubbedEnv
35800
36175
  });
35801
36176
  } catch (err) {
@@ -35818,13 +36193,13 @@ Run /mcp reconnect in Claude Code to load the new version.`
35818
36193
  }]
35819
36194
  };
35820
36195
  }
35821
- var import_child_process14, import_fs80, import_path84;
36196
+ var import_child_process14, import_fs81, import_path85;
35822
36197
  var init_gossip_update = __esm({
35823
36198
  "apps/cli/src/handlers/gossip-update.ts"() {
35824
36199
  "use strict";
35825
36200
  import_child_process14 = require("child_process");
35826
- import_fs80 = require("fs");
35827
- import_path84 = require("path");
36201
+ import_fs81 = require("fs");
36202
+ import_path85 = require("path");
35828
36203
  init_version();
35829
36204
  }
35830
36205
  });
@@ -36035,8 +36410,8 @@ __export(mcp_server_sdk_exports, {
36035
36410
  createMcpServer: () => createMcpServer
36036
36411
  });
36037
36412
  module.exports = __toCommonJS(mcp_server_sdk_exports);
36038
- var import_fs81 = require("fs");
36039
- var import_path85 = require("path");
36413
+ var import_fs82 = require("fs");
36414
+ var import_path86 = require("path");
36040
36415
 
36041
36416
  // apps/cli/src/hook-run.ts
36042
36417
  var import_fs = require("fs");
@@ -49939,15 +50314,15 @@ init_native_tasks();
49939
50314
 
49940
50315
  // apps/cli/src/handlers/dispatch.ts
49941
50316
  var import_crypto31 = require("crypto");
49942
- var import_fs71 = require("fs");
49943
- var import_path76 = require("path");
50317
+ var import_fs72 = require("fs");
50318
+ var import_path77 = require("path");
49944
50319
  init_src4();
49945
50320
  init_src3();
49946
50321
  init_mcp_context();
49947
50322
  init_native_tasks();
49948
50323
  init_dispatch_prompt_storage();
49949
50324
  init_dispatch_prompt_cache();
49950
- var import_fs72 = require("fs");
50325
+ var import_fs73 = require("fs");
49951
50326
 
49952
50327
  // apps/cli/src/handlers/relay-tasks.ts
49953
50328
  init_mcp_context();
@@ -50040,10 +50415,16 @@ function stampConcurrencyTaint(map2) {
50040
50415
  }
50041
50416
  return true;
50042
50417
  }
50043
- function elidePromptIfRequested(projectRoot, taskId, agentPrompt, promptFormat, warmCached = false) {
50418
+ function elidePromptIfRequested(projectRoot, taskId, agentPrompt, promptFormat, warmCached = false, writeMode) {
50044
50419
  if (promptFormat !== "elided") return { elided: false };
50045
- const bytes = Buffer.byteLength(agentPrompt, "utf8");
50046
- const promptPath = writeDispatchPrompt(projectRoot, taskId, agentPrompt);
50420
+ const body = writeMode === "worktree" ? `// GOSSIP_ISOLATION: worktree
50421
+ // This task was dispatched with write_mode: "worktree".
50422
+ // The orchestrator MUST invoke Agent() with isolation: "worktree".
50423
+ // Do not paraphrase this requirement.
50424
+
50425
+ ` + agentPrompt : agentPrompt;
50426
+ const bytes = Buffer.byteLength(body, "utf8");
50427
+ const promptPath = writeDispatchPrompt(projectRoot, taskId, body);
50047
50428
  const warmSuffix = warmCached ? " \u2014 warm-cached (skills) + live task" : "";
50048
50429
  const marker = `[skills section elided: see ${promptPath}, ${bytes} bytes${warmSuffix} \u2014 READ this file and pass its CONTENTS verbatim as the Agent(prompt: ...) value. Do NOT pass the path string.]`;
50049
50430
  return { elided: true, promptPath, marker, bytes };
@@ -50054,7 +50435,7 @@ function tryWarmCacheHit(liveTaskBlock, cacheKey, promptFormat) {
50054
50435
  const cached4 = getCachedPrompt(cacheKey);
50055
50436
  if (!cached4) return null;
50056
50437
  if (cached4.skillFingerprint !== cacheKey.skillFingerprint) return null;
50057
- if (!(0, import_fs72.existsSync)(cached4.skillsSectionPath)) return null;
50438
+ if (!(0, import_fs73.existsSync)(cached4.skillsSectionPath)) return null;
50058
50439
  try {
50059
50440
  const skillsSection = require("fs").readFileSync(cached4.skillsSectionPath, "utf8");
50060
50441
  return skillsSection + liveTaskBlock;
@@ -50131,9 +50512,9 @@ function formatFalsifiedNote(block, verdicts) {
50131
50512
  }
50132
50513
  function writePremiseVerificationLog(projectRoot, taskId, result, opts) {
50133
50514
  try {
50134
- const logPath = (0, import_path76.join)(projectRoot, PREMISE_VERIFICATION_LOG);
50515
+ const logPath = (0, import_path77.join)(projectRoot, PREMISE_VERIFICATION_LOG);
50135
50516
  rotateIfNeeded2(logPath, MAX_PREMISE_VERIFICATION_BYTES);
50136
- (0, import_fs71.mkdirSync)((0, import_path76.join)(projectRoot, ".gossip"), { recursive: true });
50517
+ (0, import_fs72.mkdirSync)((0, import_path77.join)(projectRoot, ".gossip"), { recursive: true });
50137
50518
  const row = {
50138
50519
  ts: (/* @__PURE__ */ new Date()).toISOString(),
50139
50520
  consensus_id: null,
@@ -50147,7 +50528,7 @@ function writePremiseVerificationLog(projectRoot, taskId, result, opts) {
50147
50528
  skill_bound: opts.skill_bound
50148
50529
  };
50149
50530
  if (opts.schema_lint) row.schema_lint = opts.schema_lint;
50150
- (0, import_fs71.appendFileSync)(logPath, JSON.stringify(row) + "\n");
50531
+ (0, import_fs72.appendFileSync)(logPath, JSON.stringify(row) + "\n");
50151
50532
  } catch {
50152
50533
  }
50153
50534
  }
@@ -50259,7 +50640,7 @@ var AGENT_PROVIDER_MAP = {
50259
50640
  };
50260
50641
  function readQuotaState() {
50261
50642
  try {
50262
- const raw = (0, import_fs71.readFileSync)((0, import_path76.join)(process.cwd(), ".gossip", "quota-state.json"), "utf8");
50643
+ const raw = (0, import_fs72.readFileSync)((0, import_path77.join)(process.cwd(), ".gossip", "quota-state.json"), "utf8");
50263
50644
  return JSON.parse(raw);
50264
50645
  } catch {
50265
50646
  return {};
@@ -50415,17 +50796,31 @@ Task: ${task}`;
50415
50796
  worktreePath: void 0,
50416
50797
  timestamp: Date.now()
50417
50798
  });
50418
- const elision = elidePromptIfRequested(process.cwd(), taskId, agentPrompt, prompt_format, singleWarm);
50799
+ const elision = elidePromptIfRequested(
50800
+ process.cwd(),
50801
+ taskId,
50802
+ agentPrompt,
50803
+ prompt_format,
50804
+ singleWarm,
50805
+ useWorktree ? "worktree" : void 0
50806
+ );
50419
50807
  if (elision.elided) {
50420
50808
  const info = ctx.nativeTaskMap.get(taskId);
50421
50809
  if (info) info.promptPath = elision.promptPath;
50422
50810
  }
50423
50811
  persistNativeTaskMap();
50812
+ const promptRef = elision.elided ? "<file contents>" : `<AGENT_PROMPT:${taskId} below>`;
50813
+ const agentCall = useWorktree ? `Agent(
50814
+ model: "${nativeConfig.model}",
50815
+ prompt: ${promptRef},
50816
+ isolation: "worktree", // REQUIRED \u2014 do not omit
50817
+ run_in_background: true
50818
+ )` : `Agent(model: "${nativeConfig.model}", prompt: ${promptRef}, run_in_background: true)`;
50424
50819
  const promptInstruction = elision.elided ? `Step 1 \u2014 ${elision.marker}
50425
- Agent(model: "${nativeConfig.model}", prompt: <file contents>${useWorktree ? ', isolation: "worktree"' : ""}, run_in_background: true)
50820
+ ${agentCall}
50426
50821
 
50427
50822
  ` : `Step 1 \u2014 Pass the AGENT_PROMPT:${taskId} content item below verbatim to Agent(prompt: ...):
50428
- Agent(model: "${nativeConfig.model}", prompt: <AGENT_PROMPT:${taskId} below>${useWorktree ? ', isolation: "worktree"' : ""}, run_in_background: true)
50823
+ ${agentCall}
50429
50824
 
50430
50825
  `;
50431
50826
  return { content: [
@@ -50437,8 +50832,10 @@ NATIVE_DISPATCH: Execute this via Claude Code Agent tool, then relay the result.
50437
50832
  Task ID: ${taskId}
50438
50833
  Agent: ${agent_id}
50439
50834
  Model: ${nativeConfig.model}
50835
+ ` + (useWorktree ? `Worktree isolation: REQUIRED \u2014 Agent() MUST be invoked with isolation: "worktree"
50440
50836
 
50441
- ` + promptInstruction + `Step 2 \u2014 REQUIRED after agent completes:
50837
+ ` : `
50838
+ `) + promptInstruction + `Step 2 \u2014 REQUIRED after agent completes:
50442
50839
  gossip_relay(task_id: "${taskId}", relay_token: "${relayToken}", result: "<agent output>")
50443
50840
  (VERBATIM \u2014 pass the agent's raw output; do NOT paraphrase or summarize, or <agent_finding> tags will be lost)
50444
50841
 
@@ -50680,15 +51077,24 @@ Task: ${def.task}`;
50680
51077
  worktreePath: void 0,
50681
51078
  timestamp: Date.now()
50682
51079
  });
50683
- const parallelElision = elidePromptIfRequested(process.cwd(), taskId, agentPrompt, prompt_format, parallelWarm);
51080
+ const parallelElision = elidePromptIfRequested(process.cwd(), taskId, agentPrompt, prompt_format, parallelWarm, def.write_mode);
50684
51081
  if (parallelElision.elided) {
50685
51082
  const info = ctx.nativeTaskMap.get(taskId);
50686
51083
  if (info) info.promptPath = parallelElision.promptPath;
50687
51084
  }
50688
51085
  const parallelPromptRef = parallelElision.elided ? parallelElision.marker : `<AGENT_PROMPT:${taskId} below>`;
51086
+ const parallelUseWorktree = def.write_mode === "worktree";
51087
+ const parallelWorktreeBanner = parallelUseWorktree ? `
51088
+ Worktree isolation: REQUIRED \u2014 Agent() MUST be invoked with isolation: "worktree"` : "";
51089
+ const parallelAgentCall = parallelUseWorktree ? `Agent(
51090
+ model: "${nativeConfig.model}",
51091
+ prompt: ${parallelPromptRef},
51092
+ isolation: "worktree", // REQUIRED \u2014 do not omit
51093
+ run_in_background: true
51094
+ )` : `Agent(model: "${nativeConfig.model}", prompt: ${parallelPromptRef}, run_in_background: true)`;
50689
51095
  lines.push(` ${taskId} \u2192 ${def.agent_id} (native \u2014 dispatch via Agent tool)`);
50690
51096
  nativeInstructions.push(
50691
- `[${taskId}] Agent(model: "${nativeConfig.model}", prompt: ${parallelPromptRef}${def.write_mode === "worktree" ? ', isolation: "worktree"' : ""}, run_in_background: true)
51097
+ `[${taskId}] ${parallelAgentCall}${parallelWorktreeBanner}
50692
51098
  \u2192 then: gossip_relay(task_id: "${taskId}", relay_token: "${relayToken}", result: "<output>")`
50693
51099
  );
50694
51100
  if (!parallelElision.elided) {
@@ -50898,16 +51304,25 @@ Task: ${def.task}`;
50898
51304
  }
50899
51305
  }
50900
51306
  agentPrompt = maybeApplyUnverifiedNote(agentPrompt, def.task, def.agent_id);
50901
- const consensusElision = elidePromptIfRequested(process.cwd(), taskId, agentPrompt, prompt_format, consensusWarm);
51307
+ const consensusElision = elidePromptIfRequested(process.cwd(), taskId, agentPrompt, prompt_format, consensusWarm, def.write_mode);
50902
51308
  if (consensusElision.elided) {
50903
51309
  const info = ctx.nativeTaskMap.get(taskId);
50904
51310
  if (info) info.promptPath = consensusElision.promptPath;
50905
51311
  persistNativeTaskMap();
50906
51312
  }
50907
51313
  const consensusPromptRef = consensusElision.elided ? consensusElision.marker : `<AGENT_PROMPT:${taskId} below>`;
51314
+ const consensusUseWorktree = def.write_mode === "worktree";
51315
+ const consensusWorktreeBanner = consensusUseWorktree ? `
51316
+ Worktree isolation: REQUIRED \u2014 Agent() MUST be invoked with isolation: "worktree"` : "";
51317
+ const consensusAgentCall = consensusUseWorktree ? `Agent(
51318
+ model: "${nativeConfig.model}",
51319
+ prompt: ${consensusPromptRef},
51320
+ isolation: "worktree", // REQUIRED \u2014 do not omit
51321
+ run_in_background: true
51322
+ )` : `Agent(model: "${nativeConfig.model}", prompt: ${consensusPromptRef}, run_in_background: true)`;
50908
51323
  lines.push(` ${taskId} \u2192 ${def.agent_id} (native \u2014 dispatch via Agent tool)`);
50909
51324
  nativeInstructions.push(
50910
- `[${taskId}] Agent(model: "${nativeConfig.model}", prompt: ${consensusPromptRef}, run_in_background: true)
51325
+ `[${taskId}] ${consensusAgentCall}${consensusWorktreeBanner}
50911
51326
  \u2192 then: gossip_relay(task_id: "${taskId}", relay_token: "${relayToken}", result: "<output>")`
50912
51327
  );
50913
51328
  if (!consensusElision.elided) {
@@ -51053,13 +51468,13 @@ function buildAutoVerifyDispatch(binding) {
51053
51468
  var _autoResolverErrors = /* @__PURE__ */ new Set();
51054
51469
  var _autoResolverLockWarned = false;
51055
51470
  var CONSENSUS_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{8}$/;
51056
- function isValidConsensusId(id) {
51471
+ function isValidConsensusId2(id) {
51057
51472
  return typeof id === "string" && CONSENSUS_ID_RE.test(id);
51058
51473
  }
51059
51474
  function extractConsensusIdFromFindingId(findingId) {
51060
51475
  if (typeof findingId !== "string") return void 0;
51061
51476
  const first = findingId.split(":")[0];
51062
- return isValidConsensusId(first) ? first : void 0;
51477
+ return isValidConsensusId2(first) ? first : void 0;
51063
51478
  }
51064
51479
  function reconcilerFindingsAll(consensusReport) {
51065
51480
  return [
@@ -51761,7 +52176,7 @@ ${np.user}
51761
52176
  ...consensusReport.unique || []
51762
52177
  ];
51763
52178
  const authoritativeId = consensusReport?.signals?.[0]?.consensusId;
51764
- const provisionalConsensusId = (isValidConsensusId(authoritativeId) ? authoritativeId : void 0) ?? (allFindings.length > 0 ? extractConsensusIdFromFindingId(allFindings[0].id) : void 0);
52179
+ const provisionalConsensusId = (isValidConsensusId2(authoritativeId) ? authoritativeId : void 0) ?? (allFindings.length > 0 ? extractConsensusIdFromFindingId(allFindings[0].id) : void 0);
51765
52180
  const provisionalSignals = allFindings.filter((f) => !isFindingAlreadySignaled(alreadySignaled, f)).map((f) => {
51766
52181
  const extracted = extractCategories2(f.finding || "");
51767
52182
  const category = f.category || extracted[0] || void 0;
@@ -52009,19 +52424,19 @@ function filterWatchEvents(rawJsonl, opts) {
52009
52424
  }
52010
52425
 
52011
52426
  // apps/cli/src/stickyPort.ts
52012
- var import_fs75 = require("fs");
52013
- var import_path79 = require("path");
52427
+ var import_fs76 = require("fs");
52428
+ var import_path80 = require("path");
52014
52429
  var import_net = require("net");
52015
- var RELAY_STICKY_FILE = (0, import_path79.join)(".gossip", "relay.port");
52016
- var HTTP_MCP_STICKY_FILE = (0, import_path79.join)(".gossip", "http-mcp.port");
52430
+ var RELAY_STICKY_FILE = (0, import_path80.join)(".gossip", "relay.port");
52431
+ var HTTP_MCP_STICKY_FILE = (0, import_path80.join)(".gossip", "http-mcp.port");
52017
52432
  function stickyPath(filename) {
52018
- return (0, import_path79.join)(process.cwd(), filename);
52433
+ return (0, import_path80.join)(process.cwd(), filename);
52019
52434
  }
52020
52435
  function readStickyPort(filename) {
52021
52436
  const p = stickyPath(filename);
52022
- if (!(0, import_fs75.existsSync)(p)) return null;
52437
+ if (!(0, import_fs76.existsSync)(p)) return null;
52023
52438
  try {
52024
- const raw = (0, import_fs75.readFileSync)(p, "utf-8").trim();
52439
+ const raw = (0, import_fs76.readFileSync)(p, "utf-8").trim();
52025
52440
  const n = parseInt(raw, 10);
52026
52441
  if (!Number.isFinite(n) || n < 1 || n > 65535) return null;
52027
52442
  return n;
@@ -52033,8 +52448,8 @@ function writeStickyPort(filename, port) {
52033
52448
  if (!Number.isFinite(port) || port < 1 || port > 65535) return;
52034
52449
  const p = stickyPath(filename);
52035
52450
  try {
52036
- (0, import_fs75.mkdirSync)((0, import_path79.dirname)(p), { recursive: true });
52037
- (0, import_fs75.writeFileSync)(p, String(port), "utf-8");
52451
+ (0, import_fs76.mkdirSync)((0, import_path80.dirname)(p), { recursive: true });
52452
+ (0, import_fs76.writeFileSync)(p, String(port), "utf-8");
52038
52453
  } catch {
52039
52454
  }
52040
52455
  }
@@ -52098,22 +52513,22 @@ function buildDashboardAdvisory(input) {
52098
52513
  }
52099
52514
 
52100
52515
  // apps/cli/src/native-agent-cache.ts
52101
- var import_fs76 = require("fs");
52102
- var import_path80 = require("path");
52516
+ var import_fs77 = require("fs");
52517
+ var import_path81 = require("path");
52103
52518
  var realFs = {
52104
- existsSync: import_fs76.existsSync,
52105
- readFileSync: import_fs76.readFileSync,
52106
- statSync: (p) => ({ mtimeMs: (0, import_fs76.statSync)(p).mtimeMs })
52519
+ existsSync: import_fs77.existsSync,
52520
+ readFileSync: import_fs77.readFileSync,
52521
+ statSync: (p) => ({ mtimeMs: (0, import_fs77.statSync)(p).mtimeMs })
52107
52522
  };
52108
52523
  function modelTierFromId(modelId) {
52109
52524
  if (modelId.includes("opus")) return "opus";
52110
52525
  if (modelId.includes("haiku")) return "haiku";
52111
52526
  return "sonnet";
52112
52527
  }
52113
- function refreshNativeAgentFromDisk(ac, cache2, projectRoot, fs6 = realFs) {
52114
- const claudeAgentPath = (0, import_path80.join)(projectRoot, ".claude", "agents", `${ac.id}.md`);
52115
- const instrPath = (0, import_path80.join)(projectRoot, ".gossip", "agents", ac.id, "instructions.md");
52116
- const prev = cache2.get(ac.id);
52528
+ function refreshNativeAgentFromDisk(ac, cache3, projectRoot, fs6 = realFs) {
52529
+ const claudeAgentPath = (0, import_path81.join)(projectRoot, ".claude", "agents", `${ac.id}.md`);
52530
+ const instrPath = (0, import_path81.join)(projectRoot, ".gossip", "agents", ac.id, "instructions.md");
52531
+ const prev = cache3.get(ac.id);
52117
52532
  let sourcePath = null;
52118
52533
  let stripFrontmatter = false;
52119
52534
  if (fs6.existsSync(claudeAgentPath)) {
@@ -52127,7 +52542,7 @@ function refreshNativeAgentFromDisk(ac, cache2, projectRoot, fs6 = realFs) {
52127
52542
  if (prev && prev.instructions.length > 0) {
52128
52543
  return;
52129
52544
  }
52130
- cache2.set(ac.id, {
52545
+ cache3.set(ac.id, {
52131
52546
  model: modelTierFromId(ac.model),
52132
52547
  instructions: "",
52133
52548
  description: ac.role || ac.preset || "",
@@ -52143,7 +52558,7 @@ function refreshNativeAgentFromDisk(ac, cache2, projectRoot, fs6 = realFs) {
52143
52558
  if (prev && prev.instructions.length > 0) {
52144
52559
  return;
52145
52560
  }
52146
- cache2.set(ac.id, {
52561
+ cache3.set(ac.id, {
52147
52562
  model: modelTierFromId(ac.model),
52148
52563
  instructions: "",
52149
52564
  description: ac.role || ac.preset || "",
@@ -52161,7 +52576,7 @@ function refreshNativeAgentFromDisk(ac, cache2, projectRoot, fs6 = realFs) {
52161
52576
  if (instructions.length === 0 && prev && prev.instructions.length > 0) {
52162
52577
  return;
52163
52578
  }
52164
- cache2.set(ac.id, {
52579
+ cache3.set(ac.id, {
52165
52580
  model: modelTierFromId(ac.model),
52166
52581
  instructions,
52167
52582
  description: ac.role || ac.preset || "",
@@ -52171,16 +52586,16 @@ function refreshNativeAgentFromDisk(ac, cache2, projectRoot, fs6 = realFs) {
52171
52586
  }
52172
52587
 
52173
52588
  // apps/cli/src/rules-content.ts
52174
- var import_fs77 = require("fs");
52175
- var import_path81 = require("path");
52589
+ var import_fs78 = require("fs");
52590
+ var import_path82 = require("path");
52176
52591
  var AGENT_LIST_PLACEHOLDER = "{{AGENT_LIST}}";
52177
52592
  function resolveRulesPath() {
52178
52593
  const candidates = [
52179
- (0, import_path81.join)(process.cwd(), "docs", "RULES.md"),
52180
- (0, import_path81.join)(__dirname, "..", "docs", "RULES.md"),
52181
- (0, import_path81.join)(__dirname, "docs", "RULES.md")
52594
+ (0, import_path82.join)(process.cwd(), "docs", "RULES.md"),
52595
+ (0, import_path82.join)(__dirname, "..", "docs", "RULES.md"),
52596
+ (0, import_path82.join)(__dirname, "docs", "RULES.md")
52182
52597
  ];
52183
- return candidates.find((p) => (0, import_fs77.existsSync)(p)) ?? null;
52598
+ return candidates.find((p) => (0, import_fs78.existsSync)(p)) ?? null;
52184
52599
  }
52185
52600
  function generateRulesContent(agentList) {
52186
52601
  const rulesPath = resolveRulesPath();
@@ -52189,7 +52604,7 @@ function generateRulesContent(agentList) {
52189
52604
  `[gossipcat] generateRulesContent: docs/RULES.md not found in any fallback path (cwd=${process.cwd()}, dirname=${__dirname}). Expected docs/RULES.md tracked in the gossipcat repo or shipped alongside the MCP bundle. If running from a fresh install, re-run \`npm run build:mcp\` to copy docs/RULES.md into dist-mcp/docs/.`
52190
52605
  );
52191
52606
  }
52192
- const template = (0, import_fs77.readFileSync)(rulesPath, "utf-8");
52607
+ const template = (0, import_fs78.readFileSync)(rulesPath, "utf-8");
52193
52608
  return template.split(AGENT_LIST_PLACEHOLDER).join(agentList);
52194
52609
  }
52195
52610
 
@@ -52259,12 +52674,12 @@ function isReservedAgentId(id) {
52259
52674
  }
52260
52675
  }
52261
52676
  if (process.env.GOSSIPCAT_MCP_NO_MAIN !== "1") {
52262
- const gossipDir = (0, import_path85.join)(process.cwd(), ".gossip");
52677
+ const gossipDir = (0, import_path86.join)(process.cwd(), ".gossip");
52263
52678
  try {
52264
- (0, import_fs81.mkdirSync)(gossipDir, { recursive: true });
52679
+ (0, import_fs82.mkdirSync)(gossipDir, { recursive: true });
52265
52680
  } catch {
52266
52681
  }
52267
- const logStream = (0, import_fs81.createWriteStream)((0, import_path85.join)(gossipDir, "mcp.log"), { flags: "a" });
52682
+ const logStream = (0, import_fs82.createWriteStream)((0, import_path86.join)(gossipDir, "mcp.log"), { flags: "a" });
52268
52683
  process.stderr.write = ((chunk, ...args) => {
52269
52684
  return logStream.write(chunk, ...args);
52270
52685
  });
@@ -52275,7 +52690,7 @@ try {
52275
52690
  } catch {
52276
52691
  }
52277
52692
  function memoryDirForProject(cwd) {
52278
- return (0, import_path85.join)((0, import_os7.homedir)(), ".claude", "projects", cwd.replaceAll("/", "-"), "memory");
52693
+ return (0, import_path86.join)((0, import_os7.homedir)(), ".claude", "projects", cwd.replaceAll("/", "-"), "memory");
52279
52694
  }
52280
52695
  function detectEnvironment() {
52281
52696
  if (process.env.CLAUDECODE === "1" || process.env.CLAUDE_CODE_ENTRYPOINT) {
@@ -52330,14 +52745,14 @@ var _pendingPlanData = /* @__PURE__ */ new Map();
52330
52745
  var _utilityGuardSnapshots = /* @__PURE__ */ new Map();
52331
52746
  var _modules = null;
52332
52747
  function lookupFindingSeverity(findingId, projectRoot) {
52333
- const { existsSync: existsSync69, readdirSync: readdirSync22, readFileSync: readFileSync62 } = require("fs");
52334
- const { join: join82 } = require("path");
52335
- const reportsDir = join82(projectRoot, ".gossip", "consensus-reports");
52336
- if (!existsSync69(reportsDir)) return null;
52748
+ const { existsSync: existsSync70, readdirSync: readdirSync22, readFileSync: readFileSync64 } = require("fs");
52749
+ const { join: join83 } = require("path");
52750
+ const reportsDir = join83(projectRoot, ".gossip", "consensus-reports");
52751
+ if (!existsSync70(reportsDir)) return null;
52337
52752
  try {
52338
52753
  const files = readdirSync22(reportsDir).filter((f) => f.endsWith(".json"));
52339
52754
  for (const file2 of files) {
52340
- const report = JSON.parse(readFileSync62(join82(reportsDir, file2), "utf-8"));
52755
+ const report = JSON.parse(readFileSync64(join83(reportsDir, file2), "utf-8"));
52341
52756
  for (const bucket of ["confirmed", "disputed", "unverified", "unique"]) {
52342
52757
  for (const finding of report[bucket] || []) {
52343
52758
  if (finding.id === findingId && finding.severity) {
@@ -52415,7 +52830,7 @@ async function doBoot() {
52415
52830
  const agentConfigs = m.configToAgentConfigs(config2);
52416
52831
  ctx.keychain = new m.Keychain();
52417
52832
  const { existsSync: pidExists, readFileSync: readPid, writeFileSync: writePid, unlinkSync: delPid } = require("fs");
52418
- const pidFile = (0, import_path85.join)(process.cwd(), ".gossip", "relay.pid");
52833
+ const pidFile = (0, import_path86.join)(process.cwd(), ".gossip", "relay.pid");
52419
52834
  if (pidExists(pidFile)) {
52420
52835
  const oldPid = parseInt(readPid(pidFile, "utf-8").trim(), 10);
52421
52836
  if (!isNaN(oldPid) && oldPid !== process.pid) {
@@ -52525,10 +52940,10 @@ async function doBoot() {
52525
52940
  }
52526
52941
  const key = await ctx.keychain.getKey(ac.provider);
52527
52942
  const llm = m.createProvider(ac.provider, ac.model, key ?? void 0, void 0, ac.base_url);
52528
- const { existsSync: existsSync69, readFileSync: readFileSync62 } = require("fs");
52529
- const { join: join82 } = require("path");
52530
- const instructionsPath = join82(process.cwd(), ".gossip", "agents", ac.id, "instructions.md");
52531
- const baseInstructions = existsSync69(instructionsPath) ? readFileSync62(instructionsPath, "utf-8") : "";
52943
+ const { existsSync: existsSync70, readFileSync: readFileSync64 } = require("fs");
52944
+ const { join: join83 } = require("path");
52945
+ const instructionsPath = join83(process.cwd(), ".gossip", "agents", ac.id, "instructions.md");
52946
+ const baseInstructions = existsSync70(instructionsPath) ? readFileSync64(instructionsPath, "utf-8") : "";
52532
52947
  const identity = ctx.identityRegistry.get(ac.id);
52533
52948
  const identityBlock = identity ? m.formatIdentityBlock(identity) + "\n" : "";
52534
52949
  const instructions = (identityBlock + baseInstructions).trim() || void 0;
@@ -53363,7 +53778,7 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
53363
53778
  }
53364
53779
  try {
53365
53780
  const { readFileSync: rfHealth } = await import("fs");
53366
- const healthPath = (0, import_path85.join)(process.cwd(), ".gossip", "skill-runner-health.json");
53781
+ const healthPath = (0, import_path86.join)(process.cwd(), ".gossip", "skill-runner-health.json");
53367
53782
  const raw = rfHealth(healthPath, "utf8");
53368
53783
  const h = JSON.parse(raw);
53369
53784
  const lastMs = h.last_run_at ? new Date(h.last_run_at).getTime() : NaN;
@@ -53379,9 +53794,9 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
53379
53794
  lines.push(" Skill graduation: never run since session start (expected after first gossip_collect)");
53380
53795
  }
53381
53796
  try {
53382
- const { readFileSync: readFileSync62 } = await import("fs");
53383
- const quotaPath = (0, import_path85.join)(process.cwd(), ".gossip", "quota-state.json");
53384
- const quotaRaw = readFileSync62(quotaPath, "utf8");
53797
+ const { readFileSync: readFileSync64 } = await import("fs");
53798
+ const quotaPath = (0, import_path86.join)(process.cwd(), ".gossip", "quota-state.json");
53799
+ const quotaRaw = readFileSync64(quotaPath, "utf8");
53385
53800
  const quotaState = JSON.parse(quotaRaw);
53386
53801
  for (const [provider, state] of Object.entries(quotaState)) {
53387
53802
  const now = Date.now();
@@ -53395,19 +53810,19 @@ Note: write-mode classification unavailable on this native-only install \u2014 a
53395
53810
  } catch {
53396
53811
  }
53397
53812
  try {
53398
- const { readdirSync: readdirSync22, statSync: statSync34 } = await import("fs");
53813
+ const { readdirSync: readdirSync22, statSync: statSync35 } = await import("fs");
53399
53814
  const { readJsonlWithRotated: readJsonlRotated1506 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
53400
- const reportsDir = (0, import_path85.join)(process.cwd(), ".gossip", "consensus-reports");
53401
- const perfPath = (0, import_path85.join)(process.cwd(), ".gossip", "agent-performance.jsonl");
53402
- const WINDOW_MS2 = 24 * 60 * 60 * 1e3;
53815
+ const reportsDir = (0, import_path86.join)(process.cwd(), ".gossip", "consensus-reports");
53816
+ const perfPath = (0, import_path86.join)(process.cwd(), ".gossip", "agent-performance.jsonl");
53817
+ const WINDOW_MS3 = 24 * 60 * 60 * 1e3;
53403
53818
  const now = Date.now();
53404
53819
  const recentReports = [];
53405
53820
  try {
53406
53821
  for (const fname of readdirSync22(reportsDir)) {
53407
53822
  if (!fname.endsWith(".json")) continue;
53408
- const fpath = (0, import_path85.join)(reportsDir, fname);
53409
- const st = statSync34(fpath);
53410
- if (now - st.mtimeMs > WINDOW_MS2) continue;
53823
+ const fpath = (0, import_path86.join)(reportsDir, fname);
53824
+ const st = statSync35(fpath);
53825
+ if (now - st.mtimeMs > WINDOW_MS3) continue;
53411
53826
  recentReports.push({ id: fname.replace(/\.json$/, ""), mtimeMs: st.mtimeMs });
53412
53827
  }
53413
53828
  } catch {
@@ -53771,8 +54186,8 @@ ${body}`
53771
54186
  }
53772
54187
  return { content: [{ type: "text", text: results.join("\n") }] };
53773
54188
  }
53774
- const { writeFileSync: writeFileSync34, mkdirSync: mkdirSync41, existsSync: existsSync69 } = require("fs");
53775
- const { join: join82 } = require("path");
54189
+ const { writeFileSync: writeFileSync34, mkdirSync: mkdirSync41, existsSync: existsSync70 } = require("fs");
54190
+ const { join: join83 } = require("path");
53776
54191
  const root = process.cwd();
53777
54192
  const CLAUDE_MODEL_MAP2 = {
53778
54193
  opus: { provider: "anthropic", model: "claude-opus-4-6" },
@@ -53786,8 +54201,8 @@ ${body}`
53786
54201
  let existingAgents = {};
53787
54202
  if (mode === "merge") {
53788
54203
  try {
53789
- const { readFileSync: readFileSync62 } = require("fs");
53790
- const existing = JSON.parse(readFileSync62(join82(root, ".gossip", "config.json"), "utf-8"));
54204
+ const { readFileSync: readFileSync64 } = require("fs");
54205
+ const existing = JSON.parse(readFileSync64(join83(root, ".gossip", "config.json"), "utf-8"));
53791
54206
  existingAgents = existing.agents || {};
53792
54207
  } catch {
53793
54208
  }
@@ -53818,9 +54233,9 @@ ${body}`
53818
54233
  "",
53819
54234
  body
53820
54235
  ].join("\n");
53821
- const agentsDir = join82(root, ".claude", "agents");
54236
+ const agentsDir = join83(root, ".claude", "agents");
53822
54237
  mkdirSync41(agentsDir, { recursive: true });
53823
- writeFileSync34(join82(agentsDir, `${agent.id}.md`), md, "utf-8");
54238
+ writeFileSync34(join83(agentsDir, `${agent.id}.md`), md, "utf-8");
53824
54239
  nativeCreated.push(agent.id);
53825
54240
  configAgents[agent.id] = {
53826
54241
  provider: mapped.provider,
@@ -53838,8 +54253,8 @@ ${body}`
53838
54253
  errors.push(`${agent.id}: custom agent requires "custom_model" field`);
53839
54254
  continue;
53840
54255
  }
53841
- const nativeFile = join82(root, ".claude", "agents", `${agent.id}.md`);
53842
- const wasNative = existingAgents[agent.id]?.native || existsSync69(nativeFile);
54256
+ const nativeFile = join83(root, ".claude", "agents", `${agent.id}.md`);
54257
+ const wasNative = existingAgents[agent.id]?.native || existsSync70(nativeFile);
53843
54258
  if (wasNative) {
53844
54259
  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.`);
53845
54260
  continue;
@@ -53853,9 +54268,9 @@ ${body}`
53853
54268
  };
53854
54269
  customCreated.push(agent.id);
53855
54270
  if (agent.instructions) {
53856
- const instrDir = join82(root, ".gossip", "agents", agent.id);
54271
+ const instrDir = join83(root, ".gossip", "agents", agent.id);
53857
54272
  mkdirSync41(instrDir, { recursive: true });
53858
- writeFileSync34(join82(instrDir, "instructions.md"), agent.instructions, "utf-8");
54273
+ writeFileSync34(join83(instrDir, "instructions.md"), agent.instructions, "utf-8");
53859
54274
  }
53860
54275
  }
53861
54276
  }
@@ -53869,8 +54284,8 @@ ${body}`
53869
54284
  } catch (err) {
53870
54285
  return { content: [{ type: "text", text: `Invalid config: ${err.message}` }] };
53871
54286
  }
53872
- mkdirSync41(join82(root, ".gossip"), { recursive: true });
53873
- writeFileSync34(join82(root, ".gossip", "config.json"), JSON.stringify(config2, null, 2));
54287
+ mkdirSync41(join83(root, ".gossip"), { recursive: true });
54288
+ writeFileSync34(join83(root, ".gossip", "config.json"), JSON.stringify(config2, null, 2));
53874
54289
  let hookSummary = "";
53875
54290
  try {
53876
54291
  const { installWorktreeSandboxHook: installWorktreeSandboxHook2, writeOrchestratorRoleMarker: writeOrchestratorRoleMarker2 } = (init_src4(), __toCommonJS(src_exports3));
@@ -53947,8 +54362,8 @@ ${body}`
53947
54362
  }
53948
54363
  }
53949
54364
  const agentList = Object.entries(config2.agents).map(([id, a]) => `- ${id}: ${a.provider}/${a.model} (${a.preset || "custom"})${a.native ? " \u2014 native" : ""}`).join("\n");
53950
- const rulesDir = join82(root, env.rulesDir);
53951
- const rulesFile = join82(root, env.rulesFile);
54365
+ const rulesDir = join83(root, env.rulesDir);
54366
+ const rulesFile = join83(root, env.rulesFile);
53952
54367
  mkdirSync41(rulesDir, { recursive: true });
53953
54368
  writeFileSync34(rulesFile, generateRulesContent(agentList));
53954
54369
  const lines = [`Host: ${env.host}`, ""];
@@ -54245,11 +54660,11 @@ The original signal remains in the audit log but will be excluded from scoring.`
54245
54660
  const fid = finding_id.trim();
54246
54661
  const cwd = process.cwd();
54247
54662
  const findingsPath = require("path").join(cwd, ".gossip", "implementation-findings.jsonl");
54248
- const { readFileSync: readFileSync62, existsSync: existsSync69, writeFileSync: writeFileSync34, renameSync: renameSync15 } = require("fs");
54249
- if (!existsSync69(findingsPath)) {
54663
+ const { readFileSync: readFileSync64, existsSync: existsSync70, writeFileSync: writeFileSync34, renameSync: renameSync15 } = require("fs");
54664
+ if (!existsSync70(findingsPath)) {
54250
54665
  return { content: [{ type: "text", text: `No implementation-findings.jsonl found at ${findingsPath}` }] };
54251
54666
  }
54252
- const lines = readFileSync62(findingsPath, "utf-8").split("\n");
54667
+ const lines = readFileSync64(findingsPath, "utf-8").split("\n");
54253
54668
  let matched = false;
54254
54669
  let alreadyTarget = false;
54255
54670
  let matchedEntry = null;
@@ -54337,18 +54752,18 @@ The original signal remains in the audit log but will be excluded from scoring.`
54337
54752
  return { content: [{ type: "text", text: "Error: consensus_id is required for bulk_from_consensus." }] };
54338
54753
  }
54339
54754
  try {
54340
- const { readFileSync: readFileSync62 } = await import("fs");
54341
- const { join: join82 } = await import("path");
54342
- const reportPath = join82(process.cwd(), ".gossip", "consensus-reports", `${consensus_id}.json`);
54755
+ const { readFileSync: readFileSync64 } = await import("fs");
54756
+ const { join: join83 } = await import("path");
54757
+ const reportPath = join83(process.cwd(), ".gossip", "consensus-reports", `${consensus_id}.json`);
54343
54758
  let report;
54344
54759
  try {
54345
- report = JSON.parse(readFileSync62(reportPath, "utf-8"));
54760
+ report = JSON.parse(readFileSync64(reportPath, "utf-8"));
54346
54761
  } catch {
54347
54762
  return { content: [{ type: "text", text: `Error: consensus report not found: ${consensus_id}` }] };
54348
54763
  }
54349
54764
  const existingFindingIds = /* @__PURE__ */ new Set();
54350
54765
  try {
54351
- const perfPath = join82(process.cwd(), ".gossip", "agent-performance.jsonl");
54766
+ const perfPath = join83(process.cwd(), ".gossip", "agent-performance.jsonl");
54352
54767
  const { readJsonlWithRotated: readJsonlRotated2570 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
54353
54768
  const lines = readJsonlRotated2570(perfPath).split("\n").filter(Boolean);
54354
54769
  for (const line of lines) {
@@ -55364,16 +55779,16 @@ ${preview}` }]
55364
55779
  const { SkillGapTracker: SkillGapTracker2, parseSkillFrontmatter: parseSkillFrontmatter2, normalizeSkillName: normalizeSkillName2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
55365
55780
  const tracker = new SkillGapTracker2(process.cwd());
55366
55781
  if (skills && skills.length > 0) {
55367
- const { writeFileSync: writeFileSync34, mkdirSync: mkdirSync41, existsSync: existsSync69, readFileSync: readFileSync62 } = require("fs");
55368
- const { join: join82 } = require("path");
55369
- const dir = join82(process.cwd(), ".gossip", "skills");
55782
+ const { writeFileSync: writeFileSync34, mkdirSync: mkdirSync41, existsSync: existsSync70, readFileSync: readFileSync64 } = require("fs");
55783
+ const { join: join83 } = require("path");
55784
+ const dir = join83(process.cwd(), ".gossip", "skills");
55370
55785
  mkdirSync41(dir, { recursive: true });
55371
55786
  const results = [];
55372
55787
  for (const sk of skills) {
55373
55788
  const name = normalizeSkillName2(sk.name);
55374
- const filePath = join82(dir, `${name}.md`);
55375
- if (existsSync69(filePath)) {
55376
- const existing = readFileSync62(filePath, "utf-8");
55789
+ const filePath = join83(dir, `${name}.md`);
55790
+ if (existsSync70(filePath)) {
55791
+ const existing = readFileSync64(filePath, "utf-8");
55377
55792
  const fm = parseSkillFrontmatter2(existing);
55378
55793
  if (fm) {
55379
55794
  if (fm.generated_by === "manual") {
@@ -56209,9 +56624,9 @@ ${p.user}
56209
56624
  max_events: external_exports.number().int().positive().max(WATCH_MAX_EVENTS).optional().describe(`Cap events returned (default ${WATCH_MAX_EVENTS}).`)
56210
56625
  },
56211
56626
  async ({ cursor, max_events }) => {
56212
- const { join: join82 } = await import("node:path");
56627
+ const { join: join83 } = await import("node:path");
56213
56628
  const { readJsonlWithRotated: readJsonlWithRotated2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
56214
- const perfPath = join82(process.cwd(), ".gossip", "agent-performance.jsonl");
56629
+ const perfPath = join83(process.cwd(), ".gossip", "agent-performance.jsonl");
56215
56630
  const raw = readJsonlWithRotated2(perfPath);
56216
56631
  const result = filterWatchEvents(raw, { cursor, maxEvents: max_events });
56217
56632
  return { content: [{ type: "text", text: JSON.stringify(result) }] };