gossipcat 0.1.0 → 0.1.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.
@@ -69,6 +69,46 @@ var init_mcp_context = __esm({
69
69
  }
70
70
  });
71
71
 
72
+ // apps/cli/src/version.ts
73
+ var version_exports = {};
74
+ __export(version_exports, {
75
+ getGossipcatVersion: () => getGossipcatVersion
76
+ });
77
+ function getGossipcatVersion() {
78
+ if (cached2 !== null) return cached2;
79
+ cached2 = resolveVersion();
80
+ return cached2;
81
+ }
82
+ function resolveVersion() {
83
+ let dir = __dirname;
84
+ const root = (0, import_path.resolve)("/");
85
+ for (let i = 0; i < 20 && dir !== root; i++) {
86
+ const candidate = (0, import_path.resolve)(dir, "package.json");
87
+ if ((0, import_fs.existsSync)(candidate)) {
88
+ try {
89
+ const pkg = JSON.parse((0, import_fs.readFileSync)(candidate, "utf-8"));
90
+ if (pkg && pkg.name === "gossipcat" && typeof pkg.version === "string") {
91
+ return pkg.version;
92
+ }
93
+ } catch {
94
+ }
95
+ }
96
+ const parent = (0, import_path.dirname)(dir);
97
+ if (parent === dir) break;
98
+ dir = parent;
99
+ }
100
+ return "unknown";
101
+ }
102
+ var import_fs, import_path, cached2;
103
+ var init_version = __esm({
104
+ "apps/cli/src/version.ts"() {
105
+ "use strict";
106
+ import_fs = require("fs");
107
+ import_path = require("path");
108
+ cached2 = null;
109
+ }
110
+ });
111
+
72
112
  // packages/orchestrator/src/llm-client.ts
73
113
  async function fetchWithRetry503(url2, init, providerName) {
74
114
  const res = await fetch(url2, init);
@@ -108,13 +148,13 @@ function createProvider(provider, model, apiKey, projectRoot, baseUrl) {
108
148
  throw new Error(`Unknown provider: ${provider}`);
109
149
  }
110
150
  }
111
- var import_crypto, import_fs, import_path, QuotaExhaustedException, QuotaTracker, AnthropicProvider, OpenAIProvider, GeminiProvider, OllamaProvider, NullProvider;
151
+ var import_crypto, import_fs2, import_path2, QuotaExhaustedException, QuotaTracker, AnthropicProvider, OpenAIProvider, GeminiProvider, OllamaProvider, NullProvider;
112
152
  var init_llm_client = __esm({
113
153
  "packages/orchestrator/src/llm-client.ts"() {
114
154
  "use strict";
115
155
  import_crypto = require("crypto");
116
- import_fs = require("fs");
117
- import_path = require("path");
156
+ import_fs2 = require("fs");
157
+ import_path2 = require("path");
118
158
  QuotaExhaustedException = class extends Error {
119
159
  provider;
120
160
  retryAfterMs;
@@ -128,7 +168,7 @@ var init_llm_client = __esm({
128
168
  QuotaTracker = class {
129
169
  constructor(provider, projectRoot) {
130
170
  this.provider = provider;
131
- this.statePath = projectRoot ? (0, import_path.join)(projectRoot, ".gossip", "quota-state.json") : null;
171
+ this.statePath = projectRoot ? (0, import_path2.join)(projectRoot, ".gossip", "quota-state.json") : null;
132
172
  this.load();
133
173
  }
134
174
  consecutive429s = 0;
@@ -136,9 +176,9 @@ var init_llm_client = __esm({
136
176
  reason = "quota";
137
177
  statePath;
138
178
  load() {
139
- if (!this.statePath || !(0, import_fs.existsSync)(this.statePath)) return;
179
+ if (!this.statePath || !(0, import_fs2.existsSync)(this.statePath)) return;
140
180
  try {
141
- const state = JSON.parse((0, import_fs.readFileSync)(this.statePath, "utf-8"));
181
+ const state = JSON.parse((0, import_fs2.readFileSync)(this.statePath, "utf-8"));
142
182
  if (state[this.provider]) {
143
183
  this.exhaustedUntil = state[this.provider].exhaustedUntil;
144
184
  this.consecutive429s = state[this.provider].consecutive429s;
@@ -150,15 +190,15 @@ var init_llm_client = __esm({
150
190
  persist() {
151
191
  if (!this.statePath) return;
152
192
  try {
153
- const dir = (0, import_path.join)(this.statePath, "..");
154
- if (!(0, import_fs.existsSync)(dir)) (0, import_fs.mkdirSync)(dir, { recursive: true });
193
+ const dir = (0, import_path2.join)(this.statePath, "..");
194
+ if (!(0, import_fs2.existsSync)(dir)) (0, import_fs2.mkdirSync)(dir, { recursive: true });
155
195
  let existing = {};
156
196
  try {
157
- existing = JSON.parse((0, import_fs.readFileSync)(this.statePath, "utf-8"));
197
+ existing = JSON.parse((0, import_fs2.readFileSync)(this.statePath, "utf-8"));
158
198
  } catch {
159
199
  }
160
200
  existing[this.provider] = { exhaustedUntil: this.exhaustedUntil, consecutive429s: this.consecutive429s, reason: this.reason };
161
- (0, import_fs.writeFileSync)(this.statePath, JSON.stringify(existing, null, 2));
201
+ (0, import_fs2.writeFileSync)(this.statePath, JSON.stringify(existing, null, 2));
162
202
  } catch {
163
203
  }
164
204
  }
@@ -3078,7 +3118,7 @@ var init_gossip_agent = __esm({
3078
3118
  }
3079
3119
  // ─── Public API ─────────────────────────────────────────────────────────────
3080
3120
  connect() {
3081
- return new Promise((resolve17, reject) => {
3121
+ return new Promise((resolve18, reject) => {
3082
3122
  const ws = new import_ws.default(this.config.relayUrl);
3083
3123
  const timeout = setTimeout(() => {
3084
3124
  ws.removeAllListeners();
@@ -3111,7 +3151,7 @@ var init_gossip_agent = __esm({
3111
3151
  ws.on("error", (err) => this.emit("error", err));
3112
3152
  this.startKeepAlive();
3113
3153
  this.emit("connect", msg.sessionId);
3114
- resolve17();
3154
+ resolve18();
3115
3155
  } else if (msg.type === "error") {
3116
3156
  clearTimeout(timeout);
3117
3157
  ws.removeAllListeners();
@@ -3137,7 +3177,7 @@ var init_gossip_agent = __esm({
3137
3177
  this.reconnectTimer = null;
3138
3178
  }
3139
3179
  if (!this.ws) return;
3140
- return new Promise((resolve17) => {
3180
+ return new Promise((resolve18) => {
3141
3181
  this.intentionalDisconnect = true;
3142
3182
  this._connected = false;
3143
3183
  const ws = this.ws;
@@ -3148,7 +3188,7 @@ var init_gossip_agent = __esm({
3148
3188
  settled = true;
3149
3189
  this.intentionalDisconnect = false;
3150
3190
  this.emit("disconnect", code);
3151
- resolve17();
3191
+ resolve18();
3152
3192
  };
3153
3193
  const timer = setTimeout(() => done(1e3), 2e3);
3154
3194
  ws.once("close", (code) => {
@@ -3187,8 +3227,8 @@ var init_gossip_agent = __esm({
3187
3227
  throw new Error("Not connected to relay");
3188
3228
  }
3189
3229
  const encoded = Buffer.from(this.codec.encode(envelope));
3190
- return new Promise((resolve17, reject) => {
3191
- this.ws.send(encoded, (err) => err ? reject(err) : resolve17());
3230
+ return new Promise((resolve18, reject) => {
3231
+ this.ws.send(encoded, (err) => err ? reject(err) : resolve18());
3192
3232
  });
3193
3233
  }
3194
3234
  // ─── Internal ────────────────────────────────────────────────────────────────
@@ -3632,7 +3672,7 @@ ${context}` : ""}
3632
3672
  this.toolCallBudget.set(name, used + 1);
3633
3673
  }
3634
3674
  const requestId = (0, import_crypto4.randomUUID)();
3635
- const resultPromise = new Promise((resolve17, reject) => {
3675
+ const resultPromise = new Promise((resolve18, reject) => {
3636
3676
  const timer = setTimeout(() => {
3637
3677
  if (this.pendingToolCalls.has(requestId)) {
3638
3678
  this.pendingToolCalls.delete(requestId);
@@ -3643,7 +3683,7 @@ ${context}` : ""}
3643
3683
  this.pendingToolCalls.set(requestId, {
3644
3684
  resolve: (r) => {
3645
3685
  clearTimeout(timer);
3646
- resolve17(r);
3686
+ resolve18(r);
3647
3687
  },
3648
3688
  reject: (e) => {
3649
3689
  clearTimeout(timer);
@@ -3708,12 +3748,12 @@ ${context}` : ""}
3708
3748
  });
3709
3749
 
3710
3750
  // packages/tools/src/file-tools.ts
3711
- var import_promises, import_path2, FileTools;
3751
+ var import_promises, import_path3, FileTools;
3712
3752
  var init_file_tools = __esm({
3713
3753
  "packages/tools/src/file-tools.ts"() {
3714
3754
  "use strict";
3715
3755
  import_promises = require("fs/promises");
3716
- import_path2 = require("path");
3756
+ import_path3 = require("path");
3717
3757
  FileTools = class {
3718
3758
  constructor(sandbox) {
3719
3759
  this.sandbox = sandbox;
@@ -3738,7 +3778,7 @@ var init_file_tools = __esm({
3738
3778
  }
3739
3779
  async fileWrite(args) {
3740
3780
  const absPath = this.sandbox.validatePath(args.path);
3741
- const dir = (0, import_path2.resolve)(absPath, "..");
3781
+ const dir = (0, import_path3.resolve)(absPath, "..");
3742
3782
  await (0, import_promises.mkdir)(dir, { recursive: true });
3743
3783
  await (0, import_promises.writeFile)(absPath, args.content, "utf-8");
3744
3784
  return `Written ${args.content.length} bytes to ${args.path}`;
@@ -3783,7 +3823,7 @@ var init_file_tools = __esm({
3783
3823
  }
3784
3824
  for (const entry of entries) {
3785
3825
  if (entry === "node_modules" || entry === ".git") continue;
3786
- const fullPath = (0, import_path2.join)(dir, entry);
3826
+ const fullPath = (0, import_path3.join)(dir, entry);
3787
3827
  let info;
3788
3828
  try {
3789
3829
  info = await (0, import_promises.stat)(fullPath);
@@ -3795,7 +3835,7 @@ var init_file_tools = __esm({
3795
3835
  } else {
3796
3836
  const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
3797
3837
  const regex = new RegExp(regexStr);
3798
- const relPath = (0, import_path2.relative)(this.sandbox.projectRoot, fullPath);
3838
+ const relPath = (0, import_path3.relative)(this.sandbox.projectRoot, fullPath);
3799
3839
  if (regex.test(entry) || regex.test(relPath)) {
3800
3840
  results.push(relPath);
3801
3841
  }
@@ -3812,7 +3852,7 @@ var init_file_tools = __esm({
3812
3852
  }
3813
3853
  for (const entry of entries) {
3814
3854
  if (entry === "node_modules" || entry === ".git") continue;
3815
- const fullPath = (0, import_path2.join)(dir, entry);
3855
+ const fullPath = (0, import_path3.join)(dir, entry);
3816
3856
  let info;
3817
3857
  try {
3818
3858
  info = await (0, import_promises.stat)(fullPath);
@@ -3825,7 +3865,7 @@ var init_file_tools = __esm({
3825
3865
  try {
3826
3866
  const content = await (0, import_promises.readFile)(fullPath, "utf-8");
3827
3867
  const lines = content.split("\n");
3828
- const relPath = (0, import_path2.relative)(this.sandbox.projectRoot, fullPath);
3868
+ const relPath = (0, import_path3.relative)(this.sandbox.projectRoot, fullPath);
3829
3869
  lines.forEach((line, idx) => {
3830
3870
  if (regex.test(line)) {
3831
3871
  results.push(`${relPath}:${idx + 1}: ${line}`);
@@ -3849,7 +3889,7 @@ var init_file_tools = __esm({
3849
3889
  const entry = filtered[i];
3850
3890
  const isLast = i === filtered.length - 1;
3851
3891
  const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
3852
- const fullPath = (0, import_path2.join)(dir, entry);
3892
+ const fullPath = (0, import_path3.join)(dir, entry);
3853
3893
  let info;
3854
3894
  try {
3855
3895
  info = await (0, import_promises.stat)(fullPath);
@@ -4054,20 +4094,20 @@ var init_git_tools = __esm({
4054
4094
  });
4055
4095
 
4056
4096
  // packages/tools/src/skill-tools.ts
4057
- var import_fs2, import_path3, SkillTools;
4097
+ var import_fs3, import_path4, SkillTools;
4058
4098
  var init_skill_tools = __esm({
4059
4099
  "packages/tools/src/skill-tools.ts"() {
4060
4100
  "use strict";
4061
- import_fs2 = require("fs");
4062
- import_path3 = require("path");
4101
+ import_fs3 = require("fs");
4102
+ import_path4 = require("path");
4063
4103
  SkillTools = class {
4064
4104
  gapLogPath;
4065
4105
  constructor(projectRoot) {
4066
- const gossipDir2 = (0, import_path3.join)(projectRoot, ".gossip");
4067
- if (!(0, import_fs2.existsSync)(gossipDir2)) {
4068
- (0, import_fs2.mkdirSync)(gossipDir2, { recursive: true });
4106
+ const gossipDir2 = (0, import_path4.join)(projectRoot, ".gossip");
4107
+ if (!(0, import_fs3.existsSync)(gossipDir2)) {
4108
+ (0, import_fs3.mkdirSync)(gossipDir2, { recursive: true });
4069
4109
  }
4070
- this.gapLogPath = (0, import_path3.join)(gossipDir2, "skill-gaps.jsonl");
4110
+ this.gapLogPath = (0, import_path4.join)(gossipDir2, "skill-gaps.jsonl");
4071
4111
  }
4072
4112
  async suggestSkill(args, callerId) {
4073
4113
  const entry = {
@@ -4078,16 +4118,16 @@ var init_skill_tools = __esm({
4078
4118
  task_context: args.task_context,
4079
4119
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
4080
4120
  };
4081
- (0, import_fs2.appendFileSync)(this.gapLogPath, JSON.stringify(entry) + "\n");
4121
+ (0, import_fs3.appendFileSync)(this.gapLogPath, JSON.stringify(entry) + "\n");
4082
4122
  this.truncateIfNeeded();
4083
4123
  return `Suggestion noted: '${args.skill_name}'. Continue with your current skills.`;
4084
4124
  }
4085
4125
  truncateIfNeeded() {
4086
4126
  try {
4087
- const content = (0, import_fs2.readFileSync)(this.gapLogPath, "utf-8");
4127
+ const content = (0, import_fs3.readFileSync)(this.gapLogPath, "utf-8");
4088
4128
  const lines = content.trim().split("\n").filter(Boolean);
4089
4129
  if (lines.length > 5e3) {
4090
- (0, import_fs2.writeFileSync)(this.gapLogPath, lines.slice(-1e3).join("\n") + "\n");
4130
+ (0, import_fs3.writeFileSync)(this.gapLogPath, lines.slice(-1e3).join("\n") + "\n");
4091
4131
  }
4092
4132
  } catch {
4093
4133
  }
@@ -4097,16 +4137,16 @@ var init_skill_tools = __esm({
4097
4137
  });
4098
4138
 
4099
4139
  // packages/tools/src/sandbox.ts
4100
- var import_path4, import_fs3, Sandbox;
4140
+ var import_path5, import_fs4, Sandbox;
4101
4141
  var init_sandbox = __esm({
4102
4142
  "packages/tools/src/sandbox.ts"() {
4103
4143
  "use strict";
4104
- import_path4 = require("path");
4105
- import_fs3 = require("fs");
4144
+ import_path5 = require("path");
4145
+ import_fs4 = require("fs");
4106
4146
  Sandbox = class {
4107
4147
  root;
4108
4148
  constructor(projectRoot) {
4109
- this.root = (0, import_fs3.realpathSync)((0, import_path4.resolve)(projectRoot));
4149
+ this.root = (0, import_fs4.realpathSync)((0, import_path5.resolve)(projectRoot));
4110
4150
  }
4111
4151
  get projectRoot() {
4112
4152
  return this.root;
@@ -4118,14 +4158,14 @@ var init_sandbox = __esm({
4118
4158
  * Resolves symlinks to prevent symlink escape attacks.
4119
4159
  */
4120
4160
  validatePath(filePath) {
4121
- const resolved = (0, import_path4.resolve)(this.root, filePath);
4161
+ const resolved = (0, import_path5.resolve)(this.root, filePath);
4122
4162
  let checkPath = resolved;
4123
- while (!(0, import_fs3.existsSync)(checkPath)) {
4124
- const parent = (0, import_path4.dirname)(checkPath);
4163
+ while (!(0, import_fs4.existsSync)(checkPath)) {
4164
+ const parent = (0, import_path5.dirname)(checkPath);
4125
4165
  if (parent === checkPath) break;
4126
4166
  checkPath = parent;
4127
4167
  }
4128
- const real = (0, import_fs3.existsSync)(checkPath) ? (0, import_fs3.realpathSync)(checkPath) : checkPath;
4168
+ const real = (0, import_fs4.existsSync)(checkPath) ? (0, import_fs4.realpathSync)(checkPath) : checkPath;
4129
4169
  const remainder = resolved.slice(checkPath.length);
4130
4170
  const fullReal = real + remainder;
4131
4171
  if (!fullReal.startsWith(this.root + "/") && fullReal !== this.root) {
@@ -8343,16 +8383,16 @@ var init_tool_schemas = __esm({
8343
8383
  // packages/tools/src/tool-server.ts
8344
8384
  function canonicalizeForBoundary(p) {
8345
8385
  let out = p;
8346
- if ((0, import_fs4.existsSync)(out)) {
8386
+ if ((0, import_fs5.existsSync)(out)) {
8347
8387
  try {
8348
- out = (0, import_fs4.realpathSync)(out);
8388
+ out = (0, import_fs5.realpathSync)(out);
8349
8389
  } catch {
8350
8390
  }
8351
8391
  } else {
8352
- const parent = (0, import_path5.dirname)(out);
8353
- if (parent !== out && (0, import_fs4.existsSync)(parent)) {
8392
+ const parent = (0, import_path6.dirname)(out);
8393
+ if (parent !== out && (0, import_fs5.existsSync)(parent)) {
8354
8394
  try {
8355
- out = (0, import_path5.join)((0, import_fs4.realpathSync)(parent), (0, import_path5.basename)(out));
8395
+ out = (0, import_path6.join)((0, import_fs5.realpathSync)(parent), (0, import_path6.basename)(out));
8356
8396
  } catch {
8357
8397
  }
8358
8398
  }
@@ -8385,7 +8425,7 @@ function truncateAtLine(text, maxLength) {
8385
8425
  const cut = text.lastIndexOf("\n", maxLength);
8386
8426
  return text.slice(0, cut !== -1 ? cut : maxLength);
8387
8427
  }
8388
- var import_msgpack4, import_crypto5, import_path5, import_fs4, CASE_INSENSITIVE_FS, ToolServer;
8428
+ var import_msgpack4, import_crypto5, import_path6, import_fs5, CASE_INSENSITIVE_FS, ToolServer;
8389
8429
  var init_tool_server = __esm({
8390
8430
  "packages/tools/src/tool-server.ts"() {
8391
8431
  "use strict";
@@ -8399,8 +8439,8 @@ var init_tool_server = __esm({
8399
8439
  init_skill_tools();
8400
8440
  init_sandbox();
8401
8441
  init_tool_schemas();
8402
- import_path5 = require("path");
8403
- import_fs4 = require("fs");
8442
+ import_path6 = require("path");
8443
+ import_fs5 = require("fs");
8404
8444
  CASE_INSENSITIVE_FS = process.platform === "darwin" || process.platform === "win32";
8405
8445
  ToolServer = class _ToolServer {
8406
8446
  agent;
@@ -8455,12 +8495,12 @@ var init_tool_server = __esm({
8455
8495
  return this.agent.agentId;
8456
8496
  }
8457
8497
  assignScope(agentId, scope) {
8458
- const abs = (0, import_path5.resolve)(this.sandbox.projectRoot, scope);
8498
+ const abs = (0, import_path6.resolve)(this.sandbox.projectRoot, scope);
8459
8499
  this.agentScopes.set(agentId, canonicalizeForBoundary(abs));
8460
8500
  this.writeAgents.add(agentId);
8461
8501
  }
8462
8502
  assignRoot(agentId, root) {
8463
- const abs = (0, import_path5.resolve)(root);
8503
+ const abs = (0, import_path6.resolve)(root);
8464
8504
  this.agentRoots.set(agentId, canonicalizeForBoundary(abs));
8465
8505
  this.writeAgents.add(agentId);
8466
8506
  }
@@ -8520,13 +8560,13 @@ var init_tool_server = __esm({
8520
8560
  if (toolName === "file_write") {
8521
8561
  const filePath = args.path;
8522
8562
  if (scope) {
8523
- const canonical = canonicalizeForBoundary((0, import_path5.resolve)(this.sandbox.projectRoot, filePath));
8563
+ const canonical = canonicalizeForBoundary((0, import_path6.resolve)(this.sandbox.projectRoot, filePath));
8524
8564
  if (!canonical.startsWith(scope)) {
8525
8565
  throw new Error(`Write blocked: "${filePath}" is outside scope "${scope}"`);
8526
8566
  }
8527
8567
  }
8528
8568
  if (root) {
8529
- const canonical = canonicalizeForBoundary((0, import_path5.resolve)(root, filePath));
8569
+ const canonical = canonicalizeForBoundary((0, import_path6.resolve)(root, filePath));
8530
8570
  if (!canonical.startsWith(root)) {
8531
8571
  throw new Error(`Write blocked: "${filePath}" is outside worktree root "${root}"`);
8532
8572
  }
@@ -8561,13 +8601,13 @@ var init_tool_server = __esm({
8561
8601
  if (toolName === "file_delete") {
8562
8602
  const filePath = args.path;
8563
8603
  if (scope) {
8564
- const canonical = canonicalizeForBoundary((0, import_path5.resolve)(this.sandbox.projectRoot, filePath));
8604
+ const canonical = canonicalizeForBoundary((0, import_path6.resolve)(this.sandbox.projectRoot, filePath));
8565
8605
  if (!canonical.startsWith(scope)) {
8566
8606
  throw new Error(`Delete blocked: "${filePath}" is outside scope "${scope}"`);
8567
8607
  }
8568
8608
  }
8569
8609
  if (root) {
8570
- const canonical = canonicalizeForBoundary((0, import_path5.resolve)(root, filePath));
8610
+ const canonical = canonicalizeForBoundary((0, import_path6.resolve)(root, filePath));
8571
8611
  if (!canonical.startsWith(root)) {
8572
8612
  throw new Error(`Delete blocked: "${filePath}" is outside worktree root "${root}"`);
8573
8613
  }
@@ -8603,7 +8643,7 @@ var init_tool_server = __esm({
8603
8643
  case "file_read": {
8604
8644
  const readScope = callerId ? this.agentScopes.get(callerId) : void 0;
8605
8645
  if (readScope) {
8606
- const canonical = canonicalizeForBoundary((0, import_path5.resolve)(this.sandbox.projectRoot, args.path));
8646
+ const canonical = canonicalizeForBoundary((0, import_path6.resolve)(this.sandbox.projectRoot, args.path));
8607
8647
  if (!canonical.startsWith(readScope)) {
8608
8648
  throw new Error(`Read blocked: "${args.path}" is outside scope "${readScope}"`);
8609
8649
  }
@@ -8797,7 +8837,7 @@ ${truncateAtLine(fullDiff, 3e3)}`;
8797
8837
  }
8798
8838
  async requestPeerReview(callerId, diff, testResult) {
8799
8839
  const requestId = (0, import_crypto5.randomUUID)();
8800
- const reviewPromise = new Promise((resolve17, reject) => {
8840
+ const reviewPromise = new Promise((resolve18, reject) => {
8801
8841
  const timer = setTimeout(() => {
8802
8842
  this.pendingReviews.delete(requestId);
8803
8843
  reject(new Error("Review timed out"));
@@ -8806,7 +8846,7 @@ ${truncateAtLine(fullDiff, 3e3)}`;
8806
8846
  this.pendingReviews.set(requestId, {
8807
8847
  resolve: (r) => {
8808
8848
  clearTimeout(timer);
8809
- resolve17(r);
8849
+ resolve18(r);
8810
8850
  },
8811
8851
  reject: (e) => {
8812
8852
  clearTimeout(timer);
@@ -8832,7 +8872,7 @@ ${truncateAtLine(fullDiff, 3e3)}`;
8832
8872
  }
8833
8873
  async handleRunTests(args, callerId) {
8834
8874
  const { fileGlob } = args;
8835
- const resolvedGlob = (0, import_path5.resolve)(this.sandbox.projectRoot, fileGlob.replace(/\*/g, "_"));
8875
+ const resolvedGlob = (0, import_path6.resolve)(this.sandbox.projectRoot, fileGlob.replace(/\*/g, "_"));
8836
8876
  if (!resolvedGlob.startsWith(this.sandbox.projectRoot)) {
8837
8877
  throw new Error("run_tests: fileGlob must not contain path traversal");
8838
8878
  }
@@ -8840,7 +8880,7 @@ ${truncateAtLine(fullDiff, 3e3)}`;
8840
8880
  throw new Error("run_tests: fileGlob must not contain flags. Pass only file paths/globs.");
8841
8881
  }
8842
8882
  const scope = callerId ? this.agentScopes.get(callerId) : void 0;
8843
- const cwd = scope ? this.sandbox.validatePath((0, import_path5.resolve)(this.sandbox.projectRoot, scope)) : this.sandbox.projectRoot;
8883
+ const cwd = scope ? this.sandbox.validatePath((0, import_path6.resolve)(this.sandbox.projectRoot, scope)) : this.sandbox.projectRoot;
8844
8884
  let output;
8845
8885
  let success2;
8846
8886
  try {
@@ -8860,11 +8900,11 @@ ${truncateAtLine(fullDiff, 3e3)}`;
8860
8900
  }
8861
8901
  async handleRunTypecheck(callerId) {
8862
8902
  const scope = callerId ? this.agentScopes.get(callerId) : void 0;
8863
- const cwd = scope ? this.sandbox.validatePath((0, import_path5.resolve)(this.sandbox.projectRoot, scope)) : this.sandbox.projectRoot;
8903
+ const cwd = scope ? this.sandbox.validatePath((0, import_path6.resolve)(this.sandbox.projectRoot, scope)) : this.sandbox.projectRoot;
8864
8904
  let output;
8865
8905
  let success2;
8866
8906
  try {
8867
- const tsconfigPath = (0, import_path5.resolve)(this.sandbox.projectRoot, "tsconfig.json");
8907
+ const tsconfigPath = (0, import_path6.resolve)(this.sandbox.projectRoot, "tsconfig.json");
8868
8908
  output = await this.shellTools.shellExec({
8869
8909
  command: "npx",
8870
8910
  args: ["tsc", "--noEmit", "--project", tsconfigPath],
@@ -9247,16 +9287,16 @@ function resolveSkill(agentId, skill, projectRoot) {
9247
9287
  if (!normalized) return null;
9248
9288
  const filename = `${normalized}.md`;
9249
9289
  const bases = [
9250
- (0, import_path6.resolve)(projectRoot, ".gossip", "agents", agentId, "skills"),
9251
- (0, import_path6.resolve)(projectRoot, ".gossip", "skills"),
9252
- (0, import_path6.resolve)(__dirname, "default-skills")
9290
+ (0, import_path7.resolve)(projectRoot, ".gossip", "agents", agentId, "skills"),
9291
+ (0, import_path7.resolve)(projectRoot, ".gossip", "skills"),
9292
+ (0, import_path7.resolve)(__dirname, "default-skills")
9253
9293
  ];
9254
9294
  for (const base of bases) {
9255
- const candidate = (0, import_path6.resolve)(base, filename);
9256
- if (!candidate.startsWith(base + import_path6.sep)) continue;
9257
- if ((0, import_fs5.existsSync)(candidate)) {
9295
+ const candidate = (0, import_path7.resolve)(base, filename);
9296
+ if (!candidate.startsWith(base + import_path7.sep)) continue;
9297
+ if ((0, import_fs6.existsSync)(candidate)) {
9258
9298
  try {
9259
- return (0, import_fs5.readFileSync)(candidate, "utf-8");
9299
+ return (0, import_fs6.readFileSync)(candidate, "utf-8");
9260
9300
  } catch (err) {
9261
9301
  process.stderr.write(
9262
9302
  `[skill-loader] Failed to read skill file ${candidate}: ${err?.message ?? err}
@@ -9271,12 +9311,12 @@ function resolveSkill(agentId, skill, projectRoot) {
9271
9311
  function resolveSkillExists(agentId, skill, projectRoot) {
9272
9312
  return resolveSkill(agentId, skill, projectRoot) !== null;
9273
9313
  }
9274
- var import_fs5, import_path6, SAFE_AGENT_ID, MAX_CONTEXTUAL_SKILLS, MIN_KEYWORD_HITS, DEFAULT_KEYWORDS, patternCache, MAX_PATTERN_CACHE, MAX_KEYWORD_LENGTH;
9314
+ var import_fs6, import_path7, SAFE_AGENT_ID, MAX_CONTEXTUAL_SKILLS, MIN_KEYWORD_HITS, DEFAULT_KEYWORDS, patternCache, MAX_PATTERN_CACHE, MAX_KEYWORD_LENGTH;
9275
9315
  var init_skill_loader = __esm({
9276
9316
  "packages/orchestrator/src/skill-loader.ts"() {
9277
9317
  "use strict";
9278
- import_fs5 = require("fs");
9279
- import_path6 = require("path");
9318
+ import_fs6 = require("fs");
9319
+ import_path7 = require("path");
9280
9320
  init_skill_parser();
9281
9321
  init_skill_name();
9282
9322
  SAFE_AGENT_ID = /^[a-z0-9][a-z0-9_-]{0,62}$/;
@@ -9475,29 +9515,29 @@ Attributes can appear in any order. Do NOT include confirmations.`;
9475
9515
  });
9476
9516
 
9477
9517
  // packages/orchestrator/src/agent-memory.ts
9478
- var import_fs6, import_path7, AgentMemoryReader;
9518
+ var import_fs7, import_path8, AgentMemoryReader;
9479
9519
  var init_agent_memory = __esm({
9480
9520
  "packages/orchestrator/src/agent-memory.ts"() {
9481
9521
  "use strict";
9482
- import_fs6 = require("fs");
9483
- import_path7 = require("path");
9522
+ import_fs7 = require("fs");
9523
+ import_path8 = require("path");
9484
9524
  AgentMemoryReader = class {
9485
9525
  constructor(projectRoot) {
9486
9526
  this.projectRoot = projectRoot;
9487
9527
  }
9488
9528
  loadMemory(agentId, taskText) {
9489
- const memDir = (0, import_path7.join)(this.projectRoot, ".gossip", "agents", agentId, "memory");
9490
- const indexPath = (0, import_path7.join)(memDir, "MEMORY.md");
9491
- if (!(0, import_fs6.existsSync)(indexPath)) return null;
9529
+ const memDir = (0, import_path8.join)(this.projectRoot, ".gossip", "agents", agentId, "memory");
9530
+ const indexPath = (0, import_path8.join)(memDir, "MEMORY.md");
9531
+ if (!(0, import_fs7.existsSync)(indexPath)) return null;
9492
9532
  const parts = [];
9493
- const indexContent = (0, import_fs6.readFileSync)(indexPath, "utf-8");
9533
+ const indexContent = (0, import_fs7.readFileSync)(indexPath, "utf-8");
9494
9534
  const indexLines = indexContent.split("\n");
9495
9535
  parts.push(indexLines.length > 200 ? indexLines.slice(0, 200).join("\n") + "\n[Truncated]" : indexContent);
9496
- const knowledgeDir = (0, import_path7.join)(memDir, "knowledge");
9497
- if ((0, import_fs6.existsSync)(knowledgeDir)) {
9536
+ const knowledgeDir = (0, import_path8.join)(memDir, "knowledge");
9537
+ if ((0, import_fs7.existsSync)(knowledgeDir)) {
9498
9538
  const files = this.selectKnowledgeFiles(knowledgeDir, taskText);
9499
9539
  for (const file2 of files) {
9500
- let content = (0, import_fs6.readFileSync)(file2.path, "utf-8");
9540
+ let content = (0, import_fs7.readFileSync)(file2.path, "utf-8");
9501
9541
  content = content.replace(/<\/?(?:agent-memory|system|instructions)>/gi, "");
9502
9542
  parts.push(`<agent-memory>
9503
9543
  ${content}
@@ -9507,11 +9547,11 @@ ${content}
9507
9547
  }
9508
9548
  }
9509
9549
  }
9510
- const projectKnowledgeDir = (0, import_path7.join)(this.projectRoot, ".gossip", "agents", "_project", "memory", "knowledge");
9511
- if ((0, import_fs6.existsSync)(projectKnowledgeDir)) {
9550
+ const projectKnowledgeDir = (0, import_path8.join)(this.projectRoot, ".gossip", "agents", "_project", "memory", "knowledge");
9551
+ if ((0, import_fs7.existsSync)(projectKnowledgeDir)) {
9512
9552
  const projectFiles = this.selectKnowledgeFiles(projectKnowledgeDir, taskText, 3);
9513
9553
  for (const file2 of projectFiles) {
9514
- let content = (0, import_fs6.readFileSync)(file2.path, "utf-8");
9554
+ let content = (0, import_fs7.readFileSync)(file2.path, "utf-8");
9515
9555
  content = content.replace(/<\/?(?:agent-memory|system|instructions)>/gi, "");
9516
9556
  parts.push(`<project-context>
9517
9557
  ${content}
@@ -9521,19 +9561,19 @@ ${content}
9521
9561
  }
9522
9562
  }
9523
9563
  }
9524
- const calPath = (0, import_path7.join)(memDir, "calibration", "accuracy.md");
9525
- if ((0, import_fs6.existsSync)(calPath)) {
9526
- parts.push((0, import_fs6.readFileSync)(calPath, "utf-8"));
9564
+ const calPath = (0, import_path8.join)(memDir, "calibration", "accuracy.md");
9565
+ if ((0, import_fs7.existsSync)(calPath)) {
9566
+ parts.push((0, import_fs7.readFileSync)(calPath, "utf-8"));
9527
9567
  }
9528
9568
  return parts.join("\n\n");
9529
9569
  }
9530
9570
  selectKnowledgeFiles(knowledgeDir, taskText, maxFiles = 5) {
9531
- const files = (0, import_fs6.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md"));
9571
+ const files = (0, import_fs7.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md"));
9532
9572
  const scored = [];
9533
9573
  const lower = taskText.toLowerCase();
9534
9574
  for (const file2 of files) {
9535
- const filePath = (0, import_path7.join)(knowledgeDir, file2);
9536
- const content = (0, import_fs6.readFileSync)(filePath, "utf-8");
9575
+ const filePath = (0, import_path8.join)(knowledgeDir, file2);
9576
+ const content = (0, import_fs7.readFileSync)(filePath, "utf-8");
9537
9577
  const frontmatter = this.parseFrontmatter(content);
9538
9578
  if (frontmatter) {
9539
9579
  const warmth = this.calculateWarmth(frontmatter.importance, frontmatter.lastAccessed);
@@ -9547,7 +9587,7 @@ ${content}
9547
9587
  } else {
9548
9588
  const relevance = this.calculateRelevance(content.slice(0, 500), lower);
9549
9589
  try {
9550
- const mtime = (0, import_fs6.statSync)(filePath).mtimeMs;
9590
+ const mtime = (0, import_fs7.statSync)(filePath).mtimeMs;
9551
9591
  const ageDays = (Date.now() - mtime) / 864e5;
9552
9592
  const ageFactor = 1 / (1 + ageDays / 30);
9553
9593
  scored.push({ path: filePath, score: Math.max(relevance * ageFactor, 0.05) });
@@ -9602,7 +9642,7 @@ ${content}
9602
9642
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9603
9643
  const fmEnd = content.indexOf("\n---", 4);
9604
9644
  if (fmEnd < 0) {
9605
- (0, import_fs6.writeFileSync)(filePath, content);
9645
+ (0, import_fs7.writeFileSync)(filePath, content);
9606
9646
  return;
9607
9647
  }
9608
9648
  let frontmatter = content.slice(0, fmEnd);
@@ -9613,19 +9653,19 @@ ${content}
9613
9653
  const newCount = parseInt(countMatch[1]) + 1;
9614
9654
  frontmatter = frontmatter.replace(/accessCount:\s*\d+/, `accessCount: ${newCount}`);
9615
9655
  }
9616
- (0, import_fs6.writeFileSync)(filePath, frontmatter + body);
9656
+ (0, import_fs7.writeFileSync)(filePath, frontmatter + body);
9617
9657
  }
9618
9658
  };
9619
9659
  }
9620
9660
  });
9621
9661
 
9622
9662
  // packages/orchestrator/src/memory-compactor.ts
9623
- var import_fs7, import_path8, MAX_ARCHIVE_LINES, MemoryCompactor;
9663
+ var import_fs8, import_path9, MAX_ARCHIVE_LINES, MemoryCompactor;
9624
9664
  var init_memory_compactor = __esm({
9625
9665
  "packages/orchestrator/src/memory-compactor.ts"() {
9626
9666
  "use strict";
9627
- import_fs7 = require("fs");
9628
- import_path8 = require("path");
9667
+ import_fs8 = require("fs");
9668
+ import_path9 = require("path");
9629
9669
  MAX_ARCHIVE_LINES = 5e3;
9630
9670
  MemoryCompactor = class {
9631
9671
  constructor(projectRoot) {
@@ -9637,32 +9677,32 @@ var init_memory_compactor = __esm({
9637
9677
  return (importance ?? 0.5) * (1 / (1 + days / 30));
9638
9678
  }
9639
9679
  compactIfNeeded(agentId, maxEntries = 20) {
9640
- const memDir = (0, import_path8.join)(this.projectRoot, ".gossip", "agents", agentId, "memory");
9641
- const tasksPath = (0, import_path8.join)(memDir, "tasks.jsonl");
9642
- const lockPath = (0, import_path8.join)(memDir, "tasks.jsonl.lock");
9643
- if (!(0, import_fs7.existsSync)(tasksPath)) return { archived: 0 };
9644
- if ((0, import_fs7.existsSync)(lockPath)) {
9680
+ const memDir = (0, import_path9.join)(this.projectRoot, ".gossip", "agents", agentId, "memory");
9681
+ const tasksPath = (0, import_path9.join)(memDir, "tasks.jsonl");
9682
+ const lockPath = (0, import_path9.join)(memDir, "tasks.jsonl.lock");
9683
+ if (!(0, import_fs8.existsSync)(tasksPath)) return { archived: 0 };
9684
+ if ((0, import_fs8.existsSync)(lockPath)) {
9645
9685
  try {
9646
- const lockTs = parseInt((0, import_fs7.readFileSync)(lockPath, "utf-8"), 10);
9686
+ const lockTs = parseInt((0, import_fs8.readFileSync)(lockPath, "utf-8"), 10);
9647
9687
  if (!Number.isNaN(lockTs) && Date.now() - lockTs < 6e4) return { archived: 0 };
9648
- (0, import_fs7.unlinkSync)(lockPath);
9688
+ (0, import_fs8.unlinkSync)(lockPath);
9649
9689
  } catch {
9650
9690
  try {
9651
- (0, import_fs7.unlinkSync)(lockPath);
9691
+ (0, import_fs8.unlinkSync)(lockPath);
9652
9692
  } catch {
9653
9693
  return { archived: 0 };
9654
9694
  }
9655
9695
  }
9656
9696
  }
9657
9697
  try {
9658
- const fd = (0, import_fs7.openSync)(lockPath, import_fs7.constants.O_WRONLY | import_fs7.constants.O_CREAT | import_fs7.constants.O_EXCL);
9659
- (0, import_fs7.writeFileSync)(fd, `${Date.now()}`);
9660
- (0, import_fs7.closeSync)(fd);
9698
+ const fd = (0, import_fs8.openSync)(lockPath, import_fs8.constants.O_WRONLY | import_fs8.constants.O_CREAT | import_fs8.constants.O_EXCL);
9699
+ (0, import_fs8.writeFileSync)(fd, `${Date.now()}`);
9700
+ (0, import_fs8.closeSync)(fd);
9661
9701
  } catch {
9662
9702
  return { archived: 0 };
9663
9703
  }
9664
9704
  try {
9665
- const lines = (0, import_fs7.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
9705
+ const lines = (0, import_fs8.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
9666
9706
  if (lines.length <= maxEntries) return { archived: 0 };
9667
9707
  const entries = [];
9668
9708
  let dropped = 0;
@@ -9679,7 +9719,7 @@ var init_memory_compactor = __esm({
9679
9719
  const toArchive = entries.slice(0, entries.length - maxEntries);
9680
9720
  const toKeep = entries.slice(entries.length - maxEntries);
9681
9721
  toKeep.sort((a, b) => a.idx - b.idx);
9682
- const archivePath = (0, import_path8.join)(memDir, "archive.jsonl");
9722
+ const archivePath = (0, import_path9.join)(memDir, "archive.jsonl");
9683
9723
  for (const item of toArchive) {
9684
9724
  const archived = {
9685
9725
  archivedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -9687,22 +9727,22 @@ var init_memory_compactor = __esm({
9687
9727
  warmth: item.warmth,
9688
9728
  entry: item.entry
9689
9729
  };
9690
- (0, import_fs7.appendFileSync)(archivePath, JSON.stringify(archived) + "\n");
9730
+ (0, import_fs8.appendFileSync)(archivePath, JSON.stringify(archived) + "\n");
9691
9731
  }
9692
9732
  try {
9693
- if ((0, import_fs7.existsSync)(archivePath)) {
9694
- const archiveLines = (0, import_fs7.readFileSync)(archivePath, "utf-8").trim().split("\n");
9733
+ if ((0, import_fs8.existsSync)(archivePath)) {
9734
+ const archiveLines = (0, import_fs8.readFileSync)(archivePath, "utf-8").trim().split("\n");
9695
9735
  if (archiveLines.length > MAX_ARCHIVE_LINES) {
9696
- (0, import_fs7.writeFileSync)(archivePath, archiveLines.slice(-MAX_ARCHIVE_LINES).join("\n") + "\n");
9736
+ (0, import_fs8.writeFileSync)(archivePath, archiveLines.slice(-MAX_ARCHIVE_LINES).join("\n") + "\n");
9697
9737
  }
9698
9738
  }
9699
9739
  } catch {
9700
9740
  }
9701
- (0, import_fs7.writeFileSync)(tasksPath, toKeep.map((e) => e.line).join("\n") + "\n");
9741
+ (0, import_fs8.writeFileSync)(tasksPath, toKeep.map((e) => e.line).join("\n") + "\n");
9702
9742
  return { archived: toArchive.length, dropped: dropped || void 0, message: `Compacted ${toArchive.length} memories for ${agentId}${dropped ? ` (${dropped} malformed lines dropped)` : ""}` };
9703
9743
  } finally {
9704
9744
  try {
9705
- (0, import_fs7.unlinkSync)(lockPath);
9745
+ (0, import_fs8.unlinkSync)(lockPath);
9706
9746
  } catch {
9707
9747
  }
9708
9748
  }
@@ -9721,11 +9761,11 @@ function sanitizeName(name) {
9721
9761
  function discoverProjectStructure(projectRoot) {
9722
9762
  try {
9723
9763
  const parts = [];
9724
- const entries = (0, import_fs8.readdirSync)(projectRoot, { withFileTypes: true });
9764
+ const entries = (0, import_fs9.readdirSync)(projectRoot, { withFileTypes: true });
9725
9765
  for (const entry of entries) {
9726
9766
  if (!entry.isDirectory() || isSkipped(entry.name)) continue;
9727
9767
  try {
9728
- const allChildren = (0, import_fs8.readdirSync)((0, import_path9.join)(projectRoot, entry.name)).filter((f) => !f.startsWith("."));
9768
+ const allChildren = (0, import_fs9.readdirSync)((0, import_path10.join)(projectRoot, entry.name)).filter((f) => !f.startsWith("."));
9729
9769
  if (allChildren.length === 0) continue;
9730
9770
  const shown = allChildren.slice(0, MAX_CHILDREN).map(sanitizeName);
9731
9771
  const suffix = allChildren.length > MAX_CHILDREN ? `, ...${allChildren.length - MAX_CHILDREN} more` : "";
@@ -9738,12 +9778,12 @@ function discoverProjectStructure(projectRoot) {
9738
9778
  return [];
9739
9779
  }
9740
9780
  }
9741
- var import_fs8, import_path9, SKIP, MAX_CHILDREN;
9781
+ var import_fs9, import_path10, SKIP, MAX_CHILDREN;
9742
9782
  var init_project_structure = __esm({
9743
9783
  "packages/orchestrator/src/project-structure.ts"() {
9744
9784
  "use strict";
9745
- import_fs8 = require("fs");
9746
- import_path9 = require("path");
9785
+ import_fs9 = require("fs");
9786
+ import_path10 = require("path");
9747
9787
  SKIP = /* @__PURE__ */ new Set([
9748
9788
  "node_modules",
9749
9789
  "build",
@@ -9784,12 +9824,12 @@ function truncateStartAndEnd(text, maxLen) {
9784
9824
 
9785
9825
  ${text.slice(-tail)}`;
9786
9826
  }
9787
- var import_fs9, import_path10, MemoryWriter;
9827
+ var import_fs10, import_path11, MemoryWriter;
9788
9828
  var init_memory_writer = __esm({
9789
9829
  "packages/orchestrator/src/memory-writer.ts"() {
9790
9830
  "use strict";
9791
- import_fs9 = require("fs");
9792
- import_path10 = require("path");
9831
+ import_fs10 = require("fs");
9832
+ import_path11 = require("path");
9793
9833
  init_memory_compactor();
9794
9834
  init_project_structure();
9795
9835
  MemoryWriter = class {
@@ -9802,12 +9842,12 @@ var init_memory_writer = __esm({
9802
9842
  this.summaryLlm = llm;
9803
9843
  }
9804
9844
  getMemDir(agentId) {
9805
- return (0, import_path10.join)(this.projectRoot, ".gossip", "agents", agentId, "memory");
9845
+ return (0, import_path11.join)(this.projectRoot, ".gossip", "agents", agentId, "memory");
9806
9846
  }
9807
9847
  ensureDirs(agentId) {
9808
9848
  const memDir = this.getMemDir(agentId);
9809
- (0, import_fs9.mkdirSync)((0, import_path10.join)(memDir, "knowledge"), { recursive: true });
9810
- (0, import_fs9.mkdirSync)((0, import_path10.join)(memDir, "calibration"), { recursive: true });
9849
+ (0, import_fs10.mkdirSync)((0, import_path11.join)(memDir, "knowledge"), { recursive: true });
9850
+ (0, import_fs10.mkdirSync)((0, import_path11.join)(memDir, "calibration"), { recursive: true });
9811
9851
  return memDir;
9812
9852
  }
9813
9853
  async writeTaskEntry(agentId, data) {
@@ -9825,7 +9865,7 @@ var init_memory_writer = __esm({
9825
9865
  importance: this.deriveImportance(data.scores),
9826
9866
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
9827
9867
  };
9828
- (0, import_fs9.appendFileSync)((0, import_path10.join)(memDir, "tasks.jsonl"), JSON.stringify(entry) + "\n");
9868
+ (0, import_fs10.appendFileSync)((0, import_path11.join)(memDir, "tasks.jsonl"), JSON.stringify(entry) + "\n");
9829
9869
  }
9830
9870
  /**
9831
9871
  * Extract key facts from a task result and write as a knowledge entry.
@@ -9834,7 +9874,7 @@ var init_memory_writer = __esm({
9834
9874
  */
9835
9875
  async writeKnowledgeFromResult(agentId, data) {
9836
9876
  const memDir = this.ensureDirs(agentId);
9837
- const knowledgeDir = (0, import_path10.join)(memDir, "knowledge");
9877
+ const knowledgeDir = (0, import_path11.join)(memDir, "knowledge");
9838
9878
  const safeResult = data.result.length > 5e4 ? data.result.slice(0, 5e4) : data.result;
9839
9879
  let cognitiveSummary = null;
9840
9880
  if (this.summaryLlm) {
@@ -9884,7 +9924,7 @@ ${cleanSummary}` : cleanSummary;
9884
9924
  ...data.agentAccuracy !== void 0 && data.agentAccuracy < 0.4 ? ["> \u26A0 This agent has low accuracy (" + (data.agentAccuracy * 100).toFixed(0) + "%). Treat factual claims as unverified.\n"] : [],
9885
9925
  body
9886
9926
  ].join("\n");
9887
- (0, import_fs9.writeFileSync)((0, import_path10.join)(knowledgeDir, filename), content);
9927
+ (0, import_fs10.writeFileSync)((0, import_path11.join)(knowledgeDir, filename), content);
9888
9928
  }
9889
9929
  /**
9890
9930
  * Generate a cognitive summary — what the agent learned, not just what it saw.
@@ -9925,7 +9965,7 @@ ${truncateStartAndEnd(result, 4e3)}`
9925
9965
  /** Session summary data shared across public methods */
9926
9966
  sessionSummaryData(data) {
9927
9967
  const memDir = this.ensureDirs("_project");
9928
- const knowledgeDir = (0, import_path10.join)(memDir, "knowledge");
9968
+ const knowledgeDir = (0, import_path11.join)(memDir, "knowledge");
9929
9969
  const now = /* @__PURE__ */ new Date();
9930
9970
  const timestamp = now.toISOString().replace(/[:.]/g, "-").slice(0, 19);
9931
9971
  const today = now.toISOString().split("T")[0];
@@ -9948,9 +9988,9 @@ ${discovered.join("\n")}
9948
9988
  let existingMemoriesContext = "";
9949
9989
  const existingFiles = [];
9950
9990
  try {
9951
- const files = (0, import_fs9.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md") && !f.endsWith("-session.md"));
9991
+ const files = (0, import_fs10.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md") && !f.endsWith("-session.md"));
9952
9992
  for (const f of files) {
9953
- const content = (0, import_fs9.readFileSync)((0, import_path10.join)(knowledgeDir, f), "utf-8");
9993
+ const content = (0, import_fs10.readFileSync)((0, import_path11.join)(knowledgeDir, f), "utf-8");
9954
9994
  const descMatch = content.match(/description:\s*(.+)/);
9955
9995
  const desc = descMatch ? descMatch[1].trim() : "(no description)";
9956
9996
  existingFiles.push(f);
@@ -10060,10 +10100,18 @@ ${rawInput.slice(0, SESSION_SUMMARY_MAX_CHARS)}`;
10060
10100
  summaryBody = raw;
10061
10101
  } else {
10062
10102
  rawLlmResponse = raw;
10063
- const hasSummaryLine = /^SUMMARY:\s*.+/m.test(raw);
10064
10103
  const hasSectionHeader = /^##\s+\w/m.test(raw);
10065
- if (!hasSummaryLine || !hasSectionHeader) {
10104
+ if (!hasSectionHeader) {
10066
10105
  process.stderr.write("[gossipcat] Session summary missing required structure, using raw fallback\n");
10106
+ try {
10107
+ const debugPath = (0, import_path11.join)(memDir, "last-malformed-summary.txt");
10108
+ (0, import_fs10.writeFileSync)(debugPath, `# Malformed session summary @ ${timestamp}
10109
+ # No ## header found in LLM output.
10110
+
10111
+ ---
10112
+ ${raw}`);
10113
+ } catch {
10114
+ }
10067
10115
  summaryBody = `> \u26A0\uFE0F LLM summary malformed \u2014 raw data below.
10068
10116
 
10069
10117
  ${rawInput.slice(0, SESSION_SUMMARY_MAX_CHARS)}`;
@@ -10105,15 +10153,15 @@ ${rawInput.slice(0, SESSION_SUMMARY_MAX_CHARS)}`;
10105
10153
  if (staleFiles.length > 0) {
10106
10154
  for (const sf of staleFiles) {
10107
10155
  try {
10108
- const filePath = (0, import_path10.join)(knowledgeDir, sf);
10109
- let fileContent = (0, import_fs9.readFileSync)(filePath, "utf-8");
10156
+ const filePath = (0, import_path11.join)(knowledgeDir, sf);
10157
+ let fileContent = (0, import_fs10.readFileSync)(filePath, "utf-8");
10110
10158
  fileContent = fileContent.replace(/importance:\s*[\d.]+/, "importance: 0.1");
10111
10159
  if (!/status:/.test(fileContent)) {
10112
10160
  fileContent = fileContent.replace(/\n---/, "\nstatus: shipped\n---");
10113
10161
  } else {
10114
10162
  fileContent = fileContent.replace(/status:\s*.+/, "status: shipped");
10115
10163
  }
10116
- (0, import_fs9.writeFileSync)(filePath, fileContent);
10164
+ (0, import_fs10.writeFileSync)(filePath, fileContent);
10117
10165
  process.stderr.write(`[gossipcat] \u{1F5DC}\uFE0F Marked stale: ${sf}
10118
10166
  `);
10119
10167
  } catch {
@@ -10134,8 +10182,8 @@ ${rawInput.slice(0, SESSION_SUMMARY_MAX_CHARS)}`;
10134
10182
  "",
10135
10183
  summaryBody
10136
10184
  ].filter((l) => l !== "").join("\n");
10137
- (0, import_fs9.writeFileSync)((0, import_path10.join)(knowledgeDir, filename), content);
10138
- const nextSessionPath = (0, import_path10.join)(this.projectRoot, ".gossip", "next-session.md");
10185
+ (0, import_fs10.writeFileSync)((0, import_path11.join)(knowledgeDir, filename), content);
10186
+ const nextSessionPath = (0, import_path11.join)(this.projectRoot, ".gossip", "next-session.md");
10139
10187
  const openMatch = summaryBody.match(/##\s+Open[^\n]*\n([\s\S]*?)(?=\n##|\s*$)/i);
10140
10188
  const NEXT_SESSION_MAX_CHARS = 1500;
10141
10189
  const nextSessionContent = openMatch ? `# Next Session
@@ -10145,11 +10193,11 @@ ${openMatch[0].trim()}
10145
10193
 
10146
10194
  ${truncateAtWord(summaryBody, NEXT_SESSION_MAX_CHARS)}
10147
10195
  `;
10148
- (0, import_fs9.writeFileSync)(nextSessionPath, nextSessionContent);
10149
- const migrationTasksPath = (0, import_path10.join)(memDir, "tasks.jsonl");
10150
- if ((0, import_fs9.existsSync)(migrationTasksPath)) {
10196
+ (0, import_fs10.writeFileSync)(nextSessionPath, nextSessionContent);
10197
+ const migrationTasksPath = (0, import_path11.join)(memDir, "tasks.jsonl");
10198
+ if ((0, import_fs10.existsSync)(migrationTasksPath)) {
10151
10199
  try {
10152
- const mLines = (0, import_fs9.readFileSync)(migrationTasksPath, "utf-8").trim().split("\n").filter(Boolean);
10200
+ const mLines = (0, import_fs10.readFileSync)(migrationTasksPath, "utf-8").trim().split("\n").filter(Boolean);
10153
10201
  let migrated = false;
10154
10202
  const fixed = mLines.map((line) => {
10155
10203
  try {
@@ -10163,7 +10211,7 @@ ${truncateAtWord(summaryBody, NEXT_SESSION_MAX_CHARS)}
10163
10211
  return line;
10164
10212
  }
10165
10213
  });
10166
- if (migrated) (0, import_fs9.writeFileSync)(migrationTasksPath, fixed.join("\n") + "\n");
10214
+ if (migrated) (0, import_fs10.writeFileSync)(migrationTasksPath, fixed.join("\n") + "\n");
10167
10215
  } catch {
10168
10216
  }
10169
10217
  }
@@ -10188,10 +10236,10 @@ ${truncateAtWord(summaryBody, NEXT_SESSION_MAX_CHARS)}
10188
10236
  /** Shared warmth-aware pruning — evicts lowest-warmth files, respects pinned */
10189
10237
  pruneKnowledgeDir(knowledgeDir, maxFiles) {
10190
10238
  try {
10191
- const existing = (0, import_fs9.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md") && !f.endsWith("-session.md")).sort();
10239
+ const existing = (0, import_fs10.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md") && !f.endsWith("-session.md")).sort();
10192
10240
  if (existing.length >= maxFiles) {
10193
10241
  const scored = existing.map((f) => {
10194
- const content = (0, import_fs9.readFileSync)((0, import_path10.join)(knowledgeDir, f), "utf-8");
10242
+ const content = (0, import_fs10.readFileSync)((0, import_path11.join)(knowledgeDir, f), "utf-8");
10195
10243
  const importance = parseFloat(content.match(/importance:\s*([\d.]+)/)?.[1] ?? "0.5");
10196
10244
  const isPinned = /pinned:\s*true/i.test(content);
10197
10245
  const ts = f.slice(0, 19).replace(/^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})/, "$1T$2:$3:$4");
@@ -10210,10 +10258,10 @@ ${truncateAtWord(summaryBody, NEXT_SESSION_MAX_CHARS)}
10210
10258
  );
10211
10259
  }
10212
10260
  for (const item of toEvict) {
10213
- (0, import_fs9.unlinkSync)((0, import_path10.join)(knowledgeDir, item.file));
10261
+ (0, import_fs10.unlinkSync)((0, import_path11.join)(knowledgeDir, item.file));
10214
10262
  }
10215
10263
  }
10216
- const sessionFiles = (0, import_fs9.readdirSync)(knowledgeDir).filter((f) => f.endsWith("-session.md")).sort();
10264
+ const sessionFiles = (0, import_fs10.readdirSync)(knowledgeDir).filter((f) => f.endsWith("-session.md")).sort();
10217
10265
  const MAX_SESSION_FILES = 5;
10218
10266
  const SESSION_TTL_DAYS = 14;
10219
10267
  for (const sf of sessionFiles) {
@@ -10221,10 +10269,10 @@ ${truncateAtWord(summaryBody, NEXT_SESSION_MAX_CHARS)}
10221
10269
  const ts = sf.slice(0, 19).replace(/^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})/, "$1T$2:$3:$4");
10222
10270
  const days = (Date.now() - new Date(ts).getTime()) / 864e5;
10223
10271
  if (days > SESSION_TTL_DAYS) {
10224
- const sfPath = (0, import_path10.join)(knowledgeDir, sf);
10225
- const sfContent = (0, import_fs9.readFileSync)(sfPath, "utf-8");
10272
+ const sfPath = (0, import_path11.join)(knowledgeDir, sf);
10273
+ const sfContent = (0, import_fs10.readFileSync)(sfPath, "utf-8");
10226
10274
  if (!/importance:\s*0\.1/.test(sfContent)) {
10227
- (0, import_fs9.writeFileSync)(sfPath, sfContent.replace(/importance:\s*[\d.]+/, "importance: 0.1"));
10275
+ (0, import_fs10.writeFileSync)(sfPath, sfContent.replace(/importance:\s*[\d.]+/, "importance: 0.1"));
10228
10276
  }
10229
10277
  }
10230
10278
  } catch {
@@ -10235,7 +10283,7 @@ ${truncateAtWord(summaryBody, NEXT_SESSION_MAX_CHARS)}
10235
10283
  const bodies = [];
10236
10284
  for (const sf of toCompact) {
10237
10285
  try {
10238
- const sfContent = (0, import_fs9.readFileSync)((0, import_path10.join)(knowledgeDir, sf), "utf-8");
10286
+ const sfContent = (0, import_fs10.readFileSync)((0, import_path11.join)(knowledgeDir, sf), "utf-8");
10239
10287
  const body = sfContent.split("---").slice(2).join("---").trim();
10240
10288
  if (body) bodies.push(body.slice(0, 800));
10241
10289
  } catch {
@@ -10255,10 +10303,10 @@ ${truncateAtWord(summaryBody, NEXT_SESSION_MAX_CHARS)}
10255
10303
  "",
10256
10304
  ...bodies
10257
10305
  ].join("\n").slice(0, 3e3);
10258
- (0, import_fs9.writeFileSync)((0, import_path10.join)(knowledgeDir, digestName), digestContent);
10306
+ (0, import_fs10.writeFileSync)((0, import_path11.join)(knowledgeDir, digestName), digestContent);
10259
10307
  for (const sf of toCompact) {
10260
10308
  try {
10261
- (0, import_fs9.unlinkSync)((0, import_path10.join)(knowledgeDir, sf));
10309
+ (0, import_fs10.unlinkSync)((0, import_path11.join)(knowledgeDir, sf));
10262
10310
  } catch {
10263
10311
  }
10264
10312
  }
@@ -10441,7 +10489,7 @@ ${result}`;
10441
10489
  writeConsensusKnowledge(agentId, findings) {
10442
10490
  if (findings.length === 0) return;
10443
10491
  const memDir = this.ensureDirs(agentId);
10444
- const knowledgeDir = (0, import_path10.join)(memDir, "knowledge");
10492
+ const knowledgeDir = (0, import_path11.join)(memDir, "knowledge");
10445
10493
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
10446
10494
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
10447
10495
  const filename = `${timestamp}-consensus.md`;
@@ -10471,7 +10519,7 @@ ${result}`;
10471
10519
  })
10472
10520
  ].join("\n");
10473
10521
  this.pruneKnowledgeDir(knowledgeDir, 25);
10474
- (0, import_fs9.writeFileSync)((0, import_path10.join)(knowledgeDir, filename), content);
10522
+ (0, import_fs10.writeFileSync)((0, import_path11.join)(knowledgeDir, filename), content);
10475
10523
  }
10476
10524
  /**
10477
10525
  * Update task memory importance based on consensus signals.
@@ -10494,14 +10542,14 @@ ${result}`;
10494
10542
  taskAdj.set(s.taskId, (taskAdj.get(s.taskId) ?? 0) + weight);
10495
10543
  }
10496
10544
  for (const [agentId, taskAdjustments] of adjustments) {
10497
- const memDir = (0, import_path10.join)(this.projectRoot, ".gossip", "agents", agentId, "memory");
10498
- const tasksPath = (0, import_path10.join)(memDir, "tasks.jsonl");
10499
- const lockPath = (0, import_path10.join)(memDir, "tasks.jsonl.lock");
10500
- if (!(0, import_fs9.existsSync)(tasksPath)) continue;
10501
- if ((0, import_fs9.existsSync)(lockPath)) continue;
10545
+ const memDir = (0, import_path11.join)(this.projectRoot, ".gossip", "agents", agentId, "memory");
10546
+ const tasksPath = (0, import_path11.join)(memDir, "tasks.jsonl");
10547
+ const lockPath = (0, import_path11.join)(memDir, "tasks.jsonl.lock");
10548
+ if (!(0, import_fs10.existsSync)(tasksPath)) continue;
10549
+ if ((0, import_fs10.existsSync)(lockPath)) continue;
10502
10550
  try {
10503
- (0, import_fs9.writeFileSync)(lockPath, `${Date.now()}`);
10504
- const lines = (0, import_fs9.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
10551
+ (0, import_fs10.writeFileSync)(lockPath, `${Date.now()}`);
10552
+ const lines = (0, import_fs10.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
10505
10553
  let modified = false;
10506
10554
  const updated = lines.map((line) => {
10507
10555
  try {
@@ -10518,12 +10566,12 @@ ${result}`;
10518
10566
  }
10519
10567
  });
10520
10568
  if (modified) {
10521
- (0, import_fs9.writeFileSync)(tasksPath, updated.join("\n") + "\n");
10569
+ (0, import_fs10.writeFileSync)(tasksPath, updated.join("\n") + "\n");
10522
10570
  }
10523
10571
  } catch {
10524
10572
  } finally {
10525
10573
  try {
10526
- (0, import_fs9.unlinkSync)(lockPath);
10574
+ (0, import_fs10.unlinkSync)(lockPath);
10527
10575
  } catch {
10528
10576
  }
10529
10577
  }
@@ -10533,13 +10581,13 @@ ${result}`;
10533
10581
  const memDir = this.getMemDir(agentId);
10534
10582
  const parts = [`# Agent Memory \u2014 ${agentId}
10535
10583
  `];
10536
- const knowledgeDir = (0, import_path10.join)(memDir, "knowledge");
10537
- if ((0, import_fs9.existsSync)(knowledgeDir)) {
10538
- const files = (0, import_fs9.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md")).sort().reverse();
10584
+ const knowledgeDir = (0, import_path11.join)(memDir, "knowledge");
10585
+ if ((0, import_fs10.existsSync)(knowledgeDir)) {
10586
+ const files = (0, import_fs10.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md")).sort().reverse();
10539
10587
  if (files.length > 0) {
10540
10588
  parts.push("## Knowledge (most recent first)");
10541
10589
  for (const file2 of files) {
10542
- const content = (0, import_fs9.readFileSync)((0, import_path10.join)(knowledgeDir, file2), "utf-8");
10590
+ const content = (0, import_fs10.readFileSync)((0, import_path11.join)(knowledgeDir, file2), "utf-8");
10543
10591
  const descMatch = content.match(/description:\s*(.+)/);
10544
10592
  const desc = descMatch ? descMatch[1].trim() : file2.replace(".md", "");
10545
10593
  parts.push(`- [${file2.replace(".md", "")}](knowledge/${file2}) \u2014 ${desc}`);
@@ -10547,17 +10595,17 @@ ${result}`;
10547
10595
  parts.push("");
10548
10596
  }
10549
10597
  }
10550
- const calPath = (0, import_path10.join)(memDir, "calibration", "accuracy.md");
10551
- if ((0, import_fs9.existsSync)(calPath)) {
10552
- const content = (0, import_fs9.readFileSync)(calPath, "utf-8");
10598
+ const calPath = (0, import_path11.join)(memDir, "calibration", "accuracy.md");
10599
+ if ((0, import_fs10.existsSync)(calPath)) {
10600
+ const content = (0, import_fs10.readFileSync)(calPath, "utf-8");
10553
10601
  const descMatch = content.match(/description:\s*(.+)/);
10554
10602
  parts.push("## Calibration");
10555
10603
  parts.push(`- [accuracy](calibration/accuracy.md) \u2014 ${descMatch ? descMatch[1].trim() : "accuracy data"}`);
10556
10604
  parts.push("");
10557
10605
  }
10558
- const tasksPath = (0, import_path10.join)(memDir, "tasks.jsonl");
10559
- if ((0, import_fs9.existsSync)(tasksPath)) {
10560
- const lines = (0, import_fs9.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
10606
+ const tasksPath = (0, import_path11.join)(memDir, "tasks.jsonl");
10607
+ if ((0, import_fs10.existsSync)(tasksPath)) {
10608
+ const lines = (0, import_fs10.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
10561
10609
  const recent = lines.slice(-5).reverse();
10562
10610
  if (recent.length > 0) {
10563
10611
  parts.push("## Recent Tasks");
@@ -10574,12 +10622,12 @@ ${result}`;
10574
10622
  }
10575
10623
  }
10576
10624
  try {
10577
- const knowledgeDir2 = (0, import_path10.join)(memDir, "knowledge");
10578
- if ((0, import_fs9.existsSync)(knowledgeDir2)) {
10579
- const knowledgeFiles = (0, import_fs9.readdirSync)(knowledgeDir2).filter((f) => f.endsWith(".md")).sort().reverse().slice(0, 5);
10625
+ const knowledgeDir2 = (0, import_path11.join)(memDir, "knowledge");
10626
+ if ((0, import_fs10.existsSync)(knowledgeDir2)) {
10627
+ const knowledgeFiles = (0, import_fs10.readdirSync)(knowledgeDir2).filter((f) => f.endsWith(".md")).sort().reverse().slice(0, 5);
10580
10628
  const patterns = [];
10581
10629
  for (const kf of knowledgeFiles) {
10582
- const kContent = (0, import_fs9.readFileSync)((0, import_path10.join)(knowledgeDir2, kf), "utf-8");
10630
+ const kContent = (0, import_fs10.readFileSync)((0, import_path11.join)(knowledgeDir2, kf), "utf-8");
10583
10631
  const decisionsMatch = kContent.match(/Decisions: (.+)/);
10584
10632
  if (decisionsMatch) patterns.push(decisionsMatch[1].trim());
10585
10633
  const failuresMatch = kContent.match(/Failures: (.+)/);
@@ -10591,19 +10639,19 @@ ${result}`;
10591
10639
  }
10592
10640
  } catch {
10593
10641
  }
10594
- (0, import_fs9.writeFileSync)((0, import_path10.join)(memDir, "MEMORY.md"), parts.join("\n"));
10642
+ (0, import_fs10.writeFileSync)((0, import_path11.join)(memDir, "MEMORY.md"), parts.join("\n"));
10595
10643
  }
10596
10644
  };
10597
10645
  }
10598
10646
  });
10599
10647
 
10600
10648
  // packages/orchestrator/src/task-graph.ts
10601
- var import_fs10, import_path11, MAX_SCAN_LINES, TaskGraph;
10649
+ var import_fs11, import_path12, MAX_SCAN_LINES, TaskGraph;
10602
10650
  var init_task_graph = __esm({
10603
10651
  "packages/orchestrator/src/task-graph.ts"() {
10604
10652
  "use strict";
10605
- import_fs10 = require("fs");
10606
- import_path11 = require("path");
10653
+ import_fs11 = require("fs");
10654
+ import_path12 = require("path");
10607
10655
  MAX_SCAN_LINES = 1e3;
10608
10656
  TaskGraph = class {
10609
10657
  graphPath;
@@ -10613,14 +10661,14 @@ var init_task_graph = __esm({
10613
10661
  // taskId → last event line number
10614
10662
  eventCount = 0;
10615
10663
  constructor(projectRoot) {
10616
- const gossipDir2 = (0, import_path11.join)(projectRoot, ".gossip");
10617
- (0, import_fs10.mkdirSync)(gossipDir2, { recursive: true });
10618
- this.graphPath = (0, import_path11.join)(gossipDir2, "task-graph.jsonl");
10619
- this.syncMetaPath = (0, import_path11.join)(gossipDir2, "task-graph-sync.json");
10620
- this.indexPath = (0, import_path11.join)(gossipDir2, "task-graph-index.json");
10664
+ const gossipDir2 = (0, import_path12.join)(projectRoot, ".gossip");
10665
+ (0, import_fs11.mkdirSync)(gossipDir2, { recursive: true });
10666
+ this.graphPath = (0, import_path12.join)(gossipDir2, "task-graph.jsonl");
10667
+ this.syncMetaPath = (0, import_path12.join)(gossipDir2, "task-graph-sync.json");
10668
+ this.indexPath = (0, import_path12.join)(gossipDir2, "task-graph-index.json");
10621
10669
  this.loadIndex();
10622
- if ((0, import_fs10.existsSync)(this.graphPath)) {
10623
- const buf = (0, import_fs10.readFileSync)(this.graphPath);
10670
+ if ((0, import_fs11.existsSync)(this.graphPath)) {
10671
+ const buf = (0, import_fs11.readFileSync)(this.graphPath);
10624
10672
  let count = 0;
10625
10673
  for (let i = 0; i < buf.length; i++) {
10626
10674
  if (buf[i] === 10) count++;
@@ -10629,9 +10677,9 @@ var init_task_graph = __esm({
10629
10677
  }
10630
10678
  }
10631
10679
  loadIndex() {
10632
- if ((0, import_fs10.existsSync)(this.indexPath)) {
10680
+ if ((0, import_fs11.existsSync)(this.indexPath)) {
10633
10681
  try {
10634
- const data = JSON.parse((0, import_fs10.readFileSync)(this.indexPath, "utf-8"));
10682
+ const data = JSON.parse((0, import_fs11.readFileSync)(this.indexPath, "utf-8"));
10635
10683
  this.index = new Map(Object.entries(data).map(([k, v]) => [k, Number(v)]));
10636
10684
  } catch {
10637
10685
  }
@@ -10639,10 +10687,10 @@ var init_task_graph = __esm({
10639
10687
  }
10640
10688
  /** Save index to disk (call explicitly, not on every append) */
10641
10689
  flushIndex() {
10642
- (0, import_fs10.writeFileSync)(this.indexPath, JSON.stringify(Object.fromEntries(this.index)));
10690
+ (0, import_fs11.writeFileSync)(this.indexPath, JSON.stringify(Object.fromEntries(this.index)));
10643
10691
  }
10644
10692
  appendEvent(event) {
10645
- (0, import_fs10.appendFileSync)(this.graphPath, JSON.stringify(event) + "\n");
10693
+ (0, import_fs11.appendFileSync)(this.graphPath, JSON.stringify(event) + "\n");
10646
10694
  if ("taskId" in event) {
10647
10695
  this.index.set(event.taskId, this.eventCount);
10648
10696
  }
@@ -10724,8 +10772,8 @@ var init_task_graph = __esm({
10724
10772
  }
10725
10773
  // ── Read methods ─────────────────────────────────────────────────────
10726
10774
  readEvents() {
10727
- if (!(0, import_fs10.existsSync)(this.graphPath)) return [];
10728
- const content = (0, import_fs10.readFileSync)(this.graphPath, "utf-8");
10775
+ if (!(0, import_fs11.existsSync)(this.graphPath)) return [];
10776
+ const content = (0, import_fs11.readFileSync)(this.graphPath, "utf-8");
10729
10777
  const lines = content.trim().split("\n").filter(Boolean);
10730
10778
  const tail = lines.slice(-MAX_SCAN_LINES);
10731
10779
  return tail.map((line) => {
@@ -10807,14 +10855,14 @@ var init_task_graph = __esm({
10807
10855
  return this.eventCount;
10808
10856
  }
10809
10857
  getSyncMeta() {
10810
- if (!(0, import_fs10.existsSync)(this.syncMetaPath)) {
10858
+ if (!(0, import_fs11.existsSync)(this.syncMetaPath)) {
10811
10859
  return { lastSync: "", lastSyncEventCount: 0 };
10812
10860
  }
10813
- return JSON.parse((0, import_fs10.readFileSync)(this.syncMetaPath, "utf-8"));
10861
+ return JSON.parse((0, import_fs11.readFileSync)(this.syncMetaPath, "utf-8"));
10814
10862
  }
10815
10863
  updateSyncMeta(meta3) {
10816
10864
  const current = this.getSyncMeta();
10817
- (0, import_fs10.writeFileSync)(this.syncMetaPath, JSON.stringify({ ...current, ...meta3 }, null, 2));
10865
+ (0, import_fs11.writeFileSync)(this.syncMetaPath, JSON.stringify({ ...current, ...meta3 }, null, 2));
10818
10866
  }
10819
10867
  getUnsynced(lastSyncTimestamp) {
10820
10868
  if (!lastSyncTimestamp) return this.readEvents();
@@ -10825,12 +10873,12 @@ var init_task_graph = __esm({
10825
10873
  });
10826
10874
 
10827
10875
  // packages/orchestrator/src/skill-catalog.ts
10828
- var import_fs11, import_path12, SkillCatalog;
10876
+ var import_fs12, import_path13, SkillCatalog;
10829
10877
  var init_skill_catalog = __esm({
10830
10878
  "packages/orchestrator/src/skill-catalog.ts"() {
10831
10879
  "use strict";
10832
- import_fs11 = require("fs");
10833
- import_path12 = require("path");
10880
+ import_fs12 = require("fs");
10881
+ import_path13 = require("path");
10834
10882
  init_skill_name();
10835
10883
  init_skill_parser();
10836
10884
  SkillCatalog = class {
@@ -10839,11 +10887,11 @@ var init_skill_catalog = __esm({
10839
10887
  projectSkillsDir;
10840
10888
  projectFileMtimes = /* @__PURE__ */ new Map();
10841
10889
  constructor(projectRoot, catalogPath) {
10842
- const defaultPath = catalogPath || (0, import_path12.resolve)(__dirname, "default-skills", "catalog.json");
10843
- this.defaultSkillsDir = (0, import_path12.resolve)(__dirname, "default-skills");
10844
- this.projectSkillsDir = projectRoot ? (0, import_path12.join)(projectRoot, ".gossip", "skills") : null;
10890
+ const defaultPath = catalogPath || (0, import_path13.resolve)(__dirname, "default-skills", "catalog.json");
10891
+ this.defaultSkillsDir = (0, import_path13.resolve)(__dirname, "default-skills");
10892
+ this.projectSkillsDir = projectRoot ? (0, import_path13.join)(projectRoot, ".gossip", "skills") : null;
10845
10893
  try {
10846
- const raw = (0, import_fs11.readFileSync)(defaultPath, "utf-8");
10894
+ const raw = (0, import_fs12.readFileSync)(defaultPath, "utf-8");
10847
10895
  const data = JSON.parse(raw);
10848
10896
  this.entries = data.skills.map((s) => ({
10849
10897
  ...s,
@@ -10884,7 +10932,7 @@ var init_skill_catalog = __esm({
10884
10932
  }
10885
10933
  validate() {
10886
10934
  const issues = [];
10887
- const mdFiles = (0, import_fs11.readdirSync)(this.defaultSkillsDir).filter((f) => f.endsWith(".md")).map((f) => normalizeSkillName(f.replace(".md", "")));
10935
+ const mdFiles = (0, import_fs12.readdirSync)(this.defaultSkillsDir).filter((f) => f.endsWith(".md")).map((f) => normalizeSkillName(f.replace(".md", "")));
10888
10936
  for (const file2 of mdFiles) {
10889
10937
  if (!this.entries.find((e) => e.name === file2)) {
10890
10938
  issues.push(`Skill file '${file2}' has no catalog entry`);
@@ -10893,15 +10941,15 @@ var init_skill_catalog = __esm({
10893
10941
  return issues;
10894
10942
  }
10895
10943
  loadProjectSkills() {
10896
- if (!this.projectSkillsDir || !(0, import_fs11.existsSync)(this.projectSkillsDir)) return;
10897
- const files = (0, import_fs11.readdirSync)(this.projectSkillsDir).filter((f) => f.endsWith(".md"));
10944
+ if (!this.projectSkillsDir || !(0, import_fs12.existsSync)(this.projectSkillsDir)) return;
10945
+ const files = (0, import_fs12.readdirSync)(this.projectSkillsDir).filter((f) => f.endsWith(".md"));
10898
10946
  const newMtimes = /* @__PURE__ */ new Map();
10899
10947
  for (const file2 of files) {
10900
- const filePath = (0, import_path12.join)(this.projectSkillsDir, file2);
10948
+ const filePath = (0, import_path13.join)(this.projectSkillsDir, file2);
10901
10949
  try {
10902
- const mtime = (0, import_fs11.statSync)(filePath).mtimeMs;
10950
+ const mtime = (0, import_fs12.statSync)(filePath).mtimeMs;
10903
10951
  newMtimes.set(file2, mtime);
10904
- const content = (0, import_fs11.readFileSync)(filePath, "utf-8");
10952
+ const content = (0, import_fs12.readFileSync)(filePath, "utf-8");
10905
10953
  const fm = parseSkillFrontmatter(content);
10906
10954
  if (!fm) continue;
10907
10955
  const entry = {
@@ -10923,14 +10971,14 @@ var init_skill_catalog = __esm({
10923
10971
  this.projectFileMtimes = newMtimes;
10924
10972
  }
10925
10973
  reloadIfChanged() {
10926
- if (!this.projectSkillsDir || !(0, import_fs11.existsSync)(this.projectSkillsDir)) return;
10927
- const files = (0, import_fs11.readdirSync)(this.projectSkillsDir).filter((f) => f.endsWith(".md"));
10974
+ if (!this.projectSkillsDir || !(0, import_fs12.existsSync)(this.projectSkillsDir)) return;
10975
+ const files = (0, import_fs12.readdirSync)(this.projectSkillsDir).filter((f) => f.endsWith(".md"));
10928
10976
  let changed = files.length !== this.projectFileMtimes.size;
10929
10977
  if (!changed) {
10930
10978
  for (const file2 of files) {
10931
- const filePath = (0, import_path12.join)(this.projectSkillsDir, file2);
10979
+ const filePath = (0, import_path13.join)(this.projectSkillsDir, file2);
10932
10980
  try {
10933
- const mtime = (0, import_fs11.statSync)(filePath).mtimeMs;
10981
+ const mtime = (0, import_fs12.statSync)(filePath).mtimeMs;
10934
10982
  if (mtime !== this.projectFileMtimes.get(file2)) {
10935
10983
  changed = true;
10936
10984
  break;
@@ -10951,12 +10999,12 @@ var init_skill_catalog = __esm({
10951
10999
  });
10952
11000
 
10953
11001
  // packages/orchestrator/src/skill-gap-tracker.ts
10954
- var import_fs12, import_path13, MAX_LOG_LINES, TRUNCATE_TO, SkillGapTracker;
11002
+ var import_fs13, import_path14, MAX_LOG_LINES, TRUNCATE_TO, SkillGapTracker;
10955
11003
  var init_skill_gap_tracker = __esm({
10956
11004
  "packages/orchestrator/src/skill-gap-tracker.ts"() {
10957
11005
  "use strict";
10958
- import_fs12 = require("fs");
10959
- import_path13 = require("path");
11006
+ import_fs13 = require("fs");
11007
+ import_path14 = require("path");
10960
11008
  init_skill_name();
10961
11009
  MAX_LOG_LINES = 5e3;
10962
11010
  TRUNCATE_TO = 1e3;
@@ -10965,8 +11013,8 @@ var init_skill_gap_tracker = __esm({
10965
11013
  resolutionsPath;
10966
11014
  resolutionsCache = null;
10967
11015
  constructor(projectRoot) {
10968
- this.gapLogPath = (0, import_path13.join)(projectRoot, ".gossip", "skill-gaps.jsonl");
10969
- this.resolutionsPath = (0, import_path13.join)(projectRoot, ".gossip", "skill-resolutions.json");
11016
+ this.gapLogPath = (0, import_path14.join)(projectRoot, ".gossip", "skill-gaps.jsonl");
11017
+ this.resolutionsPath = (0, import_path14.join)(projectRoot, ".gossip", "skill-resolutions.json");
10970
11018
  this.migrateResolutions();
10971
11019
  }
10972
11020
  checkThresholds() {
@@ -10994,9 +11042,9 @@ var init_skill_gap_tracker = __esm({
10994
11042
  const normalized = normalizeSkillName(skillName);
10995
11043
  const resolutions = this.loadResolutions();
10996
11044
  resolutions[normalized] = (/* @__PURE__ */ new Date()).toISOString();
10997
- const dir = (0, import_path13.join)(this.resolutionsPath, "..");
10998
- if (!(0, import_fs12.existsSync)(dir)) (0, import_fs12.mkdirSync)(dir, { recursive: true });
10999
- (0, import_fs12.writeFileSync)(this.resolutionsPath, JSON.stringify(resolutions, null, 2));
11045
+ const dir = (0, import_path14.join)(this.resolutionsPath, "..");
11046
+ if (!(0, import_fs13.existsSync)(dir)) (0, import_fs13.mkdirSync)(dir, { recursive: true });
11047
+ (0, import_fs13.writeFileSync)(this.resolutionsPath, JSON.stringify(resolutions, null, 2));
11000
11048
  this.resolutionsCache = resolutions;
11001
11049
  }
11002
11050
  getSuggestionsSince(agentId, sinceMs) {
@@ -11005,9 +11053,9 @@ var init_skill_gap_tracker = __esm({
11005
11053
  );
11006
11054
  }
11007
11055
  appendSuggestion(suggestion) {
11008
- const dir = (0, import_path13.join)(this.gapLogPath, "..");
11009
- if (!(0, import_fs12.existsSync)(dir)) (0, import_fs12.mkdirSync)(dir, { recursive: true });
11010
- (0, import_fs12.appendFileSync)(this.gapLogPath, JSON.stringify(suggestion) + "\n");
11056
+ const dir = (0, import_path14.join)(this.gapLogPath, "..");
11057
+ if (!(0, import_fs13.existsSync)(dir)) (0, import_fs13.mkdirSync)(dir, { recursive: true });
11058
+ (0, import_fs13.appendFileSync)(this.gapLogPath, JSON.stringify(suggestion) + "\n");
11011
11059
  this.truncateIfNeeded();
11012
11060
  }
11013
11061
  getPendingSkills() {
@@ -11035,9 +11083,9 @@ var init_skill_gap_tracker = __esm({
11035
11083
  );
11036
11084
  }
11037
11085
  readSuggestions() {
11038
- if (!(0, import_fs12.existsSync)(this.gapLogPath)) return [];
11086
+ if (!(0, import_fs13.existsSync)(this.gapLogPath)) return [];
11039
11087
  try {
11040
- const lines = (0, import_fs12.readFileSync)(this.gapLogPath, "utf-8").trim().split("\n").filter(Boolean);
11088
+ const lines = (0, import_fs13.readFileSync)(this.gapLogPath, "utf-8").trim().split("\n").filter(Boolean);
11041
11089
  return lines.map((line) => {
11042
11090
  try {
11043
11091
  return JSON.parse(line);
@@ -11051,12 +11099,12 @@ var init_skill_gap_tracker = __esm({
11051
11099
  }
11052
11100
  loadResolutions() {
11053
11101
  if (this.resolutionsCache) return this.resolutionsCache;
11054
- if (!(0, import_fs12.existsSync)(this.resolutionsPath)) {
11102
+ if (!(0, import_fs13.existsSync)(this.resolutionsPath)) {
11055
11103
  this.resolutionsCache = {};
11056
11104
  return this.resolutionsCache;
11057
11105
  }
11058
11106
  try {
11059
- this.resolutionsCache = JSON.parse((0, import_fs12.readFileSync)(this.resolutionsPath, "utf-8"));
11107
+ this.resolutionsCache = JSON.parse((0, import_fs13.readFileSync)(this.resolutionsPath, "utf-8"));
11060
11108
  return this.resolutionsCache;
11061
11109
  } catch {
11062
11110
  this.resolutionsCache = {};
@@ -11064,10 +11112,10 @@ var init_skill_gap_tracker = __esm({
11064
11112
  }
11065
11113
  }
11066
11114
  migrateResolutions() {
11067
- if ((0, import_fs12.existsSync)(this.resolutionsPath)) return;
11068
- if (!(0, import_fs12.existsSync)(this.gapLogPath)) return;
11115
+ if ((0, import_fs13.existsSync)(this.resolutionsPath)) return;
11116
+ if (!(0, import_fs13.existsSync)(this.gapLogPath)) return;
11069
11117
  try {
11070
- const lines = (0, import_fs12.readFileSync)(this.gapLogPath, "utf-8").trim().split("\n").filter(Boolean);
11118
+ const lines = (0, import_fs13.readFileSync)(this.gapLogPath, "utf-8").trim().split("\n").filter(Boolean);
11071
11119
  const resolutions = {};
11072
11120
  for (const line of lines) {
11073
11121
  try {
@@ -11079,21 +11127,21 @@ var init_skill_gap_tracker = __esm({
11079
11127
  }
11080
11128
  }
11081
11129
  if (Object.keys(resolutions).length > 0) {
11082
- const dir = (0, import_path13.join)(this.resolutionsPath, "..");
11083
- if (!(0, import_fs12.existsSync)(dir)) (0, import_fs12.mkdirSync)(dir, { recursive: true });
11084
- (0, import_fs12.writeFileSync)(this.resolutionsPath, JSON.stringify(resolutions, null, 2));
11130
+ const dir = (0, import_path14.join)(this.resolutionsPath, "..");
11131
+ if (!(0, import_fs13.existsSync)(dir)) (0, import_fs13.mkdirSync)(dir, { recursive: true });
11132
+ (0, import_fs13.writeFileSync)(this.resolutionsPath, JSON.stringify(resolutions, null, 2));
11085
11133
  this.resolutionsCache = resolutions;
11086
11134
  }
11087
11135
  } catch {
11088
11136
  }
11089
11137
  }
11090
11138
  truncateIfNeeded() {
11091
- if (!(0, import_fs12.existsSync)(this.gapLogPath)) return;
11139
+ if (!(0, import_fs13.existsSync)(this.gapLogPath)) return;
11092
11140
  try {
11093
- const content = (0, import_fs12.readFileSync)(this.gapLogPath, "utf-8");
11141
+ const content = (0, import_fs13.readFileSync)(this.gapLogPath, "utf-8");
11094
11142
  const lines = content.trim().split("\n").filter(Boolean);
11095
11143
  if (lines.length > MAX_LOG_LINES) {
11096
- (0, import_fs12.writeFileSync)(this.gapLogPath, lines.slice(-TRUNCATE_TO).join("\n") + "\n");
11144
+ (0, import_fs13.writeFileSync)(this.gapLogPath, lines.slice(-TRUNCATE_TO).join("\n") + "\n");
11097
11145
  }
11098
11146
  } catch {
11099
11147
  }
@@ -11103,12 +11151,12 @@ var init_skill_gap_tracker = __esm({
11103
11151
  });
11104
11152
 
11105
11153
  // packages/orchestrator/src/scope-tracker.ts
11106
- var import_path14, import_fs13, ScopeTracker;
11154
+ var import_path15, import_fs14, ScopeTracker;
11107
11155
  var init_scope_tracker = __esm({
11108
11156
  "packages/orchestrator/src/scope-tracker.ts"() {
11109
11157
  "use strict";
11110
- import_path14 = require("path");
11111
- import_fs13 = require("fs");
11158
+ import_path15 = require("path");
11159
+ import_fs14 = require("fs");
11112
11160
  ScopeTracker = class {
11113
11161
  // taskId → scope (for release)
11114
11162
  constructor(projectRoot) {
@@ -11119,15 +11167,15 @@ var init_scope_tracker = __esm({
11119
11167
  taskToScope = /* @__PURE__ */ new Map();
11120
11168
  normalize(scope) {
11121
11169
  if (!scope || !scope.trim()) throw new Error("Scope must not be empty");
11122
- const realRoot = (0, import_fs13.realpathSync)(this.projectRoot);
11123
- const abs = (0, import_path14.resolve)(realRoot, scope);
11170
+ const realRoot = (0, import_fs14.realpathSync)(this.projectRoot);
11171
+ const abs = (0, import_path15.resolve)(realRoot, scope);
11124
11172
  let real;
11125
11173
  try {
11126
- real = (0, import_fs13.realpathSync)(abs);
11174
+ real = (0, import_fs14.realpathSync)(abs);
11127
11175
  } catch {
11128
11176
  real = abs;
11129
11177
  }
11130
- const rel = (0, import_path14.relative)(realRoot, real);
11178
+ const rel = (0, import_path15.relative)(realRoot, real);
11131
11179
  if (rel.startsWith("..")) throw new Error(`Scope "${scope}" resolves outside project root`);
11132
11180
  if (rel === "") throw new Error(`Scope "${scope}" resolves to project root \u2014 too broad`);
11133
11181
  return rel.endsWith("/") ? rel : rel + "/";
@@ -11165,14 +11213,14 @@ var init_scope_tracker = __esm({
11165
11213
  });
11166
11214
 
11167
11215
  // packages/orchestrator/src/worktree-manager.ts
11168
- var import_child_process3, import_util8, import_promises2, import_path15, import_os, execFileAsync3, WorktreeManager;
11216
+ var import_child_process3, import_util8, import_promises2, import_path16, import_os, execFileAsync3, WorktreeManager;
11169
11217
  var init_worktree_manager = __esm({
11170
11218
  "packages/orchestrator/src/worktree-manager.ts"() {
11171
11219
  "use strict";
11172
11220
  import_child_process3 = require("child_process");
11173
11221
  import_util8 = require("util");
11174
11222
  import_promises2 = require("fs/promises");
11175
- import_path15 = require("path");
11223
+ import_path16 = require("path");
11176
11224
  import_os = require("os");
11177
11225
  execFileAsync3 = (0, import_util8.promisify)(import_child_process3.execFile);
11178
11226
  WorktreeManager = class {
@@ -11181,7 +11229,7 @@ var init_worktree_manager = __esm({
11181
11229
  }
11182
11230
  async create(taskId) {
11183
11231
  const branch = `gossip-${taskId}`;
11184
- const wtPath = await (0, import_promises2.mkdtemp)((0, import_path15.join)((0, import_os.tmpdir)(), "gossip-wt-"));
11232
+ const wtPath = await (0, import_promises2.mkdtemp)((0, import_path16.join)((0, import_os.tmpdir)(), "gossip-wt-"));
11185
11233
  await execFileAsync3("git", ["branch", branch, "HEAD"], { cwd: this.projectRoot });
11186
11234
  try {
11187
11235
  await execFileAsync3("git", ["worktree", "add", wtPath, branch], { cwd: this.projectRoot });
@@ -11256,12 +11304,12 @@ function getSeverityMultiplier(severity) {
11256
11304
  function clamp(v, min, max) {
11257
11305
  return Math.max(min, Math.min(max, v));
11258
11306
  }
11259
- var import_fs14, import_path16, CIRCUIT_BREAKER_THRESHOLD, NEGATIVE_SIGNALS, SIGNAL_EXPIRY_DAYS, KNOWN_SIGNALS, SEVERITY_MULTIPLIER, PerformanceReader;
11307
+ var import_fs15, import_path17, CIRCUIT_BREAKER_THRESHOLD, NEGATIVE_SIGNALS, SIGNAL_EXPIRY_DAYS, KNOWN_SIGNALS, SEVERITY_MULTIPLIER, PerformanceReader;
11260
11308
  var init_performance_reader = __esm({
11261
11309
  "packages/orchestrator/src/performance-reader.ts"() {
11262
11310
  "use strict";
11263
- import_fs14 = require("fs");
11264
- import_path16 = require("path");
11311
+ import_fs15 = require("fs");
11312
+ import_path17 = require("path");
11265
11313
  CIRCUIT_BREAKER_THRESHOLD = 3;
11266
11314
  NEGATIVE_SIGNALS = /* @__PURE__ */ new Set(["hallucination_caught", "disagreement", "unique_unconfirmed"]);
11267
11315
  SIGNAL_EXPIRY_DAYS = 30;
@@ -11290,13 +11338,13 @@ var init_performance_reader = __esm({
11290
11338
  cachedScores = null;
11291
11339
  cachedMtimeMs = 0;
11292
11340
  constructor(projectRoot) {
11293
- this.filePath = (0, import_path16.join)(projectRoot, ".gossip", "agent-performance.jsonl");
11341
+ this.filePath = (0, import_path17.join)(projectRoot, ".gossip", "agent-performance.jsonl");
11294
11342
  }
11295
11343
  /** Read all signals and compute per-agent scores (cached by file mtime) */
11296
11344
  getScores() {
11297
11345
  let mtimeMs = 0;
11298
11346
  try {
11299
- mtimeMs = (0, import_fs14.statSync)(this.filePath).mtimeMs;
11347
+ mtimeMs = (0, import_fs15.statSync)(this.filePath).mtimeMs;
11300
11348
  } catch {
11301
11349
  }
11302
11350
  if (this.cachedScores && mtimeMs === this.cachedMtimeMs) {
@@ -11372,9 +11420,9 @@ var init_performance_reader = __esm({
11372
11420
  * Don't unify these — see getCountersSince doc and consensus 9369ebfc-a3654b51 f1.
11373
11421
  */
11374
11422
  readSignalsRaw() {
11375
- if (!(0, import_fs14.existsSync)(this.filePath)) return [];
11423
+ if (!(0, import_fs15.existsSync)(this.filePath)) return [];
11376
11424
  try {
11377
- const lines = (0, import_fs14.readFileSync)(this.filePath, "utf-8").trim().split("\n").filter(Boolean);
11425
+ const lines = (0, import_fs15.readFileSync)(this.filePath, "utf-8").trim().split("\n").filter(Boolean);
11378
11426
  const all = lines.map((line) => {
11379
11427
  try {
11380
11428
  return JSON.parse(line);
@@ -11407,10 +11455,10 @@ var init_performance_reader = __esm({
11407
11455
  }
11408
11456
  }
11409
11457
  readSignals() {
11410
- if (!(0, import_fs14.existsSync)(this.filePath)) return [];
11458
+ if (!(0, import_fs15.existsSync)(this.filePath)) return [];
11411
11459
  try {
11412
11460
  const expiryMs = Date.now() - SIGNAL_EXPIRY_DAYS * 864e5;
11413
- const lines = (0, import_fs14.readFileSync)(this.filePath, "utf-8").trim().split("\n").filter(Boolean);
11461
+ const lines = (0, import_fs15.readFileSync)(this.filePath, "utf-8").trim().split("\n").filter(Boolean);
11414
11462
  const all = lines.map((line) => {
11415
11463
  try {
11416
11464
  return JSON.parse(line);
@@ -11675,11 +11723,11 @@ var init_performance_reader = __esm({
11675
11723
  return result;
11676
11724
  }
11677
11725
  getImplScore(agentId) {
11678
- if (!(0, import_fs14.existsSync)(this.filePath)) return null;
11726
+ if (!(0, import_fs15.existsSync)(this.filePath)) return null;
11679
11727
  try {
11680
11728
  const now = Date.now();
11681
11729
  const expiryMs = now - SIGNAL_EXPIRY_DAYS * 864e5;
11682
- const lines = (0, import_fs14.readFileSync)(this.filePath, "utf-8").trim().split("\n").filter(Boolean);
11730
+ const lines = (0, import_fs15.readFileSync)(this.filePath, "utf-8").trim().split("\n").filter(Boolean);
11683
11731
  let pass = 0, fail = 0, approved = 0, rejected = 0, lastImplSignalMs = 0;
11684
11732
  for (const line of lines) {
11685
11733
  try {
@@ -11718,12 +11766,12 @@ var init_performance_reader = __esm({
11718
11766
  });
11719
11767
 
11720
11768
  // packages/orchestrator/src/skill-counters.ts
11721
- var import_fs15, import_path17, STALE_THRESHOLD, PROMOTION_RATE, PROMOTION_MIN_WINDOW, SkillCounterTracker;
11769
+ var import_fs16, import_path18, STALE_THRESHOLD, PROMOTION_RATE, PROMOTION_MIN_WINDOW, SkillCounterTracker;
11722
11770
  var init_skill_counters = __esm({
11723
11771
  "packages/orchestrator/src/skill-counters.ts"() {
11724
11772
  "use strict";
11725
- import_fs15 = require("fs");
11726
- import_path17 = require("path");
11773
+ import_fs16 = require("fs");
11774
+ import_path18 = require("path");
11727
11775
  STALE_THRESHOLD = 30;
11728
11776
  PROMOTION_RATE = 0.8;
11729
11777
  PROMOTION_MIN_WINDOW = 20;
@@ -11732,7 +11780,7 @@ var init_skill_counters = __esm({
11732
11780
  filePath;
11733
11781
  dirty = false;
11734
11782
  constructor(projectRoot) {
11735
- this.filePath = (0, import_path17.join)(projectRoot, ".gossip", "skill-counters.json");
11783
+ this.filePath = (0, import_path18.join)(projectRoot, ".gossip", "skill-counters.json");
11736
11784
  this.load();
11737
11785
  }
11738
11786
  /**
@@ -11807,15 +11855,15 @@ var init_skill_counters = __esm({
11807
11855
  /** Flush counters to disk. Call during gossip_collect. */
11808
11856
  flush() {
11809
11857
  if (!this.dirty) return;
11810
- const dir = (0, import_path17.dirname)(this.filePath);
11811
- if (!(0, import_fs15.existsSync)(dir)) (0, import_fs15.mkdirSync)(dir, { recursive: true });
11812
- (0, import_fs15.writeFileSync)(this.filePath, JSON.stringify(this.data, null, 2) + "\n");
11858
+ const dir = (0, import_path18.dirname)(this.filePath);
11859
+ if (!(0, import_fs16.existsSync)(dir)) (0, import_fs16.mkdirSync)(dir, { recursive: true });
11860
+ (0, import_fs16.writeFileSync)(this.filePath, JSON.stringify(this.data, null, 2) + "\n");
11813
11861
  this.dirty = false;
11814
11862
  }
11815
11863
  load() {
11816
11864
  try {
11817
- if ((0, import_fs15.existsSync)(this.filePath)) {
11818
- const raw = JSON.parse((0, import_fs15.readFileSync)(this.filePath, "utf-8"));
11865
+ if ((0, import_fs16.existsSync)(this.filePath)) {
11866
+ const raw = JSON.parse((0, import_fs16.readFileSync)(this.filePath, "utf-8"));
11819
11867
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
11820
11868
  for (const [agentId, skills] of Object.entries(raw)) {
11821
11869
  if (!skills || typeof skills !== "object") {
@@ -11842,14 +11890,14 @@ function shortConsensusId() {
11842
11890
  const hex3 = (0, import_crypto6.randomUUID)().replace(/-/g, "");
11843
11891
  return hex3.slice(0, 8) + "-" + hex3.slice(8, 16);
11844
11892
  }
11845
- var import_promises3, import_fs16, import_crypto6, import_path18, SUMMARY_HEADER, FALLBACK_MAX_LENGTH, MAX_SUMMARY_LENGTH, MAX_CROSS_REVIEW_ENTRIES, VALID_ACTIONS, ANCHOR_PATTERN, ConsensusEngine;
11893
+ var import_promises3, import_fs17, import_crypto6, import_path19, SUMMARY_HEADER, FALLBACK_MAX_LENGTH, MAX_SUMMARY_LENGTH, MAX_CROSS_REVIEW_ENTRIES, VALID_ACTIONS, ANCHOR_PATTERN, ConsensusEngine;
11846
11894
  var init_consensus_engine = __esm({
11847
11895
  "packages/orchestrator/src/consensus-engine.ts"() {
11848
11896
  "use strict";
11849
11897
  import_promises3 = require("fs/promises");
11850
- import_fs16 = require("fs");
11898
+ import_fs17 = require("fs");
11851
11899
  import_crypto6 = require("crypto");
11852
- import_path18 = require("path");
11900
+ import_path19 = require("path");
11853
11901
  SUMMARY_HEADER = "## Consensus Summary";
11854
11902
  FALLBACK_MAX_LENGTH = 2e3;
11855
11903
  MAX_SUMMARY_LENGTH = 5e3;
@@ -11885,7 +11933,7 @@ var init_consensus_engine = __esm({
11885
11933
  for (const r of results) {
11886
11934
  const wt = r.worktreeInfo?.path;
11887
11935
  if (wt && typeof wt === "string") {
11888
- next.add((0, import_path18.resolve)(wt));
11936
+ next.add((0, import_path19.resolve)(wt));
11889
11937
  }
11890
11938
  }
11891
11939
  let changed = next.size !== this.currentWorktreeRoots.size;
@@ -12713,9 +12761,9 @@ ${safeSnippet}
12713
12761
  */
12714
12762
  /** Guard: resolved path must stay inside one of the valid roots */
12715
12763
  isInsideAnyRoot(candidate, roots) {
12716
- const normalized = (0, import_path18.resolve)(candidate);
12764
+ const normalized = (0, import_path19.resolve)(candidate);
12717
12765
  return roots.some((root) => {
12718
- const normalizedRoot = (0, import_path18.resolve)(root);
12766
+ const normalizedRoot = (0, import_path19.resolve)(root);
12719
12767
  return normalized === normalizedRoot || normalized.startsWith(normalizedRoot + "/");
12720
12768
  });
12721
12769
  }
@@ -12725,7 +12773,7 @@ ${safeSnippet}
12725
12773
  const fileName = fileRef.split("/").pop();
12726
12774
  for (const root of roots) {
12727
12775
  try {
12728
- const candidate = (0, import_path18.join)(root, fileRef);
12776
+ const candidate = (0, import_path19.join)(root, fileRef);
12729
12777
  if (this.isInsideAnyRoot(candidate, roots)) {
12730
12778
  await (0, import_promises3.stat)(candidate);
12731
12779
  return candidate;
@@ -12734,7 +12782,7 @@ ${safeSnippet}
12734
12782
  }
12735
12783
  if (fileName !== fileRef) {
12736
12784
  try {
12737
- const candidate = (0, import_path18.join)(root, fileName);
12785
+ const candidate = (0, import_path19.join)(root, fileName);
12738
12786
  if (this.isInsideAnyRoot(candidate, roots)) {
12739
12787
  await (0, import_promises3.stat)(candidate);
12740
12788
  return candidate;
@@ -12744,7 +12792,7 @@ ${safeSnippet}
12744
12792
  }
12745
12793
  const searchDirs = ["packages", "src", "apps", "tests", "test", "tools", "scripts", "lib"];
12746
12794
  for (const dir of searchDirs) {
12747
- const found = await this.findFile((0, import_path18.join)(root, dir), fileName, roots);
12795
+ const found = await this.findFile((0, import_path19.join)(root, dir), fileName, roots);
12748
12796
  if (found) return found;
12749
12797
  }
12750
12798
  }
@@ -12754,7 +12802,7 @@ ${safeSnippet}
12754
12802
  try {
12755
12803
  const entries = await (0, import_promises3.readdir)(dir, { withFileTypes: true });
12756
12804
  for (const entry of entries) {
12757
- const fullPath = (0, import_path18.join)(dir, entry.name);
12805
+ const fullPath = (0, import_path19.join)(dir, entry.name);
12758
12806
  if (entry.isFile() && entry.name === fileName) {
12759
12807
  if (!this.isInsideAnyRoot(fullPath, validRoots)) return null;
12760
12808
  return fullPath;
@@ -12780,7 +12828,7 @@ ${safeSnippet}
12780
12828
  const sourceExts = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx"]);
12781
12829
  for (const root of roots) {
12782
12830
  for (const dir of searchDirs) {
12783
- const result = await this.grepDir((0, import_path18.join)(root, dir), identifier, sourceExts, CONTEXT_LINES);
12831
+ const result = await this.grepDir((0, import_path19.join)(root, dir), identifier, sourceExts, CONTEXT_LINES);
12784
12832
  if (result) return result;
12785
12833
  }
12786
12834
  }
@@ -12791,7 +12839,7 @@ ${safeSnippet}
12791
12839
  try {
12792
12840
  const entries = await (0, import_promises3.readdir)(dir, { withFileTypes: true });
12793
12841
  for (const entry of entries) {
12794
- const fullPath = (0, import_path18.join)(dir, entry.name);
12842
+ const fullPath = (0, import_path19.join)(dir, entry.name);
12795
12843
  if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== ".git" && entry.name !== "dist") {
12796
12844
  const found = await this.grepDir(fullPath, identifier, exts, contextLines);
12797
12845
  if (found) return found;
@@ -13285,11 +13333,11 @@ ${safeSnippet}
13285
13333
  dumpFailedCrossReview(reviewerAgentId, text) {
13286
13334
  if (!this.config.projectRoot) return;
13287
13335
  try {
13288
- const dir = (0, import_path18.join)(this.config.projectRoot, ".gossip", "cross-review-failures");
13289
- (0, import_fs16.mkdirSync)(dir, { recursive: true });
13336
+ const dir = (0, import_path19.join)(this.config.projectRoot, ".gossip", "cross-review-failures");
13337
+ (0, import_fs17.mkdirSync)(dir, { recursive: true });
13290
13338
  const safeId2 = reviewerAgentId.replace(/[^a-zA-Z0-9_-]/g, "_");
13291
13339
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
13292
- (0, import_fs16.writeFileSync)((0, import_path18.join)(dir, `${safeId2}-${ts}.txt`), text);
13340
+ (0, import_fs17.writeFileSync)((0, import_path19.join)(dir, `${safeId2}-${ts}.txt`), text);
13293
13341
  } catch {
13294
13342
  }
13295
13343
  }
@@ -13362,12 +13410,12 @@ function validateSignal(signal) {
13362
13410
  throw new Error(`Signal validation failed: unknown type "${signal.type}"`);
13363
13411
  }
13364
13412
  }
13365
- var import_fs17, import_path19, VALID_CONSENSUS_SIGNALS, VALID_IMPL_SIGNALS, VALID_META_SIGNALS, PerformanceWriter;
13413
+ var import_fs18, import_path20, VALID_CONSENSUS_SIGNALS, VALID_IMPL_SIGNALS, VALID_META_SIGNALS, PerformanceWriter;
13366
13414
  var init_performance_writer = __esm({
13367
13415
  "packages/orchestrator/src/performance-writer.ts"() {
13368
13416
  "use strict";
13369
- import_fs17 = require("fs");
13370
- import_path19 = require("path");
13417
+ import_fs18 = require("fs");
13418
+ import_path20 = require("path");
13371
13419
  VALID_CONSENSUS_SIGNALS = /* @__PURE__ */ new Set([
13372
13420
  "agreement",
13373
13421
  "disagreement",
@@ -13393,19 +13441,19 @@ var init_performance_writer = __esm({
13393
13441
  PerformanceWriter = class {
13394
13442
  filePath;
13395
13443
  constructor(projectRoot) {
13396
- const dir = (0, import_path19.join)(projectRoot, ".gossip");
13397
- if (!(0, import_fs17.existsSync)(dir)) (0, import_fs17.mkdirSync)(dir, { recursive: true });
13398
- this.filePath = (0, import_path19.join)(dir, "agent-performance.jsonl");
13444
+ const dir = (0, import_path20.join)(projectRoot, ".gossip");
13445
+ if (!(0, import_fs18.existsSync)(dir)) (0, import_fs18.mkdirSync)(dir, { recursive: true });
13446
+ this.filePath = (0, import_path20.join)(dir, "agent-performance.jsonl");
13399
13447
  }
13400
13448
  appendSignal(signal) {
13401
13449
  validateSignal(signal);
13402
- (0, import_fs17.appendFileSync)(this.filePath, JSON.stringify(signal) + "\n");
13450
+ (0, import_fs18.appendFileSync)(this.filePath, JSON.stringify(signal) + "\n");
13403
13451
  }
13404
13452
  appendSignals(signals) {
13405
13453
  if (signals.length === 0) return;
13406
13454
  for (const s of signals) validateSignal(s);
13407
13455
  const data = signals.map((s) => JSON.stringify(s)).join("\n") + "\n";
13408
- (0, import_fs17.appendFileSync)(this.filePath, data);
13456
+ (0, import_fs18.appendFileSync)(this.filePath, data);
13409
13457
  }
13410
13458
  };
13411
13459
  }
@@ -13604,12 +13652,12 @@ ${topFindings}`;
13604
13652
  });
13605
13653
 
13606
13654
  // packages/orchestrator/src/session-context.ts
13607
- var import_fs18, import_path20, log3, SessionContext;
13655
+ var import_fs19, import_path21, log3, SessionContext;
13608
13656
  var init_session_context = __esm({
13609
13657
  "packages/orchestrator/src/session-context.ts"() {
13610
13658
  "use strict";
13611
- import_fs18 = require("fs");
13612
- import_path20 = require("path");
13659
+ import_fs19 = require("fs");
13660
+ import_path21 = require("path");
13613
13661
  log3 = (msg) => process.stderr.write(`[gossipcat] ${msg}
13614
13662
  `);
13615
13663
  SessionContext = class _SessionContext {
@@ -13623,7 +13671,7 @@ var init_session_context = __esm({
13623
13671
  this.projectRoot = config2.projectRoot;
13624
13672
  this.llm = config2.llm;
13625
13673
  try {
13626
- const gossipPath = (0, import_path20.join)(config2.projectRoot, ".gossip", "agents", "_project", "memory", "session-gossip.jsonl");
13674
+ const gossipPath = (0, import_path21.join)(config2.projectRoot, ".gossip", "agents", "_project", "memory", "session-gossip.jsonl");
13627
13675
  const { existsSync: ex, readFileSync: rf } = require("fs");
13628
13676
  if (ex(gossipPath)) {
13629
13677
  const lines = rf(gossipPath, "utf-8").trim().split("\n").filter(Boolean);
@@ -13675,9 +13723,9 @@ var init_session_context = __esm({
13675
13723
  this.sessionGossip.shift();
13676
13724
  }
13677
13725
  try {
13678
- const gossipPath = (0, import_path20.join)(this.projectRoot, ".gossip", "agents", "_project", "memory", "session-gossip.jsonl");
13679
- (0, import_fs18.mkdirSync)((0, import_path20.dirname)(gossipPath), { recursive: true });
13680
- (0, import_fs18.appendFileSync)(gossipPath, JSON.stringify({ agentId, taskSummary: summary, timestamp: Date.now() }) + "\n");
13726
+ const gossipPath = (0, import_path21.join)(this.projectRoot, ".gossip", "agents", "_project", "memory", "session-gossip.jsonl");
13727
+ (0, import_fs19.mkdirSync)((0, import_path21.dirname)(gossipPath), { recursive: true });
13728
+ (0, import_fs19.appendFileSync)(gossipPath, JSON.stringify({ agentId, taskSummary: summary, timestamp: Date.now() }) + "\n");
13681
13729
  this.rotateJsonlFile(gossipPath, 100, 50);
13682
13730
  } catch {
13683
13731
  }
@@ -13698,10 +13746,10 @@ ${result.slice(0, 2e3)}` }
13698
13746
  /** Rotate a JSONL file: if over maxEntries lines, keep only the last keepEntries. */
13699
13747
  rotateJsonlFile(filePath, maxEntries, keepEntries) {
13700
13748
  try {
13701
- const content = (0, import_fs18.readFileSync)(filePath, "utf-8");
13749
+ const content = (0, import_fs19.readFileSync)(filePath, "utf-8");
13702
13750
  const lines = content.trim().split("\n").filter((l) => l.length > 0);
13703
13751
  if (lines.length > maxEntries) {
13704
- (0, import_fs18.writeFileSync)(filePath, lines.slice(-keepEntries).join("\n") + "\n");
13752
+ (0, import_fs19.writeFileSync)(filePath, lines.slice(-keepEntries).join("\n") + "\n");
13705
13753
  }
13706
13754
  } catch {
13707
13755
  }
@@ -13720,13 +13768,13 @@ function shouldSkipConsensus(task, agents, costMode, agreementHistory) {
13720
13768
  const firstWord = task.trim().split(/\s+/)[0] || "";
13721
13769
  return OBSERVATION_VERBS.test(firstWord);
13722
13770
  }
13723
- var import_crypto8, import_fs19, import_path21, log4, DispatchPipeline, SECURITY_KEYWORDS, OBSERVATION_VERBS;
13771
+ var import_crypto8, import_fs20, import_path22, log4, DispatchPipeline, SECURITY_KEYWORDS, OBSERVATION_VERBS;
13724
13772
  var init_dispatch_pipeline = __esm({
13725
13773
  "packages/orchestrator/src/dispatch-pipeline.ts"() {
13726
13774
  "use strict";
13727
13775
  import_crypto8 = require("crypto");
13728
- import_fs19 = require("fs");
13729
- import_path21 = require("path");
13776
+ import_fs20 = require("fs");
13777
+ import_path22 = require("path");
13730
13778
  init_types2();
13731
13779
  init_skill_loader();
13732
13780
  init_prompt_assembler();
@@ -13815,8 +13863,8 @@ var init_dispatch_pipeline = __esm({
13815
13863
  this.sessionContext = new SessionContext({ llm: config2.llm ?? null, projectRoot: config2.projectRoot });
13816
13864
  this.worktreeManager.pruneOrphans().catch((err) => log4(`Orphan cleanup failed: ${err.message}`));
13817
13865
  try {
13818
- const projectMemDir = (0, import_path21.join)(config2.projectRoot, ".gossip", "agents", "_project", "memory");
13819
- (0, import_fs19.mkdirSync)(projectMemDir, { recursive: true });
13866
+ const projectMemDir = (0, import_path22.join)(config2.projectRoot, ".gossip", "agents", "_project", "memory");
13867
+ (0, import_fs20.mkdirSync)(projectMemDir, { recursive: true });
13820
13868
  } catch {
13821
13869
  }
13822
13870
  }
@@ -13887,11 +13935,11 @@ var init_dispatch_pipeline = __esm({
13887
13935
  const specRefs = extractSpecReferences(task);
13888
13936
  if (specRefs.length > 0) {
13889
13937
  try {
13890
- const specPath = (0, import_path21.resolve)(this.projectRoot, specRefs[0]);
13891
- const realSpecPath = (0, import_fs19.realpathSync)(specPath);
13892
- const realRoot = (0, import_fs19.realpathSync)(this.projectRoot);
13938
+ const specPath = (0, import_path22.resolve)(this.projectRoot, specRefs[0]);
13939
+ const realSpecPath = (0, import_fs20.realpathSync)(specPath);
13940
+ const realRoot = (0, import_fs20.realpathSync)(this.projectRoot);
13893
13941
  if (realSpecPath.startsWith(realRoot + "/")) {
13894
- const specContent = (0, import_fs19.readFileSync)(realSpecPath, "utf-8");
13942
+ const specContent = (0, import_fs20.readFileSync)(realSpecPath, "utf-8");
13895
13943
  const implFiles = extractSpecReferences(task, specContent);
13896
13944
  const enrichment = buildSpecReviewEnrichment(implFiles);
13897
13945
  if (enrichment) specReviewContext = enrichment;
@@ -13899,7 +13947,7 @@ var init_dispatch_pipeline = __esm({
13899
13947
  } catch {
13900
13948
  }
13901
13949
  }
13902
- const memoryDir = (0, import_path21.join)(this.projectRoot, ".gossip", "agents", agentId, "memory", "knowledge");
13950
+ const memoryDir = (0, import_path22.join)(this.projectRoot, ".gossip", "agents", agentId, "memory", "knowledge");
13903
13951
  const promptContent = assemblePrompt({
13904
13952
  memory: memory || void 0,
13905
13953
  memoryDir,
@@ -13959,7 +14007,7 @@ var init_dispatch_pipeline = __esm({
13959
14007
  const elapsedMs = (entry.completedAt ?? Date.now()) - entry.startedAt;
13960
14008
  process.stderr.write(`[gossipcat] \u2705 relay \u2190 ${entry.agentId} [${entry.id}] OK (${(elapsedMs / 1e3).toFixed(1)}s, ${(event.payload.result || "").length} chars)
13961
14009
  `);
13962
- (0, import_fs19.appendFileSync)((0, import_path21.join)(this.projectRoot, ".gossip", "task-graph.jsonl"), JSON.stringify({
14010
+ (0, import_fs20.appendFileSync)((0, import_path22.join)(this.projectRoot, ".gossip", "task-graph.jsonl"), JSON.stringify({
13963
14011
  type: "task.completed",
13964
14012
  taskId: entry.id,
13965
14013
  agentId: entry.agentId,
@@ -13983,7 +14031,7 @@ var init_dispatch_pipeline = __esm({
13983
14031
  const elapsedMs = (entry.completedAt ?? Date.now()) - entry.startedAt;
13984
14032
  process.stderr.write(`[gossipcat] \u274C relay \u2190 ${entry.agentId} [${entry.id}] FAILED (${(elapsedMs / 1e3).toFixed(1)}s) \u2014 ${event.payload.error}
13985
14033
  `);
13986
- (0, import_fs19.appendFileSync)((0, import_path21.join)(this.projectRoot, ".gossip", "task-graph.jsonl"), JSON.stringify({
14034
+ (0, import_fs20.appendFileSync)((0, import_path22.join)(this.projectRoot, ".gossip", "task-graph.jsonl"), JSON.stringify({
13987
14035
  type: "task.failed",
13988
14036
  taskId: entry.id,
13989
14037
  agentId: entry.agentId,
@@ -14910,13 +14958,13 @@ function parseYamlLikeToolCall(content) {
14910
14958
  const args = typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
14911
14959
  return { tool, args };
14912
14960
  }
14913
- var import_fs20, import_path22, log5, AGENT_ID_RE, TAG_PATTERN, BLOCK_RE, BLOCK_IN_FENCE_RE, ToolRouter, ToolExecutor;
14961
+ var import_fs21, import_path23, log5, AGENT_ID_RE, TAG_PATTERN, BLOCK_RE, BLOCK_IN_FENCE_RE, ToolRouter, ToolExecutor;
14914
14962
  var init_tool_router = __esm({
14915
14963
  "packages/orchestrator/src/tool-router.ts"() {
14916
14964
  "use strict";
14917
14965
  init_tool_definitions();
14918
- import_fs20 = require("fs");
14919
- import_path22 = require("path");
14966
+ import_fs21 = require("fs");
14967
+ import_path23 = require("path");
14920
14968
  log5 = (msg) => process.stderr.write(`[tool-router] ${msg}
14921
14969
  `);
14922
14970
  AGENT_ID_RE = /^[a-zA-Z0-9_-]+$/;
@@ -15322,12 +15370,12 @@ ${agentOutputs}` }
15322
15370
  const fsp = await import("fs/promises");
15323
15371
  const updatedIds = [];
15324
15372
  for (const id of pending.agentIds) {
15325
- const agentDir = (0, import_path22.join)(this.projectRoot, ".gossip", "agents", id);
15326
- const filePath = (0, import_path22.join)(agentDir, "instructions.md");
15327
- if (!(0, import_fs20.existsSync)(agentDir)) {
15373
+ const agentDir = (0, import_path23.join)(this.projectRoot, ".gossip", "agents", id);
15374
+ const filePath = (0, import_path23.join)(agentDir, "instructions.md");
15375
+ if (!(0, import_fs21.existsSync)(agentDir)) {
15328
15376
  await fsp.mkdir(agentDir, { recursive: true });
15329
15377
  }
15330
- if ((0, import_fs20.existsSync)(filePath)) {
15378
+ if ((0, import_fs21.existsSync)(filePath)) {
15331
15379
  await fsp.appendFile(filePath, `
15332
15380
 
15333
15381
  ${pending.instruction}`, "utf-8");
@@ -15441,9 +15489,9 @@ ${collectResult.consensus.summary}`;
15441
15489
  async handlePlan(args) {
15442
15490
  let task = String(args.task);
15443
15491
  try {
15444
- const specPath = (0, import_path22.join)(this.projectRoot, ".gossip", "spec.md");
15445
- if ((0, import_fs20.existsSync)(specPath)) {
15446
- const spec = (0, import_fs20.readFileSync)(specPath, "utf-8");
15492
+ const specPath = (0, import_path23.join)(this.projectRoot, ".gossip", "spec.md");
15493
+ if ((0, import_fs21.existsSync)(specPath)) {
15494
+ const spec = (0, import_fs21.readFileSync)(specPath, "utf-8");
15447
15495
  task = `${task}
15448
15496
 
15449
15497
  [Project Spec]
@@ -15501,11 +15549,11 @@ ${taskLines.join("\n")}`,
15501
15549
  if (!this.llm) {
15502
15550
  return { text: "Tool error: LLM not available for spec generation" };
15503
15551
  }
15504
- const specPath = (0, import_path22.join)(this.projectRoot, ".gossip", "spec.md");
15552
+ const specPath = (0, import_path23.join)(this.projectRoot, ".gossip", "spec.md");
15505
15553
  let existingSpec = "";
15506
15554
  try {
15507
- if ((0, import_fs20.existsSync)(specPath)) {
15508
- existingSpec = (0, import_fs20.readFileSync)(specPath, "utf-8");
15555
+ if ((0, import_fs21.existsSync)(specPath)) {
15556
+ existingSpec = (0, import_fs21.readFileSync)(specPath, "utf-8");
15509
15557
  }
15510
15558
  } catch {
15511
15559
  }
@@ -15541,7 +15589,7 @@ Keep it SHORT \u2014 under 30 lines. This is a working document, not a design do
15541
15589
  const specContent = response.text || "";
15542
15590
  try {
15543
15591
  const { mkdirSync: mkdirSync21, writeFileSync: writeFS } = require("fs");
15544
- mkdirSync21((0, import_path22.join)(this.projectRoot, ".gossip"), { recursive: true });
15592
+ mkdirSync21((0, import_path23.join)(this.projectRoot, ".gossip"), { recursive: true });
15545
15593
  writeFS(specPath, specContent, "utf-8");
15546
15594
  } catch (err) {
15547
15595
  return { text: `Spec generated but failed to save: ${err.message}
@@ -15579,11 +15627,11 @@ ${lines.join("\n")}` };
15579
15627
  if (!this.registry.get(agentId)) {
15580
15628
  return { text: `Tool error: agent "${agentId}" not found in registry` };
15581
15629
  }
15582
- const tasksPath = (0, import_path22.join)(this.projectRoot, ".gossip", "agents", agentId, "memory", "tasks.jsonl");
15583
- if (!(0, import_fs20.existsSync)(tasksPath)) {
15630
+ const tasksPath = (0, import_path23.join)(this.projectRoot, ".gossip", "agents", agentId, "memory", "tasks.jsonl");
15631
+ if (!(0, import_fs21.existsSync)(tasksPath)) {
15584
15632
  return { text: `Agent "${agentId}" \u2014 no task history found.` };
15585
15633
  }
15586
- const rawLines = (0, import_fs20.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
15634
+ const rawLines = (0, import_fs21.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
15587
15635
  const last5 = rawLines.slice(-5).map((line) => {
15588
15636
  try {
15589
15637
  return JSON.parse(line);
@@ -15600,11 +15648,11 @@ Last ${last5.length} tasks:
15600
15648
  ${formatted.join("\n")}` };
15601
15649
  }
15602
15650
  handleAgentPerformance() {
15603
- const perfPath = (0, import_path22.join)(this.projectRoot, ".gossip", "agent-performance.jsonl");
15604
- if (!(0, import_fs20.existsSync)(perfPath)) {
15651
+ const perfPath = (0, import_path23.join)(this.projectRoot, ".gossip", "agent-performance.jsonl");
15652
+ if (!(0, import_fs21.existsSync)(perfPath)) {
15605
15653
  return { text: "No performance data found." };
15606
15654
  }
15607
- const rawLines = (0, import_fs20.readFileSync)(perfPath, "utf-8").trim().split("\n").filter(Boolean);
15655
+ const rawLines = (0, import_fs21.readFileSync)(perfPath, "utf-8").trim().split("\n").filter(Boolean);
15608
15656
  const last20 = rawLines.slice(-20).map((line) => {
15609
15657
  try {
15610
15658
  return JSON.parse(line);
@@ -15655,11 +15703,11 @@ Instruction: "${instruction}"`,
15655
15703
  if (!this.registry.get(agentId)) {
15656
15704
  return { text: `Tool error: agent "${agentId}" not found in registry` };
15657
15705
  }
15658
- const tasksPath = (0, import_path22.join)(this.projectRoot, ".gossip", "agents", agentId, "memory", "tasks.jsonl");
15659
- if (!(0, import_fs20.existsSync)(tasksPath)) {
15706
+ const tasksPath = (0, import_path23.join)(this.projectRoot, ".gossip", "agents", agentId, "memory", "tasks.jsonl");
15707
+ if (!(0, import_fs21.existsSync)(tasksPath)) {
15660
15708
  return { text: `No task history for agent "${agentId}".` };
15661
15709
  }
15662
- const rawLines = (0, import_fs20.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
15710
+ const rawLines = (0, import_fs21.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
15663
15711
  const entries = rawLines.slice(-limit).map((line) => {
15664
15712
  try {
15665
15713
  return JSON.parse(line);
@@ -15719,17 +15767,34 @@ ${formatted.join("\n")}` };
15719
15767
  });
15720
15768
 
15721
15769
  // packages/orchestrator/src/archetype-catalog.ts
15722
- var import_fs21, import_path23, DEFAULT_PATH, ArchetypeCatalog;
15770
+ function findArchetypeCatalog() {
15771
+ const candidates = [
15772
+ (0, import_path24.resolve)(__dirname, "data", "archetypes.json"),
15773
+ // bundled prod: dist-mcp/data/archetypes.json
15774
+ (0, import_path24.resolve)(__dirname, "..", "..", "..", "data", "archetypes.json"),
15775
+ // dev ts-node: packages/orchestrator/src → repo/data
15776
+ (0, import_path24.resolve)(process.cwd(), "data", "archetypes.json")
15777
+ // last-resort dev fallback
15778
+ ];
15779
+ for (const p of candidates) {
15780
+ if ((0, import_fs22.existsSync)(p)) return p;
15781
+ }
15782
+ return null;
15783
+ }
15784
+ var import_fs22, import_path24, ArchetypeCatalog;
15723
15785
  var init_archetype_catalog = __esm({
15724
15786
  "packages/orchestrator/src/archetype-catalog.ts"() {
15725
15787
  "use strict";
15726
- import_fs21 = require("fs");
15727
- import_path23 = require("path");
15728
- DEFAULT_PATH = (0, import_path23.resolve)(__dirname, "..", "..", "..", "data", "archetypes.json");
15788
+ import_fs22 = require("fs");
15789
+ import_path24 = require("path");
15729
15790
  ArchetypeCatalog = class {
15730
15791
  archetypes;
15731
15792
  constructor(catalogPath) {
15732
- const raw = (0, import_fs21.readFileSync)(catalogPath ?? DEFAULT_PATH, "utf-8");
15793
+ const path2 = catalogPath ?? findArchetypeCatalog();
15794
+ if (!path2) {
15795
+ throw new Error("archetypes.json not found \u2014 tried bundled dist-mcp/data/, dev ts-node path, and cwd/data/. Reinstall gossipcat.");
15796
+ }
15797
+ const raw = (0, import_fs22.readFileSync)(path2, "utf-8");
15733
15798
  this.archetypes = JSON.parse(raw);
15734
15799
  }
15735
15800
  /** Return all archetype IDs */
@@ -15779,13 +15844,13 @@ var init_archetype_catalog = __esm({
15779
15844
  });
15780
15845
 
15781
15846
  // packages/orchestrator/src/project-initializer.ts
15782
- var import_fs22, import_path24, SIGNAL_DIRS, SIGNAL_FILES, LANG_FILES, ProjectInitializer;
15847
+ var import_fs23, import_path25, SIGNAL_DIRS, SIGNAL_FILES, LANG_FILES, ProjectInitializer;
15783
15848
  var init_project_initializer = __esm({
15784
15849
  "packages/orchestrator/src/project-initializer.ts"() {
15785
15850
  "use strict";
15786
15851
  init_archetype_catalog();
15787
- import_fs22 = require("fs");
15788
- import_path24 = require("path");
15852
+ import_fs23 = require("fs");
15853
+ import_path25 = require("path");
15789
15854
  SIGNAL_DIRS = [
15790
15855
  "src",
15791
15856
  "pages",
@@ -15817,16 +15882,16 @@ var init_project_initializer = __esm({
15817
15882
  this.config = config2;
15818
15883
  }
15819
15884
  scanDirectory(root) {
15820
- const absRoot = (0, import_path24.resolve)(root);
15885
+ const absRoot = (0, import_path25.resolve)(root);
15821
15886
  const signals = { dependencies: [], directories: [], files: [] };
15822
15887
  for (const [file2, lang] of Object.entries(LANG_FILES)) {
15823
- if (this.safeExists(absRoot, (0, import_path24.join)(absRoot, file2))) signals.language = lang;
15888
+ if (this.safeExists(absRoot, (0, import_path25.join)(absRoot, file2))) signals.language = lang;
15824
15889
  }
15825
- const pkgPath = (0, import_path24.join)(absRoot, "package.json");
15890
+ const pkgPath = (0, import_path25.join)(absRoot, "package.json");
15826
15891
  if (this.safeExists(absRoot, pkgPath)) {
15827
15892
  signals.files.push("package.json");
15828
15893
  try {
15829
- const pkg = JSON.parse((0, import_fs22.readFileSync)(pkgPath, "utf-8"));
15894
+ const pkg = JSON.parse((0, import_fs23.readFileSync)(pkgPath, "utf-8"));
15830
15895
  signals.dependencies = [
15831
15896
  ...Object.keys(pkg.dependencies || {}),
15832
15897
  ...Object.keys(pkg.devDependencies || {})
@@ -15836,18 +15901,18 @@ var init_project_initializer = __esm({
15836
15901
  if (!signals.language) signals.language = "JavaScript";
15837
15902
  }
15838
15903
  for (const dir of SIGNAL_DIRS) {
15839
- const p = (0, import_path24.join)(absRoot, dir);
15904
+ const p = (0, import_path25.join)(absRoot, dir);
15840
15905
  if (this.safeExists(absRoot, p) && this.isDir(p)) signals.directories.push(`${dir}/`);
15841
15906
  }
15842
- const wfPath = (0, import_path24.join)(absRoot, ".github", "workflows");
15907
+ const wfPath = (0, import_path25.join)(absRoot, ".github", "workflows");
15843
15908
  if (this.safeExists(absRoot, wfPath) && this.isDir(wfPath)) {
15844
15909
  signals.directories.push(".github/workflows/");
15845
15910
  }
15846
15911
  for (const file2 of SIGNAL_FILES) {
15847
- if (this.safeExists(absRoot, (0, import_path24.join)(absRoot, file2))) signals.files.push(file2);
15912
+ if (this.safeExists(absRoot, (0, import_path25.join)(absRoot, file2))) signals.files.push(file2);
15848
15913
  }
15849
15914
  for (const file2 of Object.keys(LANG_FILES)) {
15850
- if (this.safeExists(absRoot, (0, import_path24.join)(absRoot, file2))) signals.files.push(file2);
15915
+ if (this.safeExists(absRoot, (0, import_path25.join)(absRoot, file2))) signals.files.push(file2);
15851
15916
  }
15852
15917
  return signals;
15853
15918
  }
@@ -15865,7 +15930,8 @@ var init_project_initializer = __esm({
15865
15930
  for (const p of ["google", "anthropic", "openai"]) {
15866
15931
  if (await this.config.keyProvider(p)) providers.push(p);
15867
15932
  }
15868
- if (!providers.length) {
15933
+ const hostIsClaudeCode = process.env.CLAUDECODE === "1" || !!process.env.CLAUDE_CODE_ENTRYPOINT;
15934
+ if (!providers.length && !hostIsClaudeCode) {
15869
15935
  return { text: "No API keys available. Run gossipcat setup to configure providers." };
15870
15936
  }
15871
15937
  const catalog = new ArchetypeCatalog(this.config.catalogPath);
@@ -15877,11 +15943,14 @@ var init_project_initializer = __esm({
15877
15943
  anthropic: { best: "claude-opus-4-6", fast: "claude-sonnet-4-6", cheapest: "claude-haiku-4-5" },
15878
15944
  openai: { best: "gpt-4o", fast: "gpt-4o", cheapest: "gpt-4o-mini" }
15879
15945
  };
15880
- const availableModels = providers.map((p) => {
15881
- const tiers = MODEL_TIERS[p];
15882
- if (!tiers) return `${p}: (use any available model)`;
15883
- return `${p}: ${tiers.best} (best), ${tiers.fast} (fast), ${tiers.cheapest} (cheapest)`;
15884
- }).join("\n");
15946
+ const availableModels = [
15947
+ ...hostIsClaudeCode ? ["none: none (native Claude Code orchestration \u2014 no API key needed, preferred for main_agent on this host)"] : [],
15948
+ ...providers.map((p) => {
15949
+ const tiers = MODEL_TIERS[p];
15950
+ if (!tiers) return `${p}: (use any available model)`;
15951
+ return `${p}: ${tiers.best} (best), ${tiers.fast} (fast), ${tiers.cheapest} (cheapest)`;
15952
+ })
15953
+ ].join("\n");
15885
15954
  const brainstormCtx = signals.brainstormContext;
15886
15955
  const systemPrompt = `You are configuring an agent team for a software project.
15887
15956
 
@@ -15928,7 +15997,7 @@ You may add additional skills from the table above based on project needs. Do NO
15928
15997
  - Pick the best archetype and customize roles for this specific project
15929
15998
  - Use ONLY the exact model names listed above
15930
15999
  - Choose models based on project complexity: simple \u2192 "fast" for all, complex \u2192 "best" for critical roles
15931
- - For the main_agent (orchestrator), use the "best" model from the primary provider
16000
+ - For the main_agent (orchestrator): ${hostIsClaudeCode ? 'PREFER { "provider": "none", "model": "none" } \u2014 native Claude Code orchestration needs no API key and is the zero-config default on this host. Only pick a keyed provider if the user explicitly asks for one.' : 'use the "best" model from the primary provider'}
15932
16001
  - Do NOT include agent IDs \u2014 the system generates them automatically
15933
16002
  - **Scale team size to project complexity.** Simple (single-page app, script, simple game) \u2192 1-2 agents. Medium \u2192 2-3. Complex multi-module \u2192 4-5. NEVER duplicate roles.
15934
16003
  - Max 5 agents, prefer fewer. Every agent costs money.
@@ -15979,13 +16048,13 @@ ${agentList}`,
15979
16048
  }
15980
16049
  async writeConfig(projectRoot) {
15981
16050
  if (!this.pendingProposal) throw new Error("No pending proposal to write");
15982
- const gossipDir2 = (0, import_path24.join)(projectRoot, ".gossip");
15983
- if (!(0, import_fs22.existsSync)(gossipDir2)) (0, import_fs22.mkdirSync)(gossipDir2, { recursive: true });
16051
+ const gossipDir2 = (0, import_path25.join)(projectRoot, ".gossip");
16052
+ if (!(0, import_fs23.existsSync)(gossipDir2)) (0, import_fs23.mkdirSync)(gossipDir2, { recursive: true });
15984
16053
  const agents = {};
15985
16054
  for (const a of this.pendingProposal.agents || []) {
15986
16055
  agents[a.id] = { provider: a.provider, model: a.model, preset: a.preset, skills: a.skills || [] };
15987
- const agentDir = (0, import_path24.join)(gossipDir2, "agents", a.id);
15988
- if (!(0, import_fs22.existsSync)(agentDir)) (0, import_fs22.mkdirSync)(agentDir, { recursive: true });
16056
+ const agentDir = (0, import_path25.join)(gossipDir2, "agents", a.id);
16057
+ if (!(0, import_fs23.existsSync)(agentDir)) (0, import_fs23.mkdirSync)(agentDir, { recursive: true });
15989
16058
  }
15990
16059
  const config2 = {
15991
16060
  main_agent: this.pendingProposal.main_agent,
@@ -15996,20 +16065,20 @@ ${agentList}`,
15996
16065
  },
15997
16066
  agents
15998
16067
  };
15999
- (0, import_fs22.writeFileSync)((0, import_path24.join)(gossipDir2, "config.json"), JSON.stringify(config2, null, 2));
16068
+ (0, import_fs23.writeFileSync)((0, import_path25.join)(gossipDir2, "config.json"), JSON.stringify(config2, null, 2));
16000
16069
  }
16001
16070
  safeExists(root, target) {
16002
- const resolved = (0, import_path24.resolve)(target);
16071
+ const resolved = (0, import_path25.resolve)(target);
16003
16072
  if (!resolved.startsWith(root)) return false;
16004
16073
  try {
16005
- return !(0, import_fs22.lstatSync)(resolved).isSymbolicLink();
16074
+ return !(0, import_fs23.lstatSync)(resolved).isSymbolicLink();
16006
16075
  } catch {
16007
16076
  return false;
16008
16077
  }
16009
16078
  }
16010
16079
  isDir(target) {
16011
16080
  try {
16012
- return (0, import_fs22.lstatSync)(target).isDirectory();
16081
+ return (0, import_fs23.lstatSync)(target).isDirectory();
16013
16082
  } catch {
16014
16083
  return false;
16015
16084
  }
@@ -16019,12 +16088,12 @@ ${agentList}`,
16019
16088
  });
16020
16089
 
16021
16090
  // packages/orchestrator/src/team-manager.ts
16022
- var import_fs23, import_path25, TeamManager;
16091
+ var import_fs24, import_path26, TeamManager;
16023
16092
  var init_team_manager = __esm({
16024
16093
  "packages/orchestrator/src/team-manager.ts"() {
16025
16094
  "use strict";
16026
- import_fs23 = require("fs");
16027
- import_path25 = require("path");
16095
+ import_fs24 = require("fs");
16096
+ import_path26 = require("path");
16028
16097
  TeamManager = class {
16029
16098
  registry;
16030
16099
  pipeline;
@@ -16080,8 +16149,8 @@ var init_team_manager = __esm({
16080
16149
  applyAdd(config2) {
16081
16150
  this.registry.register(config2);
16082
16151
  this.writeConfig();
16083
- const dir = (0, import_path25.join)(this.projectRoot, ".gossip", "agents", config2.id);
16084
- if (!(0, import_fs23.existsSync)(dir)) (0, import_fs23.mkdirSync)(dir, { recursive: true });
16152
+ const dir = (0, import_path26.join)(this.projectRoot, ".gossip", "agents", config2.id);
16153
+ if (!(0, import_fs24.existsSync)(dir)) (0, import_fs24.mkdirSync)(dir, { recursive: true });
16085
16154
  this.pendingAction = null;
16086
16155
  }
16087
16156
  applyRemove(agentId) {
@@ -16115,11 +16184,11 @@ var init_team_manager = __esm({
16115
16184
  };
16116
16185
  }
16117
16186
  writeConfig() {
16118
- const configPath = (0, import_path25.join)(this.projectRoot, ".gossip", "config.json");
16187
+ const configPath = (0, import_path26.join)(this.projectRoot, ".gossip", "config.json");
16119
16188
  let existing = {};
16120
- if ((0, import_fs23.existsSync)(configPath)) {
16189
+ if ((0, import_fs24.existsSync)(configPath)) {
16121
16190
  try {
16122
- existing = JSON.parse((0, import_fs23.readFileSync)(configPath, "utf-8"));
16191
+ existing = JSON.parse((0, import_fs24.readFileSync)(configPath, "utf-8"));
16123
16192
  } catch {
16124
16193
  }
16125
16194
  }
@@ -16131,9 +16200,9 @@ var init_team_manager = __esm({
16131
16200
  ...a.preset ? { preset: a.preset } : {},
16132
16201
  skills: a.skills
16133
16202
  }));
16134
- const dir = (0, import_path25.join)(this.projectRoot, ".gossip");
16135
- if (!(0, import_fs23.existsSync)(dir)) (0, import_fs23.mkdirSync)(dir, { recursive: true });
16136
- (0, import_fs23.writeFileSync)(configPath, JSON.stringify(existing, null, 2) + "\n");
16203
+ const dir = (0, import_path26.join)(this.projectRoot, ".gossip");
16204
+ if (!(0, import_fs24.existsSync)(dir)) (0, import_fs24.mkdirSync)(dir, { recursive: true });
16205
+ (0, import_fs24.writeFileSync)(configPath, JSON.stringify(existing, null, 2) + "\n");
16137
16206
  }
16138
16207
  };
16139
16208
  }
@@ -16355,7 +16424,7 @@ message: Your question?
16355
16424
  }
16356
16425
  /** Start all worker agents (connect to relay) */
16357
16426
  async start() {
16358
- const { existsSync: existsSync41, readFileSync: readFileSync40 } = await import("fs");
16427
+ const { existsSync: existsSync43, readFileSync: readFileSync40 } = await import("fs");
16359
16428
  const { join: join48 } = await import("path");
16360
16429
  for (const config2 of this.registry.getAll()) {
16361
16430
  if (config2.native) continue;
@@ -16366,7 +16435,7 @@ message: Your question?
16366
16435
  }
16367
16436
  const llm = createProvider(config2.provider, config2.model, apiKey);
16368
16437
  const instructionsPath = join48(this.projectRoot, ".gossip", "agents", config2.id, "instructions.md");
16369
- const instructions = existsSync41(instructionsPath) ? readFileSync40(instructionsPath, "utf-8") : void 0;
16438
+ const instructions = existsSync43(instructionsPath) ? readFileSync40(instructionsPath, "utf-8") : void 0;
16370
16439
  const enableWebSearch = config2.preset === "researcher" || config2.skills.includes("research");
16371
16440
  const worker = new WorkerAgent(config2.id, llm, this.relayUrl, ALL_TOOLS, instructions, enableWebSearch, this.relayApiKey);
16372
16441
  await worker.start();
@@ -16548,7 +16617,7 @@ message: Your question?
16548
16617
  this.registry.register(config2);
16549
16618
  }
16550
16619
  async syncWorkers(keyProvider) {
16551
- const { existsSync: existsSync41, readFileSync: readFileSync40 } = await import("fs");
16620
+ const { existsSync: existsSync43, readFileSync: readFileSync40 } = await import("fs");
16552
16621
  const { join: join48 } = await import("path");
16553
16622
  let added = 0;
16554
16623
  for (const ac of this.registry.getAll()) {
@@ -16557,7 +16626,7 @@ message: Your question?
16557
16626
  const key = await keyProvider(ac.provider);
16558
16627
  const llm = createProvider(ac.provider, ac.model, key ?? void 0, void 0, ac.base_url);
16559
16628
  const instructionsPath = join48(this.projectRoot, ".gossip", "agents", ac.id, "instructions.md");
16560
- const instructions = existsSync41(instructionsPath) ? readFileSync40(instructionsPath, "utf-8") : void 0;
16629
+ const instructions = existsSync43(instructionsPath) ? readFileSync40(instructionsPath, "utf-8") : void 0;
16561
16630
  const enableWebSearch = ac.preset === "researcher" || ac.skills.includes("research");
16562
16631
  const worker = new WorkerAgent(ac.id, llm, this.relayUrl, ALL_TOOLS, instructions, enableWebSearch, this.relayApiKey);
16563
16632
  await worker.start();
@@ -17078,12 +17147,12 @@ var init_consensus_types = __esm({
17078
17147
  });
17079
17148
 
17080
17149
  // packages/orchestrator/src/skill-index.ts
17081
- var import_fs24, import_path26, DANGEROUS_KEYS, SkillIndex;
17150
+ var import_fs25, import_path27, DANGEROUS_KEYS, SkillIndex;
17082
17151
  var init_skill_index = __esm({
17083
17152
  "packages/orchestrator/src/skill-index.ts"() {
17084
17153
  "use strict";
17085
- import_fs24 = require("fs");
17086
- import_path26 = require("path");
17154
+ import_fs25 = require("fs");
17155
+ import_path27 = require("path");
17087
17156
  init_skill_name();
17088
17157
  DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype", "_project"]);
17089
17158
  SkillIndex = class {
@@ -17092,7 +17161,7 @@ var init_skill_index = __esm({
17092
17161
  dirty = false;
17093
17162
  _exists = false;
17094
17163
  constructor(projectRoot) {
17095
- this.filePath = (0, import_path26.join)(projectRoot, ".gossip", "skill-index.json");
17164
+ this.filePath = (0, import_path27.join)(projectRoot, ".gossip", "skill-index.json");
17096
17165
  this.load();
17097
17166
  }
17098
17167
  /** Bind a skill to an agent (creates or updates the slot) */
@@ -17284,7 +17353,7 @@ var init_skill_index = __esm({
17284
17353
  }
17285
17354
  load() {
17286
17355
  try {
17287
- const raw = (0, import_fs24.readFileSync)(this.filePath, "utf-8");
17356
+ const raw = (0, import_fs25.readFileSync)(this.filePath, "utf-8");
17288
17357
  const parsed = JSON.parse(raw);
17289
17358
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
17290
17359
  for (const key of Object.keys(parsed)) {
@@ -17306,9 +17375,9 @@ var init_skill_index = __esm({
17306
17375
  }
17307
17376
  save() {
17308
17377
  if (!this.dirty) return;
17309
- const dir = (0, import_path26.dirname)(this.filePath);
17310
- (0, import_fs24.mkdirSync)(dir, { recursive: true });
17311
- (0, import_fs24.writeFileSync)(this.filePath, JSON.stringify(this.data, null, 2) + "\n");
17378
+ const dir = (0, import_path27.dirname)(this.filePath);
17379
+ (0, import_fs25.mkdirSync)(dir, { recursive: true });
17380
+ (0, import_fs25.writeFileSync)(this.filePath, JSON.stringify(this.data, null, 2) + "\n");
17312
17381
  this._exists = true;
17313
17382
  this.dirty = false;
17314
17383
  }
@@ -17323,12 +17392,12 @@ function safeId(value) {
17323
17392
  }
17324
17393
  return encodeURIComponent(value);
17325
17394
  }
17326
- var import_fs25, import_path27, TaskGraphSync;
17395
+ var import_fs26, import_path28, TaskGraphSync;
17327
17396
  var init_task_graph_sync = __esm({
17328
17397
  "packages/orchestrator/src/task-graph-sync.ts"() {
17329
17398
  "use strict";
17330
- import_fs25 = require("fs");
17331
- import_path27 = require("path");
17399
+ import_fs26 = require("fs");
17400
+ import_path28 = require("path");
17332
17401
  TaskGraphSync = class {
17333
17402
  constructor(graph, supabaseUrl, supabaseKey, userId, projectId, projectRoot, displayName, migration) {
17334
17403
  this.graph = graph;
@@ -17338,7 +17407,7 @@ var init_task_graph_sync = __esm({
17338
17407
  this.projectId = projectId;
17339
17408
  this.displayName = displayName;
17340
17409
  this.migration = migration;
17341
- this.gossipDir = (0, import_path27.join)(projectRoot, ".gossip");
17410
+ this.gossipDir = (0, import_path28.join)(projectRoot, ".gossip");
17342
17411
  }
17343
17412
  gossipDir;
17344
17413
  migrationDone = false;
@@ -17461,9 +17530,9 @@ var init_task_graph_sync = __esm({
17461
17530
  });
17462
17531
  }
17463
17532
  async syncAgentScores() {
17464
- const perfPath = (0, import_path27.join)(this.gossipDir, "agent-performance.jsonl");
17465
- if (!(0, import_fs25.existsSync)(perfPath)) return 0;
17466
- const content = (0, import_fs25.readFileSync)(perfPath, "utf-8");
17533
+ const perfPath = (0, import_path28.join)(this.gossipDir, "agent-performance.jsonl");
17534
+ if (!(0, import_fs26.existsSync)(perfPath)) return 0;
17535
+ const content = (0, import_fs26.readFileSync)(perfPath, "utf-8");
17467
17536
  const lines = content.trim().split("\n").filter(Boolean);
17468
17537
  const meta3 = this.graph.getSyncMeta();
17469
17538
  let synced = 0;
@@ -17610,61 +17679,61 @@ Return JSON: { "<agentId>": "<summary>", ... }`
17610
17679
  // packages/orchestrator/src/rules-loader.ts
17611
17680
  function findBundledRules() {
17612
17681
  const candidates = [
17613
- (0, import_path28.resolve)(__dirname, "default-rules", "gossipcat-rules.md"),
17614
- (0, import_path28.resolve)(__dirname, "..", "default-rules", "gossipcat-rules.md"),
17615
- (0, import_path28.resolve)(process.cwd(), "packages", "orchestrator", "src", "default-rules", "gossipcat-rules.md")
17682
+ (0, import_path29.resolve)(__dirname, "default-rules", "gossipcat-rules.md"),
17683
+ (0, import_path29.resolve)(__dirname, "..", "default-rules", "gossipcat-rules.md"),
17684
+ (0, import_path29.resolve)(process.cwd(), "packages", "orchestrator", "src", "default-rules", "gossipcat-rules.md")
17616
17685
  ];
17617
17686
  for (const p of candidates) {
17618
- if ((0, import_fs26.existsSync)(p)) return p;
17687
+ if ((0, import_fs27.existsSync)(p)) return p;
17619
17688
  }
17620
17689
  return null;
17621
17690
  }
17622
17691
  function ensureRulesFile(projectRoot) {
17623
- const target = (0, import_path28.join)(projectRoot, ".gossip", "rules.md");
17624
- if ((0, import_fs26.existsSync)(target)) return { created: false, path: target };
17692
+ const target = (0, import_path29.join)(projectRoot, ".gossip", "rules.md");
17693
+ if ((0, import_fs27.existsSync)(target)) return { created: false, path: target };
17625
17694
  const bundled = findBundledRules();
17626
17695
  if (!bundled) return { created: false, path: null };
17627
17696
  try {
17628
- (0, import_fs26.mkdirSync)((0, import_path28.dirname)(target), { recursive: true });
17629
- (0, import_fs26.copyFileSync)(bundled, target);
17697
+ (0, import_fs27.mkdirSync)((0, import_path29.dirname)(target), { recursive: true });
17698
+ (0, import_fs27.copyFileSync)(bundled, target);
17630
17699
  return { created: true, path: target };
17631
17700
  } catch {
17632
17701
  return { created: false, path: null };
17633
17702
  }
17634
17703
  }
17635
17704
  function readRulesContent(projectRoot) {
17636
- const local = (0, import_path28.join)(projectRoot, ".gossip", "rules.md");
17637
- if ((0, import_fs26.existsSync)(local)) {
17705
+ const local = (0, import_path29.join)(projectRoot, ".gossip", "rules.md");
17706
+ if ((0, import_fs27.existsSync)(local)) {
17638
17707
  try {
17639
- return (0, import_fs26.readFileSync)(local, "utf-8");
17708
+ return (0, import_fs27.readFileSync)(local, "utf-8");
17640
17709
  } catch {
17641
17710
  }
17642
17711
  }
17643
17712
  const bundled = findBundledRules();
17644
17713
  if (bundled) {
17645
17714
  try {
17646
- return (0, import_fs26.readFileSync)(bundled, "utf-8");
17715
+ return (0, import_fs27.readFileSync)(bundled, "utf-8");
17647
17716
  } catch {
17648
17717
  }
17649
17718
  }
17650
17719
  return null;
17651
17720
  }
17652
- var import_fs26, import_path28;
17721
+ var import_fs27, import_path29;
17653
17722
  var init_rules_loader = __esm({
17654
17723
  "packages/orchestrator/src/rules-loader.ts"() {
17655
17724
  "use strict";
17656
- import_fs26 = require("fs");
17657
- import_path28 = require("path");
17725
+ import_fs27 = require("fs");
17726
+ import_path29 = require("path");
17658
17727
  }
17659
17728
  });
17660
17729
 
17661
17730
  // packages/orchestrator/src/bootstrap.ts
17662
- var import_fs27, import_path29, log6, BootstrapGenerator;
17731
+ var import_fs28, import_path30, log6, BootstrapGenerator;
17663
17732
  var init_bootstrap = __esm({
17664
17733
  "packages/orchestrator/src/bootstrap.ts"() {
17665
17734
  "use strict";
17666
- import_fs27 = require("fs");
17667
- import_path29 = require("path");
17735
+ import_fs28 = require("fs");
17736
+ import_path30 = require("path");
17668
17737
  init_rules_loader();
17669
17738
  log6 = (msg) => process.stderr.write(`[gossipcat] ${msg}
17670
17739
  `);
@@ -17687,23 +17756,23 @@ var init_bootstrap = __esm({
17687
17756
  };
17688
17757
  }
17689
17758
  migrateConfig() {
17690
- const oldPath = (0, import_path29.resolve)(this.projectRoot, "gossip.agents.json");
17691
- const newPath = (0, import_path29.resolve)(this.projectRoot, ".gossip", "config.json");
17692
- if (!(0, import_fs27.existsSync)(newPath) && (0, import_fs27.existsSync)(oldPath)) {
17693
- (0, import_fs27.mkdirSync)((0, import_path29.resolve)(this.projectRoot, ".gossip"), { recursive: true });
17694
- (0, import_fs27.copyFileSync)(oldPath, newPath);
17759
+ const oldPath = (0, import_path30.resolve)(this.projectRoot, "gossip.agents.json");
17760
+ const newPath = (0, import_path30.resolve)(this.projectRoot, ".gossip", "config.json");
17761
+ if (!(0, import_fs28.existsSync)(newPath) && (0, import_fs28.existsSync)(oldPath)) {
17762
+ (0, import_fs28.mkdirSync)((0, import_path30.resolve)(this.projectRoot, ".gossip"), { recursive: true });
17763
+ (0, import_fs28.copyFileSync)(oldPath, newPath);
17695
17764
  log6("Migrated config to .gossip/config.json \u2014 gossip.agents.json is now ignored.");
17696
17765
  }
17697
17766
  }
17698
17767
  loadConfig() {
17699
17768
  const paths = [
17700
- (0, import_path29.resolve)(this.projectRoot, ".gossip", "config.json"),
17701
- (0, import_path29.resolve)(this.projectRoot, "gossip.agents.json")
17769
+ (0, import_path30.resolve)(this.projectRoot, ".gossip", "config.json"),
17770
+ (0, import_path30.resolve)(this.projectRoot, "gossip.agents.json")
17702
17771
  ];
17703
17772
  for (const p of paths) {
17704
- if ((0, import_fs27.existsSync)(p)) {
17773
+ if ((0, import_fs28.existsSync)(p)) {
17705
17774
  try {
17706
- return JSON.parse((0, import_fs27.readFileSync)(p, "utf-8"));
17775
+ return JSON.parse((0, import_fs28.readFileSync)(p, "utf-8"));
17707
17776
  } catch {
17708
17777
  log6("Config parse error, falling back to setup mode");
17709
17778
  return null;
@@ -17724,9 +17793,9 @@ var init_bootstrap = __esm({
17724
17793
  skills: ac.skills || [],
17725
17794
  taskCount: 0
17726
17795
  };
17727
- const tasksPath = (0, import_path29.join)(this.projectRoot, ".gossip", "agents", id, "memory", "tasks.jsonl");
17728
- if ((0, import_fs27.existsSync)(tasksPath)) {
17729
- const lines = (0, import_fs27.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
17796
+ const tasksPath = (0, import_path30.join)(this.projectRoot, ".gossip", "agents", id, "memory", "tasks.jsonl");
17797
+ if ((0, import_fs28.existsSync)(tasksPath)) {
17798
+ const lines = (0, import_fs28.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean);
17730
17799
  let count = 0;
17731
17800
  let lastTs = "";
17732
17801
  for (const line of lines) {
@@ -17740,9 +17809,9 @@ var init_bootstrap = __esm({
17740
17809
  summary.taskCount = count;
17741
17810
  if (lastTs) summary.lastActive = lastTs.split("T")[0];
17742
17811
  }
17743
- const memPath = (0, import_path29.join)(this.projectRoot, ".gossip", "agents", id, "memory", "MEMORY.md");
17744
- if ((0, import_fs27.existsSync)(memPath)) {
17745
- const content = (0, import_fs27.readFileSync)(memPath, "utf-8").slice(0, 500);
17812
+ const memPath = (0, import_path30.join)(this.projectRoot, ".gossip", "agents", id, "memory", "MEMORY.md");
17813
+ if ((0, import_fs28.existsSync)(memPath)) {
17814
+ const content = (0, import_fs28.readFileSync)(memPath, "utf-8").slice(0, 500);
17746
17815
  const knowledgeLines = content.match(/- \[([^\]]+)\]/g);
17747
17816
  if (knowledgeLines?.length) {
17748
17817
  summary.topics = knowledgeLines.map((l) => l.replace(/- \[([^\]]+)\].*/, "$1")).join(", ");
@@ -17975,13 +18044,13 @@ Skills are auto-injected from agent config. Project-wide skills in .gossip/skill
17975
18044
  * Returns the body content of the top knowledge files, capped at 2500 chars.
17976
18045
  */
17977
18046
  readProjectMemory() {
17978
- const knowledgeDir = (0, import_path29.join)(this.projectRoot, ".gossip", "agents", "_project", "memory", "knowledge");
17979
- if (!(0, import_fs27.existsSync)(knowledgeDir)) return null;
17980
- const files = (0, import_fs27.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md") && !f.endsWith("-session.md"));
18047
+ const knowledgeDir = (0, import_path30.join)(this.projectRoot, ".gossip", "agents", "_project", "memory", "knowledge");
18048
+ if (!(0, import_fs28.existsSync)(knowledgeDir)) return null;
18049
+ const files = (0, import_fs28.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md") && !f.endsWith("-session.md"));
17981
18050
  if (files.length === 0) return null;
17982
18051
  const scored = files.map((f) => {
17983
18052
  try {
17984
- const content = (0, import_fs27.readFileSync)((0, import_path29.join)(knowledgeDir, f), "utf-8");
18053
+ const content = (0, import_fs28.readFileSync)((0, import_path30.join)(knowledgeDir, f), "utf-8");
17985
18054
  const importance = parseFloat(content.match(/importance:\s*([\d.]+)/)?.[1] ?? "0.5");
17986
18055
  const isPinned = /pinned:\s*true/i.test(content);
17987
18056
  const tsPart = f.slice(0, 19);
@@ -18006,9 +18075,9 @@ Skills are auto-injected from agent config. Project-wide skills in .gossip/skill
18006
18075
  * Annotates TODO/remaining lines where the referenced tool actually exists.
18007
18076
  */
18008
18077
  verifyToolClaims(content) {
18009
- const mcpPath = (0, import_path29.join)(this.projectRoot, "apps", "cli", "src", "mcp-server-sdk.ts");
18010
- if (!(0, import_fs27.existsSync)(mcpPath)) return content;
18011
- const rawSource = (0, import_fs27.readFileSync)(mcpPath, "utf-8");
18078
+ const mcpPath = (0, import_path30.join)(this.projectRoot, "apps", "cli", "src", "mcp-server-sdk.ts");
18079
+ if (!(0, import_fs28.existsSync)(mcpPath)) return content;
18080
+ const rawSource = (0, import_fs28.readFileSync)(mcpPath, "utf-8");
18012
18081
  const source = rawSource.replace(/\/\/.*|\/\*[\s\S]*?\*\//g, "");
18013
18082
  const keywordRe = /TODO|remaining|deferred|needed|pending/i;
18014
18083
  const toolRe = /gossip_\w+/;
@@ -18026,10 +18095,10 @@ Skills are auto-injected from agent config. Project-wide skills in .gossip/skill
18026
18095
  }
18027
18096
  /** Read .gossip/next-session.md if it exists — user/orchestrator notes for the next session */
18028
18097
  readNextSessionNotes() {
18029
- const notesPath = (0, import_path29.join)(this.projectRoot, ".gossip", "next-session.md");
18030
- if (!(0, import_fs27.existsSync)(notesPath)) return null;
18098
+ const notesPath = (0, import_path30.join)(this.projectRoot, ".gossip", "next-session.md");
18099
+ if (!(0, import_fs28.existsSync)(notesPath)) return null;
18031
18100
  try {
18032
- const content = (0, import_fs27.readFileSync)(notesPath, "utf-8").trim();
18101
+ const content = (0, import_fs28.readFileSync)(notesPath, "utf-8").trim();
18033
18102
  if (content.length === 0) return null;
18034
18103
  return this.verifyToolClaims(content.slice(0, 3e3));
18035
18104
  } catch {
@@ -18243,13 +18312,13 @@ var init_check_effectiveness = __esm({
18243
18312
  });
18244
18313
 
18245
18314
  // packages/orchestrator/src/skill-engine.ts
18246
- var import_fs28, import_crypto9, import_path30, SAFE_NAME, KNOWN_CATEGORIES, CATEGORY_KEYWORDS, REQUIRED_SECTIONS, BUNDLED_TEMPLATE, SkillEngine;
18315
+ var import_fs29, import_crypto9, import_path31, SAFE_NAME, KNOWN_CATEGORIES, CATEGORY_KEYWORDS, REQUIRED_SECTIONS, BUNDLED_TEMPLATE, SkillEngine;
18247
18316
  var init_skill_engine = __esm({
18248
18317
  "packages/orchestrator/src/skill-engine.ts"() {
18249
18318
  "use strict";
18250
- import_fs28 = require("fs");
18319
+ import_fs29 = require("fs");
18251
18320
  import_crypto9 = require("crypto");
18252
- import_path30 = require("path");
18321
+ import_path31 = require("path");
18253
18322
  init_skill_name();
18254
18323
  init_check_effectiveness();
18255
18324
  SAFE_NAME = /^[a-z0-9][a-z0-9_-]{0,62}$/;
@@ -18350,9 +18419,9 @@ NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST.
18350
18419
  }
18351
18420
  }
18352
18421
  let projectContext = "";
18353
- const bootstrapPath = (0, import_path30.join)(this.projectRoot, ".gossip", "bootstrap.md");
18354
- if ((0, import_fs28.existsSync)(bootstrapPath)) {
18355
- projectContext = (0, import_fs28.readFileSync)(bootstrapPath, "utf-8").slice(0, 1500);
18422
+ const bootstrapPath = (0, import_path31.join)(this.projectRoot, ".gossip", "bootstrap.md");
18423
+ if ((0, import_fs29.existsSync)(bootstrapPath)) {
18424
+ projectContext = (0, import_fs29.readFileSync)(bootstrapPath, "utf-8").slice(0, 1500);
18356
18425
  }
18357
18426
  if (this.techStackCache === void 0) {
18358
18427
  this.techStackCache = await this.detectTechStack();
@@ -18434,10 +18503,10 @@ Requirements:
18434
18503
  const bound_at = (/* @__PURE__ */ new Date()).toISOString();
18435
18504
  cleaned = this.injectSnapshotFields(cleaned, { baseline_accuracy_correct, baseline_accuracy_hallucinated, bound_at });
18436
18505
  const skillName = normalizeSkillName(category);
18437
- const skillDir = (0, import_path30.join)(this.projectRoot, ".gossip", "agents", agentId, "skills");
18438
- (0, import_fs28.mkdirSync)(skillDir, { recursive: true });
18439
- const skillPath = (0, import_path30.join)(skillDir, `${skillName}.md`);
18440
- (0, import_fs28.writeFileSync)(skillPath, cleaned);
18506
+ const skillDir = (0, import_path31.join)(this.projectRoot, ".gossip", "agents", agentId, "skills");
18507
+ (0, import_fs29.mkdirSync)(skillDir, { recursive: true });
18508
+ const skillPath = (0, import_path31.join)(skillDir, `${skillName}.md`);
18509
+ (0, import_fs29.writeFileSync)(skillPath, cleaned);
18441
18510
  return { path: skillPath, content: cleaned };
18442
18511
  }
18443
18512
  /**
@@ -18481,24 +18550,24 @@ ${fm}
18481
18550
  }
18482
18551
  }
18483
18552
  loadTemplate() {
18484
- const userDir = (0, import_path30.join)(this.projectRoot, ".gossip", "skill-templates");
18485
- if ((0, import_fs28.existsSync)(userDir)) {
18486
- const files = (0, import_fs28.readdirSync)(userDir).filter((f) => f.endsWith(".md"));
18553
+ const userDir = (0, import_path31.join)(this.projectRoot, ".gossip", "skill-templates");
18554
+ if ((0, import_fs29.existsSync)(userDir)) {
18555
+ const files = (0, import_fs29.readdirSync)(userDir).filter((f) => f.endsWith(".md"));
18487
18556
  if (files.length > 0) {
18488
- return (0, import_fs28.readFileSync)((0, import_path30.join)(userDir, files[0]), "utf-8");
18557
+ return (0, import_fs29.readFileSync)((0, import_path31.join)(userDir, files[0]), "utf-8");
18489
18558
  }
18490
18559
  }
18491
18560
  const home = process.env.HOME || process.env.USERPROFILE || "";
18492
- const cacheBase = (0, import_path30.join)(home, ".claude", "plugins", "cache", "claude-plugins-official", "superpowers");
18493
- if ((0, import_fs28.existsSync)(cacheBase)) {
18561
+ const cacheBase = (0, import_path31.join)(home, ".claude", "plugins", "cache", "claude-plugins-official", "superpowers");
18562
+ if ((0, import_fs29.existsSync)(cacheBase)) {
18494
18563
  try {
18495
- const versions = (0, import_fs28.readdirSync)(cacheBase).sort().reverse();
18564
+ const versions = (0, import_fs29.readdirSync)(cacheBase).sort().reverse();
18496
18565
  for (const ver of versions) {
18497
- const skillPath = (0, import_path30.join)(cacheBase, ver, "skills", "systematic-debugging", "SKILL.md");
18498
- if ((0, import_fs28.existsSync)(skillPath)) {
18499
- const realPath = (0, import_fs28.realpathSync)(skillPath);
18500
- if (realPath.startsWith((0, import_path30.resolve)(cacheBase))) {
18501
- return (0, import_fs28.readFileSync)(realPath, "utf-8");
18566
+ const skillPath = (0, import_path31.join)(cacheBase, ver, "skills", "systematic-debugging", "SKILL.md");
18567
+ if ((0, import_fs29.existsSync)(skillPath)) {
18568
+ const realPath = (0, import_fs29.realpathSync)(skillPath);
18569
+ if (realPath.startsWith((0, import_path31.resolve)(cacheBase))) {
18570
+ return (0, import_fs29.readFileSync)(realPath, "utf-8");
18502
18571
  }
18503
18572
  }
18504
18573
  }
@@ -18514,20 +18583,20 @@ ${fm}
18514
18583
  */
18515
18584
  async detectTechStack() {
18516
18585
  const inputs = [];
18517
- const pkgPaths = [(0, import_path30.join)(this.projectRoot, "package.json")];
18586
+ const pkgPaths = [(0, import_path31.join)(this.projectRoot, "package.json")];
18518
18587
  try {
18519
- const packagesDir = (0, import_path30.join)(this.projectRoot, "packages");
18520
- if ((0, import_fs28.existsSync)(packagesDir)) {
18521
- for (const dir of (0, import_fs28.readdirSync)(packagesDir)) {
18522
- const p = (0, import_path30.join)(packagesDir, dir, "package.json");
18523
- if ((0, import_fs28.existsSync)(p)) pkgPaths.push(p);
18588
+ const packagesDir = (0, import_path31.join)(this.projectRoot, "packages");
18589
+ if ((0, import_fs29.existsSync)(packagesDir)) {
18590
+ for (const dir of (0, import_fs29.readdirSync)(packagesDir)) {
18591
+ const p = (0, import_path31.join)(packagesDir, dir, "package.json");
18592
+ if ((0, import_fs29.existsSync)(p)) pkgPaths.push(p);
18524
18593
  }
18525
18594
  }
18526
18595
  } catch {
18527
18596
  }
18528
18597
  for (const p of pkgPaths.slice(0, 5)) {
18529
18598
  try {
18530
- const pkg = JSON.parse((0, import_fs28.readFileSync)(p, "utf-8"));
18599
+ const pkg = JSON.parse((0, import_fs29.readFileSync)(p, "utf-8"));
18531
18600
  const deps = Object.keys({ ...pkg.dependencies, ...pkg.devDependencies });
18532
18601
  if (deps.length > 0) {
18533
18602
  inputs.push(`${p.replace(this.projectRoot + "/", "")}: ${deps.join(", ")}`);
@@ -18536,7 +18605,7 @@ ${fm}
18536
18605
  }
18537
18606
  }
18538
18607
  try {
18539
- const srcDirs = ["src", "packages", "apps", "lib"].filter((d) => (0, import_fs28.existsSync)((0, import_path30.join)(this.projectRoot, d)));
18608
+ const srcDirs = ["src", "packages", "apps", "lib"].filter((d) => (0, import_fs29.existsSync)((0, import_path31.join)(this.projectRoot, d)));
18540
18609
  inputs.push(`Source dirs: ${srcDirs.join(", ") || "root"}`);
18541
18610
  } catch {
18542
18611
  }
@@ -18563,10 +18632,10 @@ ${inputs.join("\n")}
18563
18632
  }
18564
18633
  }
18565
18634
  loadCategoryFindings(category) {
18566
- const filePath = (0, import_path30.join)(this.projectRoot, ".gossip", "agent-performance.jsonl");
18567
- if (!(0, import_fs28.existsSync)(filePath)) return [];
18635
+ const filePath = (0, import_path31.join)(this.projectRoot, ".gossip", "agent-performance.jsonl");
18636
+ if (!(0, import_fs29.existsSync)(filePath)) return [];
18568
18637
  try {
18569
- return (0, import_fs28.readFileSync)(filePath, "utf-8").trim().split("\n").filter(Boolean).map((line) => {
18638
+ return (0, import_fs29.readFileSync)(filePath, "utf-8").trim().split("\n").filter(Boolean).map((line) => {
18570
18639
  try {
18571
18640
  return JSON.parse(line);
18572
18641
  } catch {
@@ -18596,10 +18665,10 @@ ${inputs.join("\n")}
18596
18665
  return { status: "pending", shouldUpdate: false };
18597
18666
  }
18598
18667
  const skillPath = this.resolveSkillPath(agentId, category);
18599
- if (!(0, import_fs28.existsSync)(skillPath)) {
18668
+ if (!(0, import_fs29.existsSync)(skillPath)) {
18600
18669
  return { status: "pending", shouldUpdate: false };
18601
18670
  }
18602
- const raw = (0, import_fs28.readFileSync)(skillPath, "utf-8");
18671
+ const raw = (0, import_fs29.readFileSync)(skillPath, "utf-8");
18603
18672
  const { frontmatter: rawFrontmatter, body } = this.parseSkillFile(raw);
18604
18673
  const nowMs = Date.now();
18605
18674
  const { frontmatter, mutated } = this.migrateIfNeeded(
@@ -18677,7 +18746,7 @@ ${inputs.join("\n")}
18677
18746
  */
18678
18747
  resolveSkillPath(agentId, category) {
18679
18748
  const skillName = normalizeSkillName(category);
18680
- return (0, import_path30.join)(this.projectRoot, ".gossip", "agents", agentId, "skills", `${skillName}.md`);
18749
+ return (0, import_path31.join)(this.projectRoot, ".gossip", "agents", agentId, "skills", `${skillName}.md`);
18681
18750
  }
18682
18751
  /**
18683
18752
  * Splits a skill file into its frontmatter key-value map and the body text
@@ -18765,11 +18834,11 @@ ${fmLines.join("\n")}
18765
18834
  ---${body}`;
18766
18835
  const tmpPath = `${skillPath}.tmp.${process.pid}.${(0, import_crypto9.randomBytes)(4).toString("hex")}`;
18767
18836
  try {
18768
- (0, import_fs28.writeFileSync)(tmpPath, content, "utf-8");
18769
- (0, import_fs28.renameSync)(tmpPath, skillPath);
18837
+ (0, import_fs29.writeFileSync)(tmpPath, content, "utf-8");
18838
+ (0, import_fs29.renameSync)(tmpPath, skillPath);
18770
18839
  } catch (err) {
18771
18840
  try {
18772
- (0, import_fs28.unlinkSync)(tmpPath);
18841
+ (0, import_fs29.unlinkSync)(tmpPath);
18773
18842
  } catch {
18774
18843
  }
18775
18844
  throw err;
@@ -18780,12 +18849,12 @@ ${fmLines.join("\n")}
18780
18849
  });
18781
18850
 
18782
18851
  // packages/orchestrator/src/memory-searcher.ts
18783
- var import_fs29, import_path31, MAX_QUERY_LENGTH, MAX_KEYWORDS, MAX_TASK_FILE_BYTES, MemorySearcher;
18852
+ var import_fs30, import_path32, MAX_QUERY_LENGTH, MAX_KEYWORDS, MAX_TASK_FILE_BYTES, MemorySearcher;
18784
18853
  var init_memory_searcher = __esm({
18785
18854
  "packages/orchestrator/src/memory-searcher.ts"() {
18786
18855
  "use strict";
18787
- import_fs29 = require("fs");
18788
- import_path31 = require("path");
18856
+ import_fs30 = require("fs");
18857
+ import_path32 = require("path");
18789
18858
  MAX_QUERY_LENGTH = 500;
18790
18859
  MAX_KEYWORDS = 20;
18791
18860
  MAX_TASK_FILE_BYTES = 2 * 1024 * 1024;
@@ -18800,19 +18869,19 @@ var init_memory_searcher = __esm({
18800
18869
  const limit = Math.min(maxResults, 10);
18801
18870
  const keywords = this.extractKeywords(safeQuery);
18802
18871
  if (keywords.length === 0) return [];
18803
- const memDir = (0, import_path31.join)(this.projectRoot, ".gossip", "agents", agentId, "memory");
18804
- if (!(0, import_fs29.existsSync)(memDir)) return [];
18872
+ const memDir = (0, import_path32.join)(this.projectRoot, ".gossip", "agents", agentId, "memory");
18873
+ if (!(0, import_fs30.existsSync)(memDir)) return [];
18805
18874
  const results = [];
18806
- const knowledgeDir = (0, import_path31.join)(memDir, "knowledge");
18807
- if ((0, import_fs29.existsSync)(knowledgeDir)) {
18808
- const files = (0, import_fs29.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md"));
18875
+ const knowledgeDir = (0, import_path32.join)(memDir, "knowledge");
18876
+ if ((0, import_fs30.existsSync)(knowledgeDir)) {
18877
+ const files = (0, import_fs30.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md"));
18809
18878
  for (const file2 of files) {
18810
- const filePath = (0, import_path31.join)(knowledgeDir, file2);
18879
+ const filePath = (0, import_path32.join)(knowledgeDir, file2);
18811
18880
  try {
18812
- const content = (0, import_fs29.readFileSync)(filePath, "utf-8");
18881
+ const content = (0, import_fs30.readFileSync)(filePath, "utf-8");
18813
18882
  const frontmatter = this.parseFrontmatter(content);
18814
18883
  const body = content.replace(/^---[\s\S]*?---\n*/, "");
18815
- const name = frontmatter?.name || (0, import_path31.basename)(file2, ".md");
18884
+ const name = frontmatter?.name || (0, import_path32.basename)(file2, ".md");
18816
18885
  const description = frontmatter?.description || "";
18817
18886
  const importance = frontmatter?.importance ?? 0.5;
18818
18887
  const score = this.scoreContent(keywords, name, description, body, importance);
@@ -18829,12 +18898,12 @@ var init_memory_searcher = __esm({
18829
18898
  }
18830
18899
  }
18831
18900
  }
18832
- const tasksPath = (0, import_path31.join)(memDir, "tasks.jsonl");
18833
- if ((0, import_fs29.existsSync)(tasksPath)) {
18901
+ const tasksPath = (0, import_path32.join)(memDir, "tasks.jsonl");
18902
+ if ((0, import_fs30.existsSync)(tasksPath)) {
18834
18903
  try {
18835
- const stat3 = (0, import_fs29.statSync)(tasksPath);
18904
+ const stat3 = (0, import_fs30.statSync)(tasksPath);
18836
18905
  if (stat3.size > MAX_TASK_FILE_BYTES) return results.sort((a, b) => b.score - a.score).slice(0, limit);
18837
- const lines = (0, import_fs29.readFileSync)(tasksPath, "utf-8").split("\n").filter((l) => l.trim());
18906
+ const lines = (0, import_fs30.readFileSync)(tasksPath, "utf-8").split("\n").filter((l) => l.trim());
18838
18907
  for (const line of lines) {
18839
18908
  try {
18840
18909
  const entry = JSON.parse(line);
@@ -19120,9 +19189,9 @@ function prependScopeNote(prompt) {
19120
19189
  }
19121
19190
  function readSandboxMode(projectRoot) {
19122
19191
  try {
19123
- const p = (0, import_path32.join)(projectRoot, ".gossip", "config.json");
19124
- if (!(0, import_fs30.existsSync)(p)) return "warn";
19125
- const raw = JSON.parse((0, import_fs30.readFileSync)(p, "utf-8"));
19192
+ const p = (0, import_path33.join)(projectRoot, ".gossip", "config.json");
19193
+ if (!(0, import_fs31.existsSync)(p)) return "warn";
19194
+ const raw = JSON.parse((0, import_fs31.readFileSync)(p, "utf-8"));
19126
19195
  const mode = raw?.sandboxEnforcement;
19127
19196
  if (mode === "off" || mode === "warn" || mode === "block") return mode;
19128
19197
  return "warn";
@@ -19132,17 +19201,17 @@ function readSandboxMode(projectRoot) {
19132
19201
  }
19133
19202
  function recordDispatchMetadata(projectRoot, meta3) {
19134
19203
  try {
19135
- const dir = (0, import_path32.join)(projectRoot, ".gossip");
19136
- (0, import_fs30.mkdirSync)(dir, { recursive: true });
19137
- (0, import_fs30.appendFileSync)((0, import_path32.join)(dir, METADATA_FILE), JSON.stringify(meta3) + "\n");
19204
+ const dir = (0, import_path33.join)(projectRoot, ".gossip");
19205
+ (0, import_fs31.mkdirSync)(dir, { recursive: true });
19206
+ (0, import_fs31.appendFileSync)((0, import_path33.join)(dir, METADATA_FILE), JSON.stringify(meta3) + "\n");
19138
19207
  } catch {
19139
19208
  }
19140
19209
  }
19141
19210
  function lookupDispatchMetadata(projectRoot, taskId) {
19142
19211
  try {
19143
- const p = (0, import_path32.join)(projectRoot, ".gossip", METADATA_FILE);
19144
- if (!(0, import_fs30.existsSync)(p)) return null;
19145
- const raw = (0, import_fs30.readFileSync)(p, "utf-8");
19212
+ const p = (0, import_path33.join)(projectRoot, ".gossip", METADATA_FILE);
19213
+ if (!(0, import_fs31.existsSync)(p)) return null;
19214
+ const raw = (0, import_fs31.readFileSync)(p, "utf-8");
19146
19215
  const lines = raw.split("\n").filter(Boolean);
19147
19216
  for (let i = lines.length - 1; i >= 0; i--) {
19148
19217
  try {
@@ -19174,21 +19243,21 @@ function parseGitStatus(porcelain) {
19174
19243
  function normalizeScope(scope, projectRoot) {
19175
19244
  let s = scope.trim();
19176
19245
  if (!s) return "";
19177
- if ((0, import_path32.isAbsolute)(s)) {
19178
- s = (0, import_path32.relative)(projectRoot, s);
19246
+ if ((0, import_path33.isAbsolute)(s)) {
19247
+ s = (0, import_path33.relative)(projectRoot, s);
19179
19248
  } else if (s.startsWith("./")) {
19180
19249
  s = s.slice(2);
19181
19250
  }
19182
- s = (0, import_path32.normalize)(s).replace(/\/+$/, "");
19251
+ s = (0, import_path33.normalize)(s).replace(/\/+$/, "");
19183
19252
  if (s === "." || s === "") return "";
19184
19253
  return s;
19185
19254
  }
19186
19255
  function isInsideScope(filePath, scope) {
19187
19256
  if (!scope) return true;
19188
- const f = (0, import_path32.normalize)(filePath).replace(/^\.\//, "");
19257
+ const f = (0, import_path33.normalize)(filePath).replace(/^\.\//, "");
19189
19258
  const s = scope.replace(/^\.\//, "").replace(/\/+$/, "");
19190
19259
  if (f === s) return true;
19191
- return f.startsWith(s + "/") || f.startsWith(s + import_path32.sep);
19260
+ return f.startsWith(s + "/") || f.startsWith(s + import_path33.sep);
19192
19261
  }
19193
19262
  function detectBoundaryEscapes(meta3, modifiedFiles, projectRoot) {
19194
19263
  const mode = meta3.writeMode;
@@ -19250,8 +19319,8 @@ function recordBoundaryEscape(projectRoot, meta3, violations, mode) {
19250
19319
  } catch {
19251
19320
  }
19252
19321
  try {
19253
- const dir = (0, import_path32.join)(projectRoot, ".gossip");
19254
- (0, import_fs30.mkdirSync)(dir, { recursive: true });
19322
+ const dir = (0, import_path33.join)(projectRoot, ".gossip");
19323
+ (0, import_fs31.mkdirSync)(dir, { recursive: true });
19255
19324
  const line = {
19256
19325
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
19257
19326
  taskId: meta3.taskId,
@@ -19262,17 +19331,17 @@ function recordBoundaryEscape(projectRoot, meta3, violations, mode) {
19262
19331
  action: mode
19263
19332
  // "warn" or "block"
19264
19333
  };
19265
- (0, import_fs30.appendFileSync)((0, import_path32.join)(dir, BOUNDARY_ESCAPE_FILE), JSON.stringify(line) + "\n");
19334
+ (0, import_fs31.appendFileSync)((0, import_path33.join)(dir, BOUNDARY_ESCAPE_FILE), JSON.stringify(line) + "\n");
19266
19335
  } catch {
19267
19336
  }
19268
19337
  }
19269
- var import_child_process4, import_fs30, import_path32, METADATA_FILE, BOUNDARY_ESCAPE_FILE, SYSTEM_PREFIXES, SCOPE_NOTE, __test__;
19338
+ var import_child_process4, import_fs31, import_path33, METADATA_FILE, BOUNDARY_ESCAPE_FILE, SYSTEM_PREFIXES, SCOPE_NOTE, __test__;
19270
19339
  var init_sandbox2 = __esm({
19271
19340
  "apps/cli/src/sandbox.ts"() {
19272
19341
  "use strict";
19273
19342
  import_child_process4 = require("child_process");
19274
- import_fs30 = require("fs");
19275
- import_path32 = require("path");
19343
+ import_fs31 = require("fs");
19344
+ import_path33 = require("path");
19276
19345
  METADATA_FILE = "dispatch-metadata.jsonl";
19277
19346
  BOUNDARY_ESCAPE_FILE = "boundary-escapes.jsonl";
19278
19347
  SYSTEM_PREFIXES = [
@@ -19405,6 +19474,10 @@ async function handleRelayCrossReview(consensus_id, agent_id, result) {
19405
19474
  round.pendingNativeAgents.delete(agent_id);
19406
19475
  process.stderr.write(`[gossipcat] \u{1F4E8} Cross-review received from ${agent_id}. Remaining: ${round.pendingNativeAgents.size}
19407
19476
  `);
19477
+ let parsedCount = 0;
19478
+ let acceptedCount = 0;
19479
+ const rejectedPeerIds = /* @__PURE__ */ new Set();
19480
+ let parseError = null;
19408
19481
  try {
19409
19482
  const { ConsensusEngine: ConsensusEngine2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
19410
19483
  const parseLlm = ctx.mainAgent.getLlm();
@@ -19414,14 +19487,51 @@ async function handleRelayCrossReview(consensus_id, agent_id, result) {
19414
19487
  projectRoot: process.cwd()
19415
19488
  });
19416
19489
  const entries = engine.parseCrossReviewResponse(agent_id, result, 50);
19490
+ parsedCount = entries.length;
19417
19491
  const validPeerIds = new Set(round.allResults.map((r) => r.agentId));
19418
- const filtered = entries.filter((e) => e.peerAgentId !== agent_id && validPeerIds.has(e.peerAgentId));
19492
+ const filtered = entries.filter((e) => {
19493
+ const selfReview = e.peerAgentId === agent_id;
19494
+ const unknownPeer = !validPeerIds.has(e.peerAgentId);
19495
+ if (selfReview || unknownPeer) {
19496
+ if (e.peerAgentId) rejectedPeerIds.add(e.peerAgentId);
19497
+ return false;
19498
+ }
19499
+ return true;
19500
+ });
19501
+ acceptedCount = filtered.length;
19419
19502
  round.nativeCrossReviewEntries.push(...filtered);
19503
+ if (parsedCount > 0 && acceptedCount === 0) {
19504
+ process.stderr.write(
19505
+ `[gossipcat] \u26A0\uFE0F Cross-review from ${agent_id}: all ${parsedCount} entries rejected. Bad peer IDs: [${[...rejectedPeerIds].join(", ")}]. Valid round members: [${[...validPeerIds].join(", ")}]. Expected findingId format "<peerAgentId>:f<N>".
19506
+ `
19507
+ );
19508
+ } else if (parsedCount > acceptedCount) {
19509
+ process.stderr.write(
19510
+ `[gossipcat] \u26A0\uFE0F Cross-review from ${agent_id}: ${parsedCount - acceptedCount}/${parsedCount} entries rejected (bad peer IDs: [${[...rejectedPeerIds].join(", ")}]).
19511
+ `
19512
+ );
19513
+ }
19420
19514
  } catch (err) {
19421
- process.stderr.write(`[gossipcat] Failed to parse cross-review from ${agent_id}: ${err.message}
19515
+ parseError = err.message;
19516
+ process.stderr.write(`[gossipcat] Failed to parse cross-review from ${agent_id}: ${parseError}
19422
19517
  `);
19423
19518
  }
19424
19519
  persistPendingConsensus();
19520
+ const validPeerList = [...new Set(round.allResults.map((r) => r.agentId))].join(", ");
19521
+ let diagnostic = "";
19522
+ if (parseError) {
19523
+ diagnostic = `
19524
+ \u26A0\uFE0F Parse error: ${parseError}`;
19525
+ } else if (parsedCount > 0 && acceptedCount === 0) {
19526
+ diagnostic = `
19527
+ \u26A0\uFE0F All ${parsedCount} entries were REJECTED. Bad peer IDs: [${[...rejectedPeerIds].join(", ")}]. Valid round members: [${validPeerList}]. Expected findingId format "<peerAgentId>:f<N>" using exact agent IDs from the round.`;
19528
+ } else if (parsedCount > acceptedCount) {
19529
+ diagnostic = `
19530
+ \u26A0\uFE0F ${parsedCount - acceptedCount}/${parsedCount} entries rejected (bad peer IDs: [${[...rejectedPeerIds].join(", ")}]). Valid round members: [${validPeerList}].`;
19531
+ } else if (parsedCount > 0) {
19532
+ diagnostic = `
19533
+ \u2705 ${acceptedCount}/${parsedCount} entries accepted.`;
19534
+ }
19425
19535
  if (round.pendingNativeAgents.size > 0) {
19426
19536
  const EXTENSION_MS = 6e5;
19427
19537
  const MAX_TOTAL_MS = 36e5;
@@ -19430,7 +19540,7 @@ async function handleRelayCrossReview(consensus_id, agent_id, result) {
19430
19540
  return {
19431
19541
  content: [{
19432
19542
  type: "text",
19433
- text: `Cross-review from ${agent_id} received. Waiting for ${round.pendingNativeAgents.size} more agent(s): ${[...round.pendingNativeAgents].join(", ")}`
19543
+ text: `Cross-review from ${agent_id} received. Waiting for ${round.pendingNativeAgents.size} more agent(s): ${[...round.pendingNativeAgents].join(", ")}${diagnostic}`
19434
19544
  }]
19435
19545
  };
19436
19546
  }
@@ -19545,10 +19655,10 @@ function persistPendingConsensus() {
19545
19655
  }
19546
19656
  function restorePendingConsensus(projectRoot) {
19547
19657
  try {
19548
- const { existsSync: existsSync41, readFileSync: readFileSync40, unlinkSync: unlinkSync4 } = require("fs");
19658
+ const { existsSync: existsSync43, readFileSync: readFileSync40, unlinkSync: unlinkSync4 } = require("fs");
19549
19659
  const { join: join48 } = require("path");
19550
19660
  const filePath = join48(projectRoot, ".gossip", CONSENSUS_FILE);
19551
- if (!existsSync41(filePath)) return;
19661
+ if (!existsSync43(filePath)) return;
19552
19662
  const raw = JSON.parse(readFileSync40(filePath, "utf-8"));
19553
19663
  const now = Date.now();
19554
19664
  for (const [id, data] of Object.entries(raw)) {
@@ -19592,15 +19702,15 @@ __export(check_effectiveness_runner_exports, {
19592
19702
  runCheckEffectivenessForAllSkills: () => runCheckEffectivenessForAllSkills
19593
19703
  });
19594
19704
  async function runCheckEffectivenessForAllSkills(opts) {
19595
- const baseDir = (0, import_path34.join)(opts.projectRoot, ".gossip", "agents");
19596
- if (!(0, import_fs32.existsSync)(baseDir)) return;
19597
- const agentDirs = (0, import_fs32.readdirSync)(baseDir);
19705
+ const baseDir = (0, import_path35.join)(opts.projectRoot, ".gossip", "agents");
19706
+ if (!(0, import_fs33.existsSync)(baseDir)) return;
19707
+ const agentDirs = (0, import_fs33.readdirSync)(baseDir);
19598
19708
  for (const agentId of agentDirs) {
19599
- const skillsDir = (0, import_path34.join)(baseDir, agentId, "skills");
19600
- if (!(0, import_fs32.existsSync)(skillsDir)) continue;
19709
+ const skillsDir = (0, import_path35.join)(baseDir, agentId, "skills");
19710
+ if (!(0, import_fs33.existsSync)(skillsDir)) continue;
19601
19711
  const role = opts.registryGet(agentId)?.role;
19602
19712
  if (role === "implementer") continue;
19603
- const files = (0, import_fs32.readdirSync)(skillsDir).filter((f) => f.endsWith(".md"));
19713
+ const files = (0, import_fs33.readdirSync)(skillsDir).filter((f) => f.endsWith(".md"));
19604
19714
  for (const file2 of files) {
19605
19715
  const category = file2.replace(/\.md$/, "");
19606
19716
  try {
@@ -19621,12 +19731,12 @@ async function runCheckEffectivenessForAllSkills(opts) {
19621
19731
  }
19622
19732
  }
19623
19733
  }
19624
- var import_fs32, import_path34;
19734
+ var import_fs33, import_path35;
19625
19735
  var init_check_effectiveness_runner = __esm({
19626
19736
  "apps/cli/src/handlers/check-effectiveness-runner.ts"() {
19627
19737
  "use strict";
19628
- import_fs32 = require("fs");
19629
- import_path34 = require("path");
19738
+ import_fs33 = require("fs");
19739
+ import_path35 = require("path");
19630
19740
  }
19631
19741
  });
19632
19742
 
@@ -20309,12 +20419,12 @@ async function overviewHandler(projectRoot, ctx2) {
20309
20419
  const hourlyActivity = new Array(12).fill(0);
20310
20420
  const now = Date.now();
20311
20421
  const hourMs = 60 * 60 * 1e3;
20312
- const graphPath = (0, import_path35.join)(projectRoot, ".gossip", "task-graph.jsonl");
20313
- if ((0, import_fs33.existsSync)(graphPath)) {
20422
+ const graphPath = (0, import_path36.join)(projectRoot, ".gossip", "task-graph.jsonl");
20423
+ if ((0, import_fs34.existsSync)(graphPath)) {
20314
20424
  try {
20315
20425
  const created = /* @__PURE__ */ new Map();
20316
20426
  const finished = /* @__PURE__ */ new Set();
20317
- const lines = (0, import_fs33.readFileSync)(graphPath, "utf-8").trim().split("\n").filter(Boolean);
20427
+ const lines = (0, import_fs34.readFileSync)(graphPath, "utf-8").trim().split("\n").filter(Boolean);
20318
20428
  for (const line of lines) {
20319
20429
  try {
20320
20430
  const ev = JSON.parse(line);
@@ -20365,10 +20475,10 @@ async function overviewHandler(projectRoot, ctx2) {
20365
20475
  let lastConsensusTimestamp = "";
20366
20476
  let actionableFindings = 0;
20367
20477
  const consensusTaskIds = /* @__PURE__ */ new Set();
20368
- const perfPath = (0, import_path35.join)(projectRoot, ".gossip", "agent-performance.jsonl");
20369
- if ((0, import_fs33.existsSync)(perfPath)) {
20478
+ const perfPath = (0, import_path36.join)(projectRoot, ".gossip", "agent-performance.jsonl");
20479
+ if ((0, import_fs34.existsSync)(perfPath)) {
20370
20480
  try {
20371
- const lines = (0, import_fs33.readFileSync)(perfPath, "utf-8").trim().split("\n").filter(Boolean);
20481
+ const lines = (0, import_fs34.readFileSync)(perfPath, "utf-8").trim().split("\n").filter(Boolean);
20372
20482
  for (const line of lines) {
20373
20483
  try {
20374
20484
  const entry = JSON.parse(line);
@@ -20401,23 +20511,23 @@ async function overviewHandler(projectRoot, ctx2) {
20401
20511
  const avgDurationMs = durationCount > 0 ? Math.round(totalDuration / durationCount) : 0;
20402
20512
  return { agentsOnline, relayCount, relayConnected, nativeCount, consensusRuns, totalFindings, confirmedFindings, totalSignals, tasksCompleted, tasksFailed, avgDurationMs, lastConsensusTimestamp, actionableFindings, hourlyActivity };
20403
20513
  }
20404
- var import_fs33, import_path35;
20514
+ var import_fs34, import_path36;
20405
20515
  var init_api_overview = __esm({
20406
20516
  "packages/relay/src/dashboard/api-overview.ts"() {
20407
20517
  "use strict";
20408
- import_fs33 = require("fs");
20409
- import_path35 = require("path");
20518
+ import_fs34 = require("fs");
20519
+ import_path36 = require("path");
20410
20520
  }
20411
20521
  });
20412
20522
 
20413
20523
  // packages/relay/src/dashboard/api-agents.ts
20414
20524
  function readTaskGraphByAgent(projectRoot) {
20415
- const taskGraphPath = (0, import_path36.join)(projectRoot, ".gossip", "task-graph.jsonl");
20525
+ const taskGraphPath = (0, import_path37.join)(projectRoot, ".gossip", "task-graph.jsonl");
20416
20526
  const result = /* @__PURE__ */ new Map();
20417
- if (!(0, import_fs34.existsSync)(taskGraphPath)) return result;
20527
+ if (!(0, import_fs35.existsSync)(taskGraphPath)) return result;
20418
20528
  let lines;
20419
20529
  try {
20420
- lines = (0, import_fs34.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
20530
+ lines = (0, import_fs35.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
20421
20531
  } catch {
20422
20532
  return result;
20423
20533
  }
@@ -20514,14 +20624,14 @@ async function agentsHandler(projectRoot, configs, onlineAgents = []) {
20514
20624
  };
20515
20625
  });
20516
20626
  }
20517
- var import_fs34, import_path36, DEFAULT_SCORE;
20627
+ var import_fs35, import_path37, DEFAULT_SCORE;
20518
20628
  var init_api_agents = __esm({
20519
20629
  "packages/relay/src/dashboard/api-agents.ts"() {
20520
20630
  "use strict";
20521
20631
  init_performance_reader();
20522
20632
  init_skill_index();
20523
- import_fs34 = require("fs");
20524
- import_path36 = require("path");
20633
+ import_fs35 = require("fs");
20634
+ import_path37 = require("path");
20525
20635
  DEFAULT_SCORE = {
20526
20636
  agentId: "",
20527
20637
  accuracy: 0.5,
@@ -20545,7 +20655,7 @@ var init_api_agents = __esm({
20545
20655
 
20546
20656
  // packages/relay/src/dashboard/api-skills.ts
20547
20657
  function isCorrupt(projectRoot, index) {
20548
- return (0, import_fs35.existsSync)((0, import_path37.join)(projectRoot, ".gossip", "skill-index.json")) && !index.exists();
20658
+ return (0, import_fs36.existsSync)((0, import_path38.join)(projectRoot, ".gossip", "skill-index.json")) && !index.exists();
20549
20659
  }
20550
20660
  async function skillsGetHandler(projectRoot) {
20551
20661
  try {
@@ -20574,13 +20684,13 @@ async function skillsBindHandler(projectRoot, body) {
20574
20684
  return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
20575
20685
  }
20576
20686
  }
20577
- var import_fs35, import_path37, AGENT_ID_RE2;
20687
+ var import_fs36, import_path38, AGENT_ID_RE2;
20578
20688
  var init_api_skills = __esm({
20579
20689
  "packages/relay/src/dashboard/api-skills.ts"() {
20580
20690
  "use strict";
20581
20691
  init_skill_index();
20582
- import_fs35 = require("fs");
20583
- import_path37 = require("path");
20692
+ import_fs36 = require("fs");
20693
+ import_path38 = require("path");
20584
20694
  AGENT_ID_RE2 = /^[a-zA-Z0-9_-]{1,64}$/;
20585
20695
  }
20586
20696
  });
@@ -20588,25 +20698,25 @@ var init_api_skills = __esm({
20588
20698
  // packages/relay/src/dashboard/api-memory.ts
20589
20699
  async function memoryHandler(projectRoot, agentId) {
20590
20700
  if (!agentId || !AGENT_ID_RE3.test(agentId) || DANGEROUS_IDS.has(agentId)) throw new Error("Invalid agent ID");
20591
- const memDir = (0, import_path38.join)(projectRoot, ".gossip", "agents", agentId, "memory");
20701
+ const memDir = (0, import_path39.join)(projectRoot, ".gossip", "agents", agentId, "memory");
20592
20702
  let index = "";
20593
- const indexPath = (0, import_path38.join)(memDir, "MEMORY.md");
20594
- if ((0, import_fs36.existsSync)(indexPath)) {
20703
+ const indexPath = (0, import_path39.join)(memDir, "MEMORY.md");
20704
+ if ((0, import_fs37.existsSync)(indexPath)) {
20595
20705
  try {
20596
- index = (0, import_fs36.readFileSync)(indexPath, "utf-8");
20706
+ index = (0, import_fs37.readFileSync)(indexPath, "utf-8");
20597
20707
  } catch {
20598
20708
  }
20599
20709
  }
20600
20710
  const knowledge = [];
20601
- const knowledgeDir = (0, import_path38.join)(memDir, "knowledge");
20711
+ const knowledgeDir = (0, import_path39.join)(memDir, "knowledge");
20602
20712
  const knowledgeDirs = [knowledgeDir, memDir];
20603
20713
  for (const dir of knowledgeDirs) {
20604
- if (!(0, import_fs36.existsSync)(dir)) continue;
20714
+ if (!(0, import_fs37.existsSync)(dir)) continue;
20605
20715
  try {
20606
- const files = (0, import_fs36.readdirSync)(dir).filter((f) => f.endsWith(".md") && f !== "MEMORY.md");
20716
+ const files = (0, import_fs37.readdirSync)(dir).filter((f) => f.endsWith(".md") && f !== "MEMORY.md");
20607
20717
  for (const filename of files) {
20608
20718
  try {
20609
- const raw = (0, import_fs36.readFileSync)((0, import_path38.join)(dir, filename), "utf-8");
20719
+ const raw = (0, import_fs37.readFileSync)((0, import_path39.join)(dir, filename), "utf-8");
20610
20720
  const { frontmatter, content } = parseFrontmatter(raw);
20611
20721
  knowledge.push({ filename, frontmatter, content });
20612
20722
  } catch {
@@ -20616,10 +20726,10 @@ async function memoryHandler(projectRoot, agentId) {
20616
20726
  }
20617
20727
  }
20618
20728
  const tasks = [];
20619
- const tasksPath = (0, import_path38.join)(memDir, "tasks.jsonl");
20620
- if ((0, import_fs36.existsSync)(tasksPath)) {
20729
+ const tasksPath = (0, import_path39.join)(memDir, "tasks.jsonl");
20730
+ if ((0, import_fs37.existsSync)(tasksPath)) {
20621
20731
  try {
20622
- const lines = (0, import_fs36.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean).slice(-200);
20732
+ const lines = (0, import_fs37.readFileSync)(tasksPath, "utf-8").trim().split("\n").filter(Boolean).slice(-200);
20623
20733
  for (const line of lines) {
20624
20734
  try {
20625
20735
  tasks.push(JSON.parse(line));
@@ -20647,12 +20757,12 @@ function parseFrontmatter(raw) {
20647
20757
  }
20648
20758
  return { frontmatter: fm, content: raw.slice(end + 3).trim() };
20649
20759
  }
20650
- var import_fs36, import_path38, AGENT_ID_RE3, DANGEROUS_IDS;
20760
+ var import_fs37, import_path39, AGENT_ID_RE3, DANGEROUS_IDS;
20651
20761
  var init_api_memory = __esm({
20652
20762
  "packages/relay/src/dashboard/api-memory.ts"() {
20653
20763
  "use strict";
20654
- import_fs36 = require("fs");
20655
- import_path38 = require("path");
20764
+ import_fs37 = require("fs");
20765
+ import_path39 = require("path");
20656
20766
  AGENT_ID_RE3 = /^[a-zA-Z0-9_-]{1,64}$/;
20657
20767
  DANGEROUS_IDS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
20658
20768
  }
@@ -20664,11 +20774,11 @@ async function consensusHandler(projectRoot, query) {
20664
20774
  const rawPageSize = parseInt(query?.get("pageSize") ?? "", 10);
20665
20775
  const page = isNaN(rawPage) || rawPage < 1 ? 1 : rawPage;
20666
20776
  const pageSize = isNaN(rawPageSize) || rawPageSize < 1 ? DEFAULT_PAGE_SIZE : Math.min(rawPageSize, MAX_PAGE_SIZE);
20667
- const perfPath = (0, import_path39.join)(projectRoot, ".gossip", "agent-performance.jsonl");
20668
- if (!(0, import_fs37.existsSync)(perfPath)) return { runs: [], totalRuns: 0, totalSignals: 0, page, pageSize };
20777
+ const perfPath = (0, import_path40.join)(projectRoot, ".gossip", "agent-performance.jsonl");
20778
+ if (!(0, import_fs38.existsSync)(perfPath)) return { runs: [], totalRuns: 0, totalSignals: 0, page, pageSize };
20669
20779
  const signals = [];
20670
20780
  try {
20671
- const lines = (0, import_fs37.readFileSync)(perfPath, "utf-8").trim().split("\n").filter(Boolean);
20781
+ const lines = (0, import_fs38.readFileSync)(perfPath, "utf-8").trim().split("\n").filter(Boolean);
20672
20782
  for (const line of lines) {
20673
20783
  try {
20674
20784
  const parsed = JSON.parse(line);
@@ -20739,12 +20849,12 @@ async function consensusHandler(projectRoot, query) {
20739
20849
  const paginatedRuns = runs.slice(offset, offset + pageSize);
20740
20850
  return { runs: paginatedRuns, totalRuns, totalSignals: signals.length, page, pageSize };
20741
20851
  }
20742
- var import_fs37, import_path39, RESOLUTION_SIGNALS, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE;
20852
+ var import_fs38, import_path40, RESOLUTION_SIGNALS, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE;
20743
20853
  var init_api_consensus = __esm({
20744
20854
  "packages/relay/src/dashboard/api-consensus.ts"() {
20745
20855
  "use strict";
20746
- import_fs37 = require("fs");
20747
- import_path39 = require("path");
20856
+ import_fs38 = require("fs");
20857
+ import_path40 = require("path");
20748
20858
  RESOLUTION_SIGNALS = /* @__PURE__ */ new Set(["agreement", "unique_confirmed", "consensus_verified"]);
20749
20859
  DEFAULT_PAGE_SIZE = 10;
20750
20860
  MAX_PAGE_SIZE = 50;
@@ -20756,11 +20866,11 @@ async function signalsHandler(projectRoot, query) {
20756
20866
  const agentFilter = query?.get("agent") ?? null;
20757
20867
  const limit = Math.min(Math.max(parseInt(query?.get("limit") ?? "", 10) || DEFAULT_LIMIT, 1), MAX_LIMIT);
20758
20868
  const offset = Math.max(parseInt(query?.get("offset") ?? "", 10) || 0, 0);
20759
- const perfPath = (0, import_path40.join)(projectRoot, ".gossip", "agent-performance.jsonl");
20760
- if (!(0, import_fs38.existsSync)(perfPath)) return { items: [], total: 0, offset, limit };
20869
+ const perfPath = (0, import_path41.join)(projectRoot, ".gossip", "agent-performance.jsonl");
20870
+ if (!(0, import_fs39.existsSync)(perfPath)) return { items: [], total: 0, offset, limit };
20761
20871
  const all = [];
20762
20872
  try {
20763
- const lines = (0, import_fs38.readFileSync)(perfPath, "utf-8").trim().split("\n").filter(Boolean);
20873
+ const lines = (0, import_fs39.readFileSync)(perfPath, "utf-8").trim().split("\n").filter(Boolean);
20764
20874
  for (const line of lines) {
20765
20875
  try {
20766
20876
  const entry = JSON.parse(line);
@@ -20776,12 +20886,12 @@ async function signalsHandler(projectRoot, query) {
20776
20886
  all.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
20777
20887
  return { items: all.slice(offset, offset + limit), total: all.length, offset, limit };
20778
20888
  }
20779
- var import_fs38, import_path40, MAX_LIMIT, DEFAULT_LIMIT;
20889
+ var import_fs39, import_path41, MAX_LIMIT, DEFAULT_LIMIT;
20780
20890
  var init_api_signals = __esm({
20781
20891
  "packages/relay/src/dashboard/api-signals.ts"() {
20782
20892
  "use strict";
20783
- import_fs38 = require("fs");
20784
- import_path40 = require("path");
20893
+ import_fs39 = require("fs");
20894
+ import_path41 = require("path");
20785
20895
  MAX_LIMIT = 200;
20786
20896
  DEFAULT_LIMIT = 50;
20787
20897
  }
@@ -20789,29 +20899,29 @@ var init_api_signals = __esm({
20789
20899
 
20790
20900
  // packages/relay/src/dashboard/api-learnings.ts
20791
20901
  async function learningsHandler(projectRoot) {
20792
- const agentsDir = (0, import_path41.join)(projectRoot, ".gossip", "agents");
20793
- if (!(0, import_fs39.existsSync)(agentsDir)) return { learnings: [] };
20902
+ const agentsDir = (0, import_path42.join)(projectRoot, ".gossip", "agents");
20903
+ if (!(0, import_fs40.existsSync)(agentsDir)) return { learnings: [] };
20794
20904
  const all = [];
20795
20905
  let agentIds;
20796
20906
  try {
20797
- agentIds = (0, import_fs39.readdirSync)(agentsDir).filter((f) => !f.startsWith("."));
20907
+ agentIds = (0, import_fs40.readdirSync)(agentsDir).filter((f) => !f.startsWith("."));
20798
20908
  } catch {
20799
20909
  return { learnings: [] };
20800
20910
  }
20801
20911
  for (const agentId of agentIds) {
20802
- const knowledgeDir = (0, import_path41.join)(agentsDir, agentId, "memory", "knowledge");
20803
- if (!(0, import_fs39.existsSync)(knowledgeDir)) continue;
20912
+ const knowledgeDir = (0, import_path42.join)(agentsDir, agentId, "memory", "knowledge");
20913
+ if (!(0, import_fs40.existsSync)(knowledgeDir)) continue;
20804
20914
  let files;
20805
20915
  try {
20806
- files = (0, import_fs39.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md"));
20916
+ files = (0, import_fs40.readdirSync)(knowledgeDir).filter((f) => f.endsWith(".md"));
20807
20917
  } catch {
20808
20918
  continue;
20809
20919
  }
20810
20920
  for (const filename of files) {
20811
- const filepath = (0, import_path41.join)(knowledgeDir, filename);
20921
+ const filepath = (0, import_path42.join)(knowledgeDir, filename);
20812
20922
  try {
20813
- const stat3 = (0, import_fs39.statSync)(filepath);
20814
- const raw = (0, import_fs39.readFileSync)(filepath, "utf-8");
20923
+ const stat3 = (0, import_fs40.statSync)(filepath);
20924
+ const raw = (0, import_fs40.readFileSync)(filepath, "utf-8");
20815
20925
  const fm = parseFrontmatter2(raw);
20816
20926
  all.push({
20817
20927
  agentId,
@@ -20838,12 +20948,12 @@ function parseFrontmatter2(raw) {
20838
20948
  }
20839
20949
  return fm;
20840
20950
  }
20841
- var import_fs39, import_path41, MAX_LEARNINGS;
20951
+ var import_fs40, import_path42, MAX_LEARNINGS;
20842
20952
  var init_api_learnings = __esm({
20843
20953
  "packages/relay/src/dashboard/api-learnings.ts"() {
20844
20954
  "use strict";
20845
- import_fs39 = require("fs");
20846
- import_path41 = require("path");
20955
+ import_fs40 = require("fs");
20956
+ import_path42 = require("path");
20847
20957
  MAX_LEARNINGS = 10;
20848
20958
  }
20849
20959
  });
@@ -20854,12 +20964,12 @@ async function tasksHandler(projectRoot, query) {
20854
20964
  const rawOffset = parseInt(query?.get("offset") ?? "0", 10);
20855
20965
  const limit = isNaN(rawLimit) || rawLimit < 1 ? 50 : Math.min(rawLimit, 200);
20856
20966
  const offset = isNaN(rawOffset) || rawOffset < 0 ? 0 : rawOffset;
20857
- const graphPath = (0, import_path42.join)(projectRoot, ".gossip", "task-graph.jsonl");
20858
- if (!(0, import_fs40.existsSync)(graphPath)) return { items: [], total: 0, offset, limit };
20967
+ const graphPath = (0, import_path43.join)(projectRoot, ".gossip", "task-graph.jsonl");
20968
+ if (!(0, import_fs41.existsSync)(graphPath)) return { items: [], total: 0, offset, limit };
20859
20969
  const created = /* @__PURE__ */ new Map();
20860
20970
  const completed = /* @__PURE__ */ new Map();
20861
20971
  try {
20862
- const lines = (0, import_fs40.readFileSync)(graphPath, "utf-8").trim().split("\n").filter(Boolean);
20972
+ const lines = (0, import_fs41.readFileSync)(graphPath, "utf-8").trim().split("\n").filter(Boolean);
20863
20973
  for (const line of lines) {
20864
20974
  try {
20865
20975
  const entry = JSON.parse(line);
@@ -20914,23 +21024,23 @@ async function tasksHandler(projectRoot, query) {
20914
21024
  tasks.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
20915
21025
  return { items: tasks.slice(offset, offset + limit), total: tasks.length, offset, limit };
20916
21026
  }
20917
- var import_fs40, import_path42;
21027
+ var import_fs41, import_path43;
20918
21028
  var init_api_tasks = __esm({
20919
21029
  "packages/relay/src/dashboard/api-tasks.ts"() {
20920
21030
  "use strict";
20921
- import_fs40 = require("fs");
20922
- import_path42 = require("path");
21031
+ import_fs41 = require("fs");
21032
+ import_path43 = require("path");
20923
21033
  }
20924
21034
  });
20925
21035
 
20926
21036
  // packages/relay/src/dashboard/api-active-tasks.ts
20927
21037
  async function activeTasksHandler(projectRoot) {
20928
- const taskGraphPath = (0, import_path43.join)(projectRoot, ".gossip", "task-graph.jsonl");
20929
- if (!(0, import_fs41.existsSync)(taskGraphPath)) return { tasks: [] };
21038
+ const taskGraphPath = (0, import_path44.join)(projectRoot, ".gossip", "task-graph.jsonl");
21039
+ if (!(0, import_fs42.existsSync)(taskGraphPath)) return { tasks: [] };
20930
21040
  const created = /* @__PURE__ */ new Map();
20931
21041
  const finished = /* @__PURE__ */ new Set();
20932
21042
  try {
20933
- const lines = (0, import_fs41.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
21043
+ const lines = (0, import_fs42.readFileSync)(taskGraphPath, "utf-8").trim().split("\n").filter(Boolean);
20934
21044
  for (const line of lines) {
20935
21045
  try {
20936
21046
  const ev = JSON.parse(line);
@@ -20957,12 +21067,12 @@ async function activeTasksHandler(projectRoot) {
20957
21067
  active.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
20958
21068
  return { tasks: active.slice(0, 10) };
20959
21069
  }
20960
- var import_fs41, import_path43;
21070
+ var import_fs42, import_path44;
20961
21071
  var init_api_active_tasks = __esm({
20962
21072
  "packages/relay/src/dashboard/api-active-tasks.ts"() {
20963
21073
  "use strict";
20964
- import_fs41 = require("fs");
20965
- import_path43 = require("path");
21074
+ import_fs42 = require("fs");
21075
+ import_path44 = require("path");
20966
21076
  }
20967
21077
  });
20968
21078
 
@@ -20975,25 +21085,25 @@ function categorize(text) {
20975
21085
  return "other";
20976
21086
  }
20977
21087
  function logsHandler(projectRoot, query) {
20978
- const logPath = (0, import_path44.join)(projectRoot, ".gossip", "mcp.log");
20979
- if (!(0, import_fs42.existsSync)(logPath)) {
21088
+ const logPath = (0, import_path45.join)(projectRoot, ".gossip", "mcp.log");
21089
+ if (!(0, import_fs43.existsSync)(logPath)) {
20980
21090
  return { entries: [], totalLines: 0, fileSize: 0 };
20981
21091
  }
20982
21092
  const filter = query?.get("filter") || void 0;
20983
21093
  const tail = parseInt(query?.get("tail") || "200", 10);
20984
21094
  const clampedTail = Math.min(Math.max(tail, 10), 2e3);
20985
- const fileSize = (0, import_fs42.statSync)(logPath).size;
21095
+ const fileSize = (0, import_fs43.statSync)(logPath).size;
20986
21096
  const MAX_READ = 512 * 1024;
20987
21097
  const readFrom = Math.max(0, fileSize - MAX_READ);
20988
21098
  const readLen = fileSize - readFrom;
20989
- const fd = (0, import_fs42.openSync)(logPath, "r");
21099
+ const fd = (0, import_fs43.openSync)(logPath, "r");
20990
21100
  let buf = Buffer.alloc(0);
20991
21101
  try {
20992
21102
  buf = Buffer.allocUnsafe(readLen);
20993
- const bytesRead = (0, import_fs42.readSync)(fd, buf, 0, readLen, readFrom);
21103
+ const bytesRead = (0, import_fs43.readSync)(fd, buf, 0, readLen, readFrom);
20994
21104
  buf = buf.subarray(0, bytesRead);
20995
21105
  } finally {
20996
- (0, import_fs42.closeSync)(fd);
21106
+ (0, import_fs43.closeSync)(fd);
20997
21107
  }
20998
21108
  let raw = buf.toString("utf-8");
20999
21109
  let lineOffset = 0;
@@ -21001,13 +21111,13 @@ function logsHandler(projectRoot, query) {
21001
21111
  const nl = raw.indexOf("\n");
21002
21112
  raw = nl >= 0 ? raw.slice(nl + 1) : raw;
21003
21113
  const SCAN_CHUNK = 64 * 1024;
21004
- const scanFd = (0, import_fs42.openSync)(logPath, "r");
21114
+ const scanFd = (0, import_fs43.openSync)(logPath, "r");
21005
21115
  try {
21006
21116
  let pos = 0;
21007
21117
  const chunk = Buffer.allocUnsafe(SCAN_CHUNK);
21008
21118
  while (pos < readFrom) {
21009
21119
  const len = Math.min(SCAN_CHUNK, readFrom - pos);
21010
- const n = (0, import_fs42.readSync)(scanFd, chunk, 0, len, pos);
21120
+ const n = (0, import_fs43.readSync)(scanFd, chunk, 0, len, pos);
21011
21121
  if (n === 0) break;
21012
21122
  for (let j = 0; j < n; j++) {
21013
21123
  if (chunk[j] === 10) lineOffset++;
@@ -21015,7 +21125,7 @@ function logsHandler(projectRoot, query) {
21015
21125
  pos += n;
21016
21126
  }
21017
21127
  } finally {
21018
- (0, import_fs42.closeSync)(scanFd);
21128
+ (0, import_fs43.closeSync)(scanFd);
21019
21129
  }
21020
21130
  }
21021
21131
  const allLines = raw.split("\n").filter(Boolean);
@@ -21033,12 +21143,12 @@ function logsHandler(projectRoot, query) {
21033
21143
  entries = entries.slice(-clampedTail);
21034
21144
  return { entries, totalLines, fileSize, filter };
21035
21145
  }
21036
- var import_fs42, import_path44, CATEGORY_PATTERNS2;
21146
+ var import_fs43, import_path45, CATEGORY_PATTERNS2;
21037
21147
  var init_api_logs = __esm({
21038
21148
  "packages/relay/src/dashboard/api-logs.ts"() {
21039
21149
  "use strict";
21040
- import_fs42 = require("fs");
21041
- import_path44 = require("path");
21150
+ import_fs43 = require("fs");
21151
+ import_path45 = require("path");
21042
21152
  CATEGORY_PATTERNS2 = [
21043
21153
  [/^\[worker:/, "worker"],
21044
21154
  [/^\[Gemini\]/, "gemini"],
@@ -21066,8 +21176,22 @@ var init_api_logs = __esm({
21066
21176
  });
21067
21177
 
21068
21178
  // packages/relay/src/dashboard/routes.ts
21179
+ function resolveDashboardRoot(projectRoot) {
21180
+ const candidates = [
21181
+ (0, import_path46.resolve)(__dirname, "..", "dist-dashboard"),
21182
+ // bundled: dist-mcp/mcp-server.js → ../dist-dashboard
21183
+ (0, import_path46.resolve)(__dirname, "..", "..", "..", "..", "dist-dashboard"),
21184
+ // tsc dev: packages/relay/dist/dashboard → repo-root
21185
+ (0, import_path46.join)(projectRoot, "dist-dashboard")
21186
+ // legacy dev fallback (git-clone running from repo root)
21187
+ ];
21188
+ for (const p of candidates) {
21189
+ if ((0, import_fs44.existsSync)(p)) return p;
21190
+ }
21191
+ return null;
21192
+ }
21069
21193
  function readBody(req) {
21070
- return new Promise((resolve17, reject) => {
21194
+ return new Promise((resolve18, reject) => {
21071
21195
  const chunks = [];
21072
21196
  let size = 0;
21073
21197
  let tooLarge = false;
@@ -21082,14 +21206,14 @@ function readBody(req) {
21082
21206
  chunks.push(chunk);
21083
21207
  });
21084
21208
  req.on("end", () => {
21085
- if (!tooLarge) resolve17(Buffer.concat(chunks).toString("utf-8"));
21209
+ if (!tooLarge) resolve18(Buffer.concat(chunks).toString("utf-8"));
21086
21210
  });
21087
21211
  req.on("error", (err) => {
21088
21212
  if (!tooLarge) reject(err);
21089
21213
  });
21090
21214
  });
21091
21215
  }
21092
- var import_fs43, import_path45, AUTH_MAX_ATTEMPTS, AUTH_LOCKOUT_MS, DashboardRouter, MAX_BODY_SIZE;
21216
+ var import_fs44, import_path46, AUTH_MAX_ATTEMPTS, AUTH_LOCKOUT_MS, DashboardRouter, MAX_BODY_SIZE;
21093
21217
  var init_routes = __esm({
21094
21218
  "packages/relay/src/dashboard/routes.ts"() {
21095
21219
  "use strict";
@@ -21103,8 +21227,8 @@ var init_routes = __esm({
21103
21227
  init_api_tasks();
21104
21228
  init_api_active_tasks();
21105
21229
  init_api_logs();
21106
- import_fs43 = require("fs");
21107
- import_path45 = require("path");
21230
+ import_fs44 = require("fs");
21231
+ import_path46 = require("path");
21108
21232
  AUTH_MAX_ATTEMPTS = 10;
21109
21233
  AUTH_LOCKOUT_MS = 6e4;
21110
21234
  DashboardRouter = class {
@@ -21112,8 +21236,10 @@ var init_routes = __esm({
21112
21236
  this.auth = auth;
21113
21237
  this.projectRoot = projectRoot;
21114
21238
  this.ctx = ctx2;
21239
+ this.dashboardRoot = resolveDashboardRoot(projectRoot);
21115
21240
  }
21116
21241
  authAttempts = /* @__PURE__ */ new Map();
21242
+ dashboardRoot;
21117
21243
  /** Update live context (call when agents connect/disconnect) */
21118
21244
  updateContext(ctx2) {
21119
21245
  if (ctx2.agentConfigs !== void 0) this.ctx.agentConfigs = ctx2.agentConfigs;
@@ -21279,18 +21405,24 @@ var init_routes = __esm({
21279
21405
  return true;
21280
21406
  }
21281
21407
  serveDashboard(res) {
21282
- const htmlPath = (0, import_path45.join)(this.projectRoot, "dist-dashboard", "index.html");
21283
- if (!(0, import_fs43.existsSync)(htmlPath)) {
21408
+ if (!this.dashboardRoot) {
21409
+ res.writeHead(503, { "Content-Type": "text/plain" });
21410
+ res.end("Dashboard assets not found. Reinstall gossipcat or rebuild from source.");
21411
+ return true;
21412
+ }
21413
+ const htmlPath = (0, import_path46.join)(this.dashboardRoot, "index.html");
21414
+ if (!(0, import_fs44.existsSync)(htmlPath)) {
21284
21415
  res.writeHead(503, { "Content-Type": "text/plain" });
21285
- res.end("Dashboard not built. Run: npm run build:dashboard");
21416
+ res.end(`Dashboard index.html missing at ${this.dashboardRoot}. Reinstall gossipcat.`);
21286
21417
  return true;
21287
21418
  }
21288
- const html = (0, import_fs43.readFileSync)(htmlPath, "utf-8");
21419
+ const html = (0, import_fs44.readFileSync)(htmlPath, "utf-8");
21289
21420
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
21290
21421
  res.end(html);
21291
21422
  return true;
21292
21423
  }
21293
21424
  serveStaticFile(res, url2) {
21425
+ if (!this.dashboardRoot) return false;
21294
21426
  const relativePath = url2.replace(/^\/dashboard\//, "");
21295
21427
  if (relativePath.includes("..")) {
21296
21428
  res.writeHead(404);
@@ -21310,16 +21442,16 @@ var init_routes = __esm({
21310
21442
  const ext = "." + (relativePath.split(".").pop() || "");
21311
21443
  const mime = MIME[ext];
21312
21444
  if (!mime) return false;
21313
- const filePath = (0, import_path45.join)(this.projectRoot, "dist-dashboard", relativePath);
21445
+ const filePath = (0, import_path46.join)(this.dashboardRoot, relativePath);
21314
21446
  try {
21315
- const realFile = (0, import_fs43.realpathSync)(filePath);
21316
- const realBase = (0, import_fs43.realpathSync)((0, import_path45.resolve)(this.projectRoot, "dist-dashboard"));
21447
+ const realFile = (0, import_fs44.realpathSync)(filePath);
21448
+ const realBase = (0, import_fs44.realpathSync)(this.dashboardRoot);
21317
21449
  if (!realFile.startsWith(realBase + "/")) {
21318
21450
  res.writeHead(404);
21319
21451
  res.end();
21320
21452
  return true;
21321
21453
  }
21322
- const data = (0, import_fs43.readFileSync)(realFile);
21454
+ const data = (0, import_fs44.readFileSync)(realFile);
21323
21455
  res.writeHead(200, { "Content-Type": mime, "Cache-Control": "public, max-age=86400" });
21324
21456
  res.end(data);
21325
21457
  return true;
@@ -21334,15 +21466,15 @@ var init_routes = __esm({
21334
21466
  return match ? match[1] : null;
21335
21467
  }
21336
21468
  getConsensusReports(page = 1, pageSize = 5) {
21337
- const { readdirSync: readdirSync13, readFileSync: readFileSync40, existsSync: existsSync41 } = require("fs");
21338
- const reportsDir = (0, import_path45.join)(this.projectRoot, ".gossip", "consensus-reports");
21339
- if (!existsSync41(reportsDir)) return { reports: [], totalReports: 0, page, pageSize };
21469
+ const { readdirSync: readdirSync13, readFileSync: readFileSync40, existsSync: existsSync43 } = require("fs");
21470
+ const reportsDir = (0, import_path46.join)(this.projectRoot, ".gossip", "consensus-reports");
21471
+ if (!existsSync43(reportsDir)) return { reports: [], totalReports: 0, page, pageSize };
21340
21472
  try {
21341
21473
  const { statSync: statSync9 } = require("fs");
21342
21474
  const allFiles = readdirSync13(reportsDir).filter((f) => f.endsWith(".json")).sort((a, b) => {
21343
21475
  try {
21344
- const aTime = statSync9((0, import_path45.join)(reportsDir, a)).mtimeMs;
21345
- const bTime = statSync9((0, import_path45.join)(reportsDir, b)).mtimeMs;
21476
+ const aTime = statSync9((0, import_path46.join)(reportsDir, a)).mtimeMs;
21477
+ const bTime = statSync9((0, import_path46.join)(reportsDir, b)).mtimeMs;
21346
21478
  return bTime - aTime;
21347
21479
  } catch {
21348
21480
  return 0;
@@ -21353,11 +21485,11 @@ var init_routes = __esm({
21353
21485
  const clampedPage = Math.max(page, 1);
21354
21486
  const start = (clampedPage - 1) * clampedPageSize;
21355
21487
  const files = allFiles.slice(start, start + clampedPageSize);
21356
- const realReportsDir = (0, import_fs43.realpathSync)(reportsDir);
21488
+ const realReportsDir = (0, import_fs44.realpathSync)(reportsDir);
21357
21489
  const reports = files.map((f) => {
21358
21490
  try {
21359
- const filePath = (0, import_path45.join)(reportsDir, f);
21360
- const realFile = (0, import_fs43.realpathSync)(filePath);
21491
+ const filePath = (0, import_path46.join)(reportsDir, f);
21492
+ const realFile = (0, import_fs44.realpathSync)(filePath);
21361
21493
  if (!realFile.startsWith(realReportsDir + "/")) return null;
21362
21494
  return JSON.parse(readFileSync40(realFile, "utf-8"));
21363
21495
  } catch {
@@ -21370,27 +21502,27 @@ var init_routes = __esm({
21370
21502
  }
21371
21503
  }
21372
21504
  archiveFindings() {
21373
- const { readdirSync: readdirSync13, readFileSync: readFileSync40, renameSync: renameSync2, writeFileSync: writeFileSync17, mkdirSync: mkdirSync21, existsSync: existsSync41 } = require("fs");
21374
- const reportsDir = (0, import_path45.join)(this.projectRoot, ".gossip", "consensus-reports");
21375
- const archiveDir = (0, import_path45.join)(this.projectRoot, ".gossip", "consensus-reports-archive");
21505
+ const { readdirSync: readdirSync13, readFileSync: readFileSync40, renameSync: renameSync2, writeFileSync: writeFileSync17, mkdirSync: mkdirSync21, existsSync: existsSync43 } = require("fs");
21506
+ const reportsDir = (0, import_path46.join)(this.projectRoot, ".gossip", "consensus-reports");
21507
+ const archiveDir = (0, import_path46.join)(this.projectRoot, ".gossip", "consensus-reports-archive");
21376
21508
  let archived = 0;
21377
- if (existsSync41(reportsDir)) {
21509
+ if (existsSync43(reportsDir)) {
21378
21510
  const files = readdirSync13(reportsDir).filter((f) => f.endsWith(".json")).sort().reverse();
21379
21511
  if (files.length > 5) {
21380
21512
  mkdirSync21(archiveDir, { recursive: true });
21381
21513
  const toArchive = files.slice(5);
21382
21514
  for (const f of toArchive) {
21383
21515
  try {
21384
- renameSync2((0, import_path45.join)(reportsDir, f), (0, import_path45.join)(archiveDir, f));
21516
+ renameSync2((0, import_path46.join)(reportsDir, f), (0, import_path46.join)(archiveDir, f));
21385
21517
  archived++;
21386
21518
  } catch {
21387
21519
  }
21388
21520
  }
21389
21521
  }
21390
21522
  }
21391
- const findingsPath = (0, import_path45.join)(this.projectRoot, ".gossip", "implementation-findings.jsonl");
21523
+ const findingsPath = (0, import_path46.join)(this.projectRoot, ".gossip", "implementation-findings.jsonl");
21392
21524
  let findingsCleared = 0;
21393
- if (existsSync41(findingsPath)) {
21525
+ if (existsSync43(findingsPath)) {
21394
21526
  try {
21395
21527
  const lines = readFileSync40(findingsPath, "utf-8").trim().split("\n").filter(Boolean);
21396
21528
  const kept = lines.filter((line) => {
@@ -21409,7 +21541,7 @@ var init_routes = __esm({
21409
21541
  } catch {
21410
21542
  }
21411
21543
  }
21412
- const remaining = existsSync41(reportsDir) ? readdirSync13(reportsDir).filter((f) => f.endsWith(".json")).length : 0;
21544
+ const remaining = existsSync43(reportsDir) ? readdirSync13(reportsDir).filter((f) => f.endsWith(".json")).length : 0;
21413
21545
  return { archived, remaining, findingsCleared };
21414
21546
  }
21415
21547
  json(res, status, data) {
@@ -21422,14 +21554,14 @@ var init_routes = __esm({
21422
21554
  });
21423
21555
 
21424
21556
  // packages/relay/src/dashboard/ws.ts
21425
- var import_ws3, import_fs44, import_fs45, import_path46, DashboardWs;
21557
+ var import_ws3, import_fs45, import_fs46, import_path47, DashboardWs;
21426
21558
  var init_ws = __esm({
21427
21559
  "packages/relay/src/dashboard/ws.ts"() {
21428
21560
  "use strict";
21429
21561
  import_ws3 = require("ws");
21430
- import_fs44 = require("fs");
21431
21562
  import_fs45 = require("fs");
21432
- import_path46 = require("path");
21563
+ import_fs46 = require("fs");
21564
+ import_path47 = require("path");
21433
21565
  DashboardWs = class {
21434
21566
  clients = /* @__PURE__ */ new Set();
21435
21567
  logWatcher = null;
@@ -21454,15 +21586,15 @@ var init_ws = __esm({
21454
21586
  /** Start watching mcp.log for new lines and broadcasting them to connected clients. */
21455
21587
  startLogWatcher(projectRoot) {
21456
21588
  this.stopLogWatcher();
21457
- this.logPath = (0, import_path46.join)(projectRoot, ".gossip", "mcp.log");
21458
- if (!(0, import_fs44.existsSync)(this.logPath)) return;
21589
+ this.logPath = (0, import_path47.join)(projectRoot, ".gossip", "mcp.log");
21590
+ if (!(0, import_fs45.existsSync)(this.logPath)) return;
21459
21591
  try {
21460
- this.logOffset = (0, import_fs44.statSync)(this.logPath).size;
21592
+ this.logOffset = (0, import_fs45.statSync)(this.logPath).size;
21461
21593
  } catch {
21462
21594
  this.logOffset = 0;
21463
21595
  }
21464
21596
  try {
21465
- this.logWatcher = (0, import_fs45.watch)(this.logPath, () => {
21597
+ this.logWatcher = (0, import_fs46.watch)(this.logPath, () => {
21466
21598
  if (this.clients.size === 0) return;
21467
21599
  this.readNewLines();
21468
21600
  });
@@ -21479,7 +21611,7 @@ var init_ws = __esm({
21479
21611
  if (this.logReading) return;
21480
21612
  this.logReading = true;
21481
21613
  try {
21482
- const currentSize = (0, import_fs44.statSync)(this.logPath).size;
21614
+ const currentSize = (0, import_fs45.statSync)(this.logPath).size;
21483
21615
  if (currentSize < this.logOffset) {
21484
21616
  this.logOffset = 0;
21485
21617
  this.logCarry = "";
@@ -21492,7 +21624,7 @@ var init_ws = __esm({
21492
21624
  const readFrom = capped ? (this.logCarry = "", this.logCapped = true, currentSize - 65536) : (this.logCapped = false, this.logOffset);
21493
21625
  let stream;
21494
21626
  try {
21495
- stream = (0, import_fs44.createReadStream)(this.logPath, { start: readFrom, end: currentSize - 1 });
21627
+ stream = (0, import_fs45.createReadStream)(this.logPath, { start: readFrom, end: currentSize - 1 });
21496
21628
  } catch {
21497
21629
  this.logReading = false;
21498
21630
  return;
@@ -21586,7 +21718,7 @@ var init_server = __esm({
21586
21718
  return `ws://localhost:${this._port}`;
21587
21719
  }
21588
21720
  async start() {
21589
- return new Promise((resolve17) => {
21721
+ return new Promise((resolve18) => {
21590
21722
  this.httpServer = (0, import_http.createServer)(this.handleHttp.bind(this));
21591
21723
  if (this.config.dashboard) {
21592
21724
  this.dashboardAuth = new DashboardAuth();
@@ -21631,7 +21763,7 @@ var init_server = __esm({
21631
21763
  this.httpServer.listen(this.config.port, this.config.host ?? "127.0.0.1", () => {
21632
21764
  const addr = this.httpServer.address();
21633
21765
  this._port = addr.port;
21634
- resolve17();
21766
+ resolve18();
21635
21767
  });
21636
21768
  });
21637
21769
  }
@@ -21650,9 +21782,9 @@ var init_server = __esm({
21650
21782
  for (const client of this.wss.clients) {
21651
21783
  client.close(1001, "Server shutting down");
21652
21784
  }
21653
- return new Promise((resolve17) => {
21785
+ return new Promise((resolve18) => {
21654
21786
  this.wss.close(() => {
21655
- this.httpServer.close(() => resolve17());
21787
+ this.httpServer.close(() => resolve18());
21656
21788
  });
21657
21789
  });
21658
21790
  }
@@ -21848,18 +21980,18 @@ __export(config_exports, {
21848
21980
  function findConfigPath(projectRoot) {
21849
21981
  const root = projectRoot || process.cwd();
21850
21982
  const candidates = [
21851
- (0, import_path47.resolve)(root, ".gossip", "config.json"),
21852
- (0, import_path47.resolve)(root, "gossip.agents.json"),
21853
- (0, import_path47.resolve)(root, "gossip.agents.yaml"),
21854
- (0, import_path47.resolve)(root, "gossip.agents.yml")
21983
+ (0, import_path48.resolve)(root, ".gossip", "config.json"),
21984
+ (0, import_path48.resolve)(root, "gossip.agents.json"),
21985
+ (0, import_path48.resolve)(root, "gossip.agents.yaml"),
21986
+ (0, import_path48.resolve)(root, "gossip.agents.yml")
21855
21987
  ];
21856
21988
  for (const p of candidates) {
21857
- if ((0, import_fs46.existsSync)(p)) return p;
21989
+ if ((0, import_fs47.existsSync)(p)) return p;
21858
21990
  }
21859
21991
  return null;
21860
21992
  }
21861
21993
  function loadConfig(configPath) {
21862
- const raw = (0, import_fs46.readFileSync)(configPath, "utf-8");
21994
+ const raw = (0, import_fs47.readFileSync)(configPath, "utf-8");
21863
21995
  let parsed;
21864
21996
  try {
21865
21997
  parsed = JSON.parse(raw);
@@ -21938,19 +22070,19 @@ function configToAgentConfigs(config2) {
21938
22070
  }
21939
22071
  function loadClaudeSubagents(projectRoot, existingIds) {
21940
22072
  const root = projectRoot || process.cwd();
21941
- const agentsDir = (0, import_path47.join)(root, ".claude", "agents");
21942
- if (!(0, import_fs46.existsSync)(agentsDir)) return [];
22073
+ const agentsDir = (0, import_path48.join)(root, ".claude", "agents");
22074
+ if (!(0, import_fs47.existsSync)(agentsDir)) return [];
21943
22075
  let files;
21944
22076
  try {
21945
- files = (0, import_fs46.readdirSync)(agentsDir).filter((f) => f.endsWith(".md"));
22077
+ files = (0, import_fs47.readdirSync)(agentsDir).filter((f) => f.endsWith(".md"));
21946
22078
  } catch {
21947
22079
  return [];
21948
22080
  }
21949
22081
  const agents = [];
21950
22082
  for (const file2 of files) {
21951
- const filePath = (0, import_path47.join)(agentsDir, file2);
22083
+ const filePath = (0, import_path48.join)(agentsDir, file2);
21952
22084
  try {
21953
- const content = (0, import_fs46.readFileSync)(filePath, "utf-8");
22085
+ const content = (0, import_fs47.readFileSync)(filePath, "utf-8");
21954
22086
  const frontmatter = content.match(/^---\n([\s\S]*?)\n---/);
21955
22087
  if (!frontmatter) continue;
21956
22088
  const fm = frontmatter[1];
@@ -22005,12 +22137,12 @@ function inferSkills(description, name) {
22005
22137
  if (skills.length === 0) skills.push("general");
22006
22138
  return skills;
22007
22139
  }
22008
- var import_fs46, import_path47, VALID_PROVIDERS, CLAUDE_MODEL_MAP;
22140
+ var import_fs47, import_path48, VALID_PROVIDERS, CLAUDE_MODEL_MAP;
22009
22141
  var init_config = __esm({
22010
22142
  "apps/cli/src/config.ts"() {
22011
22143
  "use strict";
22012
- import_fs46 = require("fs");
22013
- import_path47 = require("path");
22144
+ import_fs47 = require("fs");
22145
+ import_path48 = require("path");
22014
22146
  VALID_PROVIDERS = ["anthropic", "openai", "openclaw", "google", "local", "native"];
22015
22147
  CLAUDE_MODEL_MAP = {
22016
22148
  opus: { provider: "anthropic", model: "claude-opus-4-6" },
@@ -22025,14 +22157,14 @@ var keychain_exports = {};
22025
22157
  __export(keychain_exports, {
22026
22158
  Keychain: () => Keychain
22027
22159
  });
22028
- var import_child_process5, import_os2, import_fs47, import_path48, import_crypto15, SERVICE_NAME, VALID_PROVIDERS2, ENCRYPTED_FILE, ALGO, Keychain;
22160
+ var import_child_process5, import_os2, import_fs48, import_path49, import_crypto15, SERVICE_NAME, VALID_PROVIDERS2, ENCRYPTED_FILE, ALGO, Keychain;
22029
22161
  var init_keychain = __esm({
22030
22162
  "apps/cli/src/keychain.ts"() {
22031
22163
  "use strict";
22032
22164
  import_child_process5 = require("child_process");
22033
22165
  import_os2 = require("os");
22034
- import_fs47 = require("fs");
22035
- import_path48 = require("path");
22166
+ import_fs48 = require("fs");
22167
+ import_path49 = require("path");
22036
22168
  import_crypto15 = require("crypto");
22037
22169
  SERVICE_NAME = "gossip-mesh";
22038
22170
  VALID_PROVIDERS2 = /^[a-zA-Z0-9_-]{1,32}$/;
@@ -22074,10 +22206,10 @@ var init_keychain = __esm({
22074
22206
  return (0, import_crypto15.pbkdf2Sync)(seed, salt, 6e5, 32, "sha256");
22075
22207
  }
22076
22208
  loadEncryptedFile() {
22077
- const filePath = (0, import_path48.join)(process.cwd(), ENCRYPTED_FILE);
22078
- if (!(0, import_fs47.existsSync)(filePath)) return;
22209
+ const filePath = (0, import_path49.join)(process.cwd(), ENCRYPTED_FILE);
22210
+ if (!(0, import_fs48.existsSync)(filePath)) return;
22079
22211
  try {
22080
- const raw = (0, import_fs47.readFileSync)(filePath);
22212
+ const raw = (0, import_fs48.readFileSync)(filePath);
22081
22213
  if (raw.length < 61) return;
22082
22214
  const salt = raw.subarray(0, 32);
22083
22215
  const iv = raw.subarray(32, 44);
@@ -22095,9 +22227,9 @@ var init_keychain = __esm({
22095
22227
  }
22096
22228
  }
22097
22229
  saveEncryptedFile() {
22098
- const filePath = (0, import_path48.join)(process.cwd(), ENCRYPTED_FILE);
22099
- const dir = (0, import_path48.join)(process.cwd(), ".gossip");
22100
- if (!(0, import_fs47.existsSync)(dir)) (0, import_fs47.mkdirSync)(dir, { recursive: true });
22230
+ const filePath = (0, import_path49.join)(process.cwd(), ENCRYPTED_FILE);
22231
+ const dir = (0, import_path49.join)(process.cwd(), ".gossip");
22232
+ if (!(0, import_fs48.existsSync)(dir)) (0, import_fs48.mkdirSync)(dir, { recursive: true });
22101
22233
  const data = JSON.stringify(Object.fromEntries(this.inMemoryStore));
22102
22234
  const salt = (0, import_crypto15.randomBytes)(32);
22103
22235
  const iv = (0, import_crypto15.randomBytes)(12);
@@ -22105,7 +22237,7 @@ var init_keychain = __esm({
22105
22237
  const cipher = (0, import_crypto15.createCipheriv)(ALGO, key, iv);
22106
22238
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
22107
22239
  const tag = cipher.getAuthTag();
22108
- (0, import_fs47.writeFileSync)(filePath, Buffer.concat([salt, iv, tag, encrypted]), { mode: 384 });
22240
+ (0, import_fs48.writeFileSync)(filePath, Buffer.concat([salt, iv, tag, encrypted]), { mode: 384 });
22109
22241
  }
22110
22242
  isKeychainAvailable() {
22111
22243
  if ((0, import_os2.platform)() === "darwin") {
@@ -22205,17 +22337,17 @@ __export(identity_exports, {
22205
22337
  normalizeGitUrl: () => normalizeGitUrl
22206
22338
  });
22207
22339
  function getOrCreateSalt(projectRoot) {
22208
- const saltPath = (0, import_path49.join)(projectRoot, ".gossip", "local-salt");
22340
+ const saltPath = (0, import_path50.join)(projectRoot, ".gossip", "local-salt");
22209
22341
  try {
22210
- return (0, import_fs48.readFileSync)(saltPath, "utf-8").trim();
22342
+ return (0, import_fs49.readFileSync)(saltPath, "utf-8").trim();
22211
22343
  } catch {
22212
22344
  const salt = (0, import_crypto16.randomBytes)(16).toString("hex");
22213
- (0, import_fs48.mkdirSync)((0, import_path49.join)(projectRoot, ".gossip"), { recursive: true });
22345
+ (0, import_fs49.mkdirSync)((0, import_path50.join)(projectRoot, ".gossip"), { recursive: true });
22214
22346
  try {
22215
- (0, import_fs48.writeFileSync)(saltPath, salt, { flag: "wx" });
22347
+ (0, import_fs49.writeFileSync)(saltPath, salt, { flag: "wx" });
22216
22348
  return salt;
22217
22349
  } catch {
22218
- return (0, import_fs48.readFileSync)(saltPath, "utf-8").trim();
22350
+ return (0, import_fs49.readFileSync)(saltPath, "utf-8").trim();
22219
22351
  }
22220
22352
  }
22221
22353
  }
@@ -22265,12 +22397,12 @@ function getProjectId(projectRoot) {
22265
22397
  }
22266
22398
  return (0, import_crypto16.createHash)("sha256").update(projectRoot).digest("hex").slice(0, 16);
22267
22399
  }
22268
- var import_fs48, import_path49, import_crypto16, import_child_process6;
22400
+ var import_fs49, import_path50, import_crypto16, import_child_process6;
22269
22401
  var init_identity = __esm({
22270
22402
  "apps/cli/src/identity.ts"() {
22271
22403
  "use strict";
22272
- import_fs48 = require("fs");
22273
- import_path49 = require("path");
22404
+ import_fs49 = require("fs");
22405
+ import_path50 = require("path");
22274
22406
  import_crypto16 = require("crypto");
22275
22407
  import_child_process6 = require("child_process");
22276
22408
  }
@@ -22282,14 +22414,8 @@ __export(gossip_update_exports, {
22282
22414
  handleGossipUpdate: () => handleGossipUpdate
22283
22415
  });
22284
22416
  function getCurrentVersion() {
22285
- try {
22286
- const pkgPath = (0, import_path50.resolve)(__dirname, "..", "..", "..", "..", "package.json");
22287
- if ((0, import_fs49.existsSync)(pkgPath)) {
22288
- return JSON.parse((0, import_fs49.readFileSync)(pkgPath, "utf-8")).version ?? "0.0.0";
22289
- }
22290
- } catch {
22291
- }
22292
- return "0.0.0";
22417
+ const v = getGossipcatVersion();
22418
+ return v === "unknown" ? "0.0.0" : v;
22293
22419
  }
22294
22420
  async function getLatestVersion() {
22295
22421
  const res = await fetch("https://registry.npmjs.org/gossipcat/latest");
@@ -22298,9 +22424,9 @@ async function getLatestVersion() {
22298
22424
  return data.version;
22299
22425
  }
22300
22426
  function detectInstallMethod() {
22301
- const packageRoot = (0, import_path50.resolve)(__dirname, "..", "..", "..", "..");
22427
+ const packageRoot = (0, import_path51.resolve)(__dirname, "..", "..", "..", "..");
22302
22428
  if (process.env.npm_config_global === "true") return "global";
22303
- if ((0, import_fs49.existsSync)((0, import_path50.join)(packageRoot, ".git"))) return "git-clone";
22429
+ if ((0, import_fs50.existsSync)((0, import_path51.join)(packageRoot, ".git"))) return "git-clone";
22304
22430
  return "local";
22305
22431
  }
22306
22432
  function updateCommand(method, version2) {
@@ -22351,7 +22477,7 @@ Check your internet connection or visit https://www.npmjs.com/package/gossipcat
22351
22477
  try {
22352
22478
  (0, import_child_process7.execSync)(command, {
22353
22479
  stdio: "inherit",
22354
- cwd: method === "git-clone" ? (0, import_path50.resolve)(__dirname, "..", "..", "..", "..") : process.cwd()
22480
+ cwd: method === "git-clone" ? (0, import_path51.resolve)(__dirname, "..", "..", "..", "..") : process.cwd()
22355
22481
  });
22356
22482
  } catch (err) {
22357
22483
  return {
@@ -22373,13 +22499,14 @@ Run /mcp reconnect in Claude Code to load the new version.`
22373
22499
  }]
22374
22500
  };
22375
22501
  }
22376
- var import_child_process7, import_fs49, import_path50;
22502
+ var import_child_process7, import_fs50, import_path51;
22377
22503
  var init_gossip_update = __esm({
22378
22504
  "apps/cli/src/handlers/gossip-update.ts"() {
22379
22505
  "use strict";
22380
22506
  import_child_process7 = require("child_process");
22381
- import_fs49 = require("fs");
22382
- import_path50 = require("path");
22507
+ import_fs50 = require("fs");
22508
+ import_path51 = require("path");
22509
+ init_version();
22383
22510
  }
22384
22511
  });
22385
22512
 
@@ -22542,8 +22669,8 @@ var init_verify_memory = __esm({
22542
22669
  });
22543
22670
 
22544
22671
  // apps/cli/src/mcp-server-sdk.ts
22545
- var import_fs50 = require("fs");
22546
- var import_path51 = require("path");
22672
+ var import_fs51 = require("fs");
22673
+ var import_path52 = require("path");
22547
22674
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
22548
22675
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
22549
22676
  var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
@@ -36320,6 +36447,7 @@ config(en_default());
36320
36447
  var import_crypto17 = require("crypto");
36321
36448
  var import_http2 = require("http");
36322
36449
  init_mcp_context();
36450
+ init_version();
36323
36451
 
36324
36452
  // apps/cli/src/handlers/native-tasks.ts
36325
36453
  var import_crypto10 = require("crypto");
@@ -36724,8 +36852,8 @@ ${utilityBlocks.join("\n\n")}`;
36724
36852
 
36725
36853
  // apps/cli/src/handlers/dispatch.ts
36726
36854
  var import_crypto11 = require("crypto");
36727
- var import_fs31 = require("fs");
36728
- var import_path33 = require("path");
36855
+ var import_fs32 = require("fs");
36856
+ var import_path34 = require("path");
36729
36857
  init_src4();
36730
36858
  init_src3();
36731
36859
  init_mcp_context();
@@ -36842,7 +36970,7 @@ var AGENT_PROVIDER_MAP = {
36842
36970
  };
36843
36971
  function readQuotaState() {
36844
36972
  try {
36845
- const raw = (0, import_fs31.readFileSync)((0, import_path33.join)(process.cwd(), ".gossip", "quota-state.json"), "utf8");
36973
+ const raw = (0, import_fs32.readFileSync)((0, import_path34.join)(process.cwd(), ".gossip", "quota-state.json"), "utf8");
36846
36974
  return JSON.parse(raw);
36847
36975
  } catch {
36848
36976
  return {};
@@ -37188,8 +37316,8 @@ async function handleDispatchConsensus(taskDefs, _utility_task_id) {
37188
37316
  });
37189
37317
  const lenses = await Promise.race([
37190
37318
  lensPromise,
37191
- new Promise((resolve17) => {
37192
- timerId = setTimeout(() => resolve17(null), LENS_TIMEOUT_MS);
37319
+ new Promise((resolve18) => {
37320
+ timerId = setTimeout(() => resolve18(null), LENS_TIMEOUT_MS);
37193
37321
  })
37194
37322
  ]);
37195
37323
  if (timerId) clearTimeout(timerId);
@@ -37405,7 +37533,7 @@ Relay may be down. Check gossip_status() for connection state.` }] };
37405
37533
  process.stderr.write(`[gossipcat] \u23F3 Consensus: ${doneCount}/${pendingNativeIds.length} agents complete (${agentStatus})
37406
37534
  `);
37407
37535
  }
37408
- await new Promise((resolve17) => setTimeout(resolve17, POLL_INTERVAL));
37536
+ await new Promise((resolve18) => setTimeout(resolve18, POLL_INTERVAL));
37409
37537
  }
37410
37538
  const arrived = pendingNativeIds.filter((id) => ctx.nativeResultMap.has(id)).length;
37411
37539
  const timedOutCount = pendingNativeIds.filter((id) => {
@@ -37902,12 +38030,12 @@ ${gaps.map((g) => ` - ${g.agentId} needs "${g.category}" (score: ${g.score.toFi
37902
38030
 
37903
38031
  // apps/cli/src/mcp-server-sdk.ts
37904
38032
  init_relay_cross_review();
37905
- var gossipDir = (0, import_path51.join)(process.cwd(), ".gossip");
38033
+ var gossipDir = (0, import_path52.join)(process.cwd(), ".gossip");
37906
38034
  try {
37907
- (0, import_fs50.mkdirSync)(gossipDir, { recursive: true });
38035
+ (0, import_fs51.mkdirSync)(gossipDir, { recursive: true });
37908
38036
  } catch {
37909
38037
  }
37910
- var logStream = (0, import_fs50.createWriteStream)((0, import_path51.join)(gossipDir, "mcp.log"), { flags: "a" });
38038
+ var logStream = (0, import_fs51.createWriteStream)((0, import_path52.join)(gossipDir, "mcp.log"), { flags: "a" });
37911
38039
  process.stderr.write = ((chunk, ...args) => {
37912
38040
  return logStream.write(chunk, ...args);
37913
38041
  });
@@ -38074,10 +38202,10 @@ var _pendingSessionData = /* @__PURE__ */ new Map();
38074
38202
  var _pendingVerifyData = /* @__PURE__ */ new Map();
38075
38203
  var _modules = null;
38076
38204
  function lookupFindingSeverity(findingId, projectRoot) {
38077
- const { existsSync: existsSync41, readdirSync: readdirSync13, readFileSync: readFileSync40 } = require("fs");
38205
+ const { existsSync: existsSync43, readdirSync: readdirSync13, readFileSync: readFileSync40 } = require("fs");
38078
38206
  const { join: join48 } = require("path");
38079
38207
  const reportsDir = join48(projectRoot, ".gossip", "consensus-reports");
38080
- if (!existsSync41(reportsDir)) return null;
38208
+ if (!existsSync43(reportsDir)) return null;
38081
38209
  try {
38082
38210
  const files = readdirSync13(reportsDir).filter((f) => f.endsWith(".json"));
38083
38211
  for (const file2 of files) {
@@ -38144,12 +38272,21 @@ async function refreshBootstrap() {
38144
38272
  async function doBoot() {
38145
38273
  const m = await getModules();
38146
38274
  const configPath = m.findConfigPath();
38147
- if (!configPath) throw new Error("No gossip.agents.json found. Run gossipcat setup first.");
38148
- const config2 = m.loadConfig(configPath);
38275
+ let config2;
38276
+ if (configPath) {
38277
+ config2 = m.loadConfig(configPath);
38278
+ } else {
38279
+ process.stderr.write("[gossipcat] \u26A0\uFE0F No gossip.agents.json found \u2014 booting in degraded mode (dashboard + relay only). Run gossip_setup inside Claude Code to create your agent team.\n");
38280
+ config2 = {
38281
+ main_agent: { provider: "none", model: "none" },
38282
+ utility_model: { provider: "none", model: "none" },
38283
+ agents: {}
38284
+ };
38285
+ }
38149
38286
  const agentConfigs = m.configToAgentConfigs(config2);
38150
38287
  ctx.keychain = new m.Keychain();
38151
38288
  const { existsSync: pidExists, readFileSync: readPid, writeFileSync: writePid, unlinkSync: delPid } = require("fs");
38152
- const pidFile = (0, import_path51.join)(process.cwd(), ".gossip", "relay.pid");
38289
+ const pidFile = (0, import_path52.join)(process.cwd(), ".gossip", "relay.pid");
38153
38290
  if (pidExists(pidFile)) {
38154
38291
  const oldPid = parseInt(readPid(pidFile, "utf-8").trim(), 10);
38155
38292
  if (!isNaN(oldPid) && oldPid !== process.pid) {
@@ -38162,8 +38299,10 @@ async function doBoot() {
38162
38299
  }
38163
38300
  }
38164
38301
  const relayApiKey = (0, import_crypto17.randomBytes)(32).toString("hex");
38302
+ const envPort = process.env.GOSSIPCAT_PORT ? parseInt(process.env.GOSSIPCAT_PORT, 10) : NaN;
38303
+ const relayPort = Number.isFinite(envPort) && envPort >= 0 && envPort <= 65535 ? envPort : 0;
38165
38304
  ctx.relay = new m.RelayServer({
38166
- port: 24420,
38305
+ port: relayPort,
38167
38306
  apiKey: relayApiKey,
38168
38307
  dashboard: {
38169
38308
  projectRoot: process.cwd(),
@@ -38237,10 +38376,10 @@ async function doBoot() {
38237
38376
  }
38238
38377
  const key = await ctx.keychain.getKey(ac.provider);
38239
38378
  const llm = m.createProvider(ac.provider, ac.model, key ?? void 0, void 0, ac.base_url);
38240
- const { existsSync: existsSync41, readFileSync: readFileSync40 } = require("fs");
38379
+ const { existsSync: existsSync43, readFileSync: readFileSync40 } = require("fs");
38241
38380
  const { join: join48 } = require("path");
38242
38381
  const instructionsPath = join48(process.cwd(), ".gossip", "agents", ac.id, "instructions.md");
38243
- const baseInstructions = existsSync41(instructionsPath) ? readFileSync40(instructionsPath, "utf-8") : "";
38382
+ const baseInstructions = existsSync43(instructionsPath) ? readFileSync40(instructionsPath, "utf-8") : "";
38244
38383
  const identity = identityRegistry.get(ac.id);
38245
38384
  const identityBlock = identity ? m.formatIdentityBlock(identity) + "\n" : "";
38246
38385
  const instructions = (identityBlock + baseInstructions).trim() || void 0;
@@ -38298,8 +38437,13 @@ async function doBoot() {
38298
38437
  if (!mainKey) {
38299
38438
  mainProvider = "none";
38300
38439
  config2.main_agent.provider = "none";
38301
- process.stderr.write(`[gossipcat] \u274C No API keys available \u2014 orchestrator LLM disabled, features degrade to profile-based
38440
+ if (env.host === "claude-code") {
38441
+ process.stderr.write(`[gossipcat] \u2705 Native Claude Code orchestration enabled (no API LLM needed \u2014 host classifies via natural language)
38442
+ `);
38443
+ } else {
38444
+ process.stderr.write(`[gossipcat] \u274C No API keys available \u2014 orchestrator LLM disabled, features degrade to profile-based
38302
38445
  `);
38446
+ }
38303
38447
  }
38304
38448
  }
38305
38449
  ctx.mainProvider = mainProvider;
@@ -38572,7 +38716,7 @@ ctx.getModules = getModules;
38572
38716
  var server = new import_mcp.McpServer(
38573
38717
  {
38574
38718
  name: "gossipcat",
38575
- version: "0.1.0"
38719
+ version: getGossipcatVersion()
38576
38720
  },
38577
38721
  {
38578
38722
  instructions: "gossipcat \u2014 multi-agent orchestration. ALWAYS call gossip_status() first when starting work in this project. The gossip_status response loads the orchestrator role, dispatch rules, consensus workflow, native agent relay rule, sandbox enforcement, and other operating rules from .gossip/rules.md. These rules are not in this instruction text \u2014 they live in the gossip_status output to keep the instruction surface small and to allow per-project customization."
@@ -38806,7 +38950,7 @@ server.tool(
38806
38950
  }
38807
38951
  try {
38808
38952
  const { readFileSync: readFileSync40 } = await import("fs");
38809
- const quotaPath = (0, import_path51.join)(process.cwd(), ".gossip", "quota-state.json");
38953
+ const quotaPath = (0, import_path52.join)(process.cwd(), ".gossip", "quota-state.json");
38810
38954
  const quotaRaw = readFileSync40(quotaPath, "utf8");
38811
38955
  const quotaState = JSON.parse(quotaRaw);
38812
38956
  for (const [provider, state] of Object.entries(quotaState)) {
@@ -38822,15 +38966,15 @@ server.tool(
38822
38966
  }
38823
38967
  try {
38824
38968
  const { readFileSync: readFileSync40, readdirSync: readdirSync13, statSync: statSync9 } = await import("fs");
38825
- const reportsDir = (0, import_path51.join)(process.cwd(), ".gossip", "consensus-reports");
38826
- const perfPath = (0, import_path51.join)(process.cwd(), ".gossip", "agent-performance.jsonl");
38969
+ const reportsDir = (0, import_path52.join)(process.cwd(), ".gossip", "consensus-reports");
38970
+ const perfPath = (0, import_path52.join)(process.cwd(), ".gossip", "agent-performance.jsonl");
38827
38971
  const WINDOW_MS = 24 * 60 * 60 * 1e3;
38828
38972
  const now = Date.now();
38829
38973
  const recentReports = [];
38830
38974
  try {
38831
38975
  for (const fname of readdirSync13(reportsDir)) {
38832
38976
  if (!fname.endsWith(".json")) continue;
38833
- const fpath = (0, import_path51.join)(reportsDir, fname);
38977
+ const fpath = (0, import_path52.join)(reportsDir, fname);
38834
38978
  const st = statSync9(fpath);
38835
38979
  if (now - st.mtimeMs > WINDOW_MS) continue;
38836
38980
  recentReports.push({ id: fname.replace(/\.json$/, ""), mtimeMs: st.mtimeMs });
@@ -39079,7 +39223,7 @@ server.tool(
39079
39223
  }
39080
39224
  return { content: [{ type: "text", text: results.join("\n") }] };
39081
39225
  }
39082
- const { writeFileSync: writeFileSync17, mkdirSync: mkdirSync21, existsSync: existsSync41 } = require("fs");
39226
+ const { writeFileSync: writeFileSync17, mkdirSync: mkdirSync21, existsSync: existsSync43 } = require("fs");
39083
39227
  const { join: join48 } = require("path");
39084
39228
  const root = process.cwd();
39085
39229
  const CLAUDE_MODEL_MAP2 = {
@@ -39148,7 +39292,7 @@ server.tool(
39148
39292
  continue;
39149
39293
  }
39150
39294
  const nativeFile = join48(root, ".claude", "agents", `${agent.id}.md`);
39151
- const wasNative = existingAgents[agent.id]?.native || existsSync41(nativeFile);
39295
+ const wasNative = existingAgents[agent.id]?.native || existsSync43(nativeFile);
39152
39296
  if (wasNative) {
39153
39297
  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.`);
39154
39298
  continue;
@@ -39991,7 +40135,7 @@ ${preview}` }]
39991
40135
  const { SkillGapTracker: SkillGapTracker2, parseSkillFrontmatter: parseSkillFrontmatter2, normalizeSkillName: normalizeSkillName2 } = await Promise.resolve().then(() => (init_src4(), src_exports3));
39992
40136
  const tracker = new SkillGapTracker2(process.cwd());
39993
40137
  if (skills && skills.length > 0) {
39994
- const { writeFileSync: writeFileSync17, mkdirSync: mkdirSync21, existsSync: existsSync41, readFileSync: readFileSync40 } = require("fs");
40138
+ const { writeFileSync: writeFileSync17, mkdirSync: mkdirSync21, existsSync: existsSync43, readFileSync: readFileSync40 } = require("fs");
39995
40139
  const { join: join48 } = require("path");
39996
40140
  const dir = join48(process.cwd(), ".gossip", "skills");
39997
40141
  mkdirSync21(dir, { recursive: true });
@@ -39999,7 +40143,7 @@ ${preview}` }]
39999
40143
  for (const sk of skills) {
40000
40144
  const name = normalizeSkillName2(sk.name);
40001
40145
  const filePath = join48(dir, `${name}.md`);
40002
- if (existsSync41(filePath)) {
40146
+ if (existsSync43(filePath)) {
40003
40147
  const existing = readFileSync40(filePath, "utf-8");
40004
40148
  const fm = parseSkillFrontmatter2(existing);
40005
40149
  if (fm) {
@@ -40685,14 +40829,8 @@ ${match.url}` }] };
40685
40829
  }
40686
40830
  return { content: [{ type: "text", text: `Dedup check failed (${err.message ?? "unknown error"}). Not filing to avoid duplicates. Run \`gh auth status\` and retry.` }] };
40687
40831
  }
40688
- let version2 = "unknown";
40689
- try {
40690
- const { readFileSync: readFileSync40 } = await import("fs");
40691
- const { join: join48 } = await import("path");
40692
- const pkgRaw = readFileSync40(join48(process.cwd(), "package.json"), "utf-8");
40693
- version2 = JSON.parse(pkgRaw).version ?? "unknown";
40694
- } catch {
40695
- }
40832
+ const { getGossipcatVersion: getGossipcatVersion2 } = await Promise.resolve().then(() => (init_version(), version_exports));
40833
+ const version2 = getGossipcatVersion2();
40696
40834
  let gitHead = "unknown";
40697
40835
  try {
40698
40836
  const result = await execFile4("git", ["rev-parse", "--short", "HEAD"]);
@@ -40774,10 +40912,10 @@ function startHttpMcpTransport() {
40774
40912
  }
40775
40913
  let body;
40776
40914
  if (req.method === "POST") {
40777
- const raw = await new Promise((resolve17, reject) => {
40915
+ const raw = await new Promise((resolve18, reject) => {
40778
40916
  const chunks = [];
40779
40917
  req.on("data", (c) => chunks.push(c));
40780
- req.on("end", () => resolve17(Buffer.concat(chunks).toString("utf-8")));
40918
+ req.on("end", () => resolve18(Buffer.concat(chunks).toString("utf-8")));
40781
40919
  req.on("error", reject);
40782
40920
  });
40783
40921
  try {