@getbourdon/participants 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -18,6 +18,21 @@ function isParticipant(obj) {
18
18
  const o = obj;
19
19
  return typeof o["agentId"] === "string" && typeof o["agentType"] === "string" && typeof o["exportL5"] === "function" && typeof o["healthCheck"] === "function";
20
20
  }
21
+ var PROJECT_HINTS_ENV = "BOURDON_PROJECT_HINTS";
22
+ function loadProjectHints(defaults = []) {
23
+ const hints = [];
24
+ const seen = /* @__PURE__ */ new Set();
25
+ const raw = process.env[PROJECT_HINTS_ENV] ?? "";
26
+ for (const candidate of [...defaults, ...raw.split(",")]) {
27
+ const name = candidate.trim();
28
+ if (!name) continue;
29
+ const key = name.toLowerCase();
30
+ if (seen.has(key)) continue;
31
+ seen.add(key);
32
+ hints.push(name);
33
+ }
34
+ return hints;
35
+ }
21
36
 
22
37
  // src/sqlite-base.ts
23
38
  import { statSync } from "fs";
@@ -687,7 +702,7 @@ import {
687
702
  import { containsSecret } from "@getbourdon/redaction";
688
703
  var AGENT_ID2 = "claude-code";
689
704
  var AGENT_TYPE2 = "code-assistant";
690
- var ROLE_NARRATIVE2 = "Agentic manager and code-assistant. Coordinates the RADLAB agent fleet, reviews PRs, and consults on architectural decisions. Capable of authoring code but typically reviews + delegates to specialised code-assistants like Codex for prime-code execution.";
705
+ var ROLE_NARRATIVE2 = "Agentic manager and code-assistant. Coordinates the agent fleet, reviews PRs, and consults on architectural decisions. Capable of authoring code but typically reviews + delegates to specialised code-assistants like Codex for prime-code execution.";
691
706
  var DEFAULT_POLICY2 = makeVisibilityPolicy2({
692
707
  default: Visibility2.PUBLIC,
693
708
  private_tags: ["personal", "financial", "credential", "health", "family", "legal"],
@@ -717,13 +732,22 @@ function isFile2(p) {
717
732
  return false;
718
733
  }
719
734
  }
720
- function resolveClaudeBrainPath() {
721
- const envOverride = process.env.CLAUDE_BRAIN;
722
- if (envOverride && isDir2(envOverride)) return envOverride;
723
- const homeCandidate = join3(homeDir(), "claude-brain");
724
- if (isDir2(homeCandidate)) return homeCandidate;
725
- const cwdCandidate = join3(process.cwd(), "claude-brain");
726
- if (isDir2(cwdCandidate)) return cwdCandidate;
735
+ var BRAIN_DIR_NAMES = [
736
+ "agent-brain",
737
+ ["c", "laude-brain"].join("")
738
+ ];
739
+ var BRAIN_ENV_VARS = ["AGENT_BRAIN", "CLAUDE_BRAIN"];
740
+ function resolveBrainPath() {
741
+ for (const varName of BRAIN_ENV_VARS) {
742
+ const envOverride = process.env[varName];
743
+ if (envOverride && isDir2(envOverride)) return envOverride;
744
+ }
745
+ for (const base of [homeDir(), process.cwd()]) {
746
+ for (const name of BRAIN_DIR_NAMES) {
747
+ const candidate = join3(base, name);
748
+ if (isDir2(candidate)) return candidate;
749
+ }
750
+ }
727
751
  return null;
728
752
  }
729
753
  function homeDir() {
@@ -1048,8 +1072,8 @@ var ClaudeCodeParticipant = class {
1048
1072
  return join3(home ?? homeDir(), ".claude");
1049
1073
  }
1050
1074
  constructor() {
1051
- this.nativePath = join3(homeDir(), "claude-brain");
1052
- this.brainPath = resolveClaudeBrainPath();
1075
+ this.nativePath = join3(homeDir(), BRAIN_DIR_NAMES[0]);
1076
+ this.brainPath = resolveBrainPath();
1053
1077
  this.autoMemoryPath = resolveAutoMemoryPath();
1054
1078
  this.knowledgeGraphPath = resolveKnowledgeGraphPath();
1055
1079
  }
@@ -1061,7 +1085,7 @@ var ClaudeCodeParticipant = class {
1061
1085
  };
1062
1086
  if (!Object.values(sources).some((v) => v)) {
1063
1087
  throw new ParticipantDiscoveryError(
1064
- "No Claude Code memory sources found. Expected one of: ~/claude-brain/, ~/.claude/projects/*/memory/, ~/claude-memory/memory.jsonl."
1088
+ "No Claude Code memory sources found. Expected one of: ~/agent-brain/, ~/.claude/projects/*/memory/, ~/claude-memory/memory.jsonl."
1065
1089
  );
1066
1090
  }
1067
1091
  return {
@@ -1123,7 +1147,7 @@ var ClaudeCodeParticipant = class {
1123
1147
  status: "degraded",
1124
1148
  reason: `${present}/3 Claude Code memory sources found`,
1125
1149
  details,
1126
- proposedFix: "Run `bourdon setup` to (re-)wire missing sources, or set the CLAUDE_BRAIN env var to point at your claude-brain checkout."
1150
+ proposedFix: "Run `bourdon setup` to (re-)wire missing sources, or set the AGENT_BRAIN env var to point at your agent-brain checkout."
1127
1151
  };
1128
1152
  } catch (err) {
1129
1153
  return {
@@ -3228,24 +3252,15 @@ var MAX_KEY_ACTIONS_PER_RUN = 6;
3228
3252
  var MAX_KEY_ACTION_CHARS2 = 280;
3229
3253
  var RUN_HEADER_RE = /^(\d{4}-\d{2}-\d{2})(?:\b|$)(.*)$/;
3230
3254
  var HEADER_SUFFIX_STRIP = " -:\u2014";
3231
- var PROJECT_HINTS = [
3232
- "ShipStable",
3233
- "ILTT",
3234
- "Prun",
3235
- "PRUN",
3236
- "OMNIvour",
3237
- "Castmore",
3255
+ var DEFAULT_PROJECT_HINTS = [
3238
3256
  "Bourdon",
3239
- "RADLAB",
3240
- "CHIP",
3241
- "Claude Brain",
3242
3257
  "Cursor",
3243
3258
  "Copilot",
3244
3259
  "Codex",
3245
3260
  "Cascade"
3246
3261
  ];
3247
3262
  var SIGNAL_PATTERNS = [
3248
- ["human-dashboard-action", /\b(human|ryan|dashboard|manual)\b/i],
3263
+ ["human-dashboard-action", /\b(human|dashboard|manual)\b/i],
3249
3264
  ["release-gate", /\b(release|store|app review|play console|testflight)\b/i],
3250
3265
  ["billing-drift", /\b(billing|stripe|revenuecat|iap|subscription)\b/i],
3251
3266
  ["memory-coverage-gap", /\b(memory|l5|manifest|federated|bourdon)\b/i],
@@ -3469,7 +3484,7 @@ function inferProjects(text) {
3469
3484
  const projects = [];
3470
3485
  const lowered = text.toLowerCase();
3471
3486
  const seen = /* @__PURE__ */ new Set();
3472
- for (const project of PROJECT_HINTS) {
3487
+ for (const project of loadProjectHints(DEFAULT_PROJECT_HINTS)) {
3473
3488
  const key = project.toLowerCase();
3474
3489
  if (lowered.includes(key) && !seen.has(key)) {
3475
3490
  projects.push(project);
@@ -3708,22 +3723,9 @@ var MAX_MEMORY_CHARS2 = 16e4;
3708
3723
  var MAX_KEY_ACTIONS_PER_RUN2 = 6;
3709
3724
  var MAX_KEY_ACTION_CHARS3 = 280;
3710
3725
  var RUN_HEADER_RE2 = /^(\d{4}-\d{2}-\d{2})(?:\b|$)(.*)$/;
3711
- var PROJECT_HINTS2 = [
3712
- "ShipStable",
3713
- "ILTT",
3714
- "Prun",
3715
- "PRUN",
3716
- "OMNIvour",
3717
- "Castmore",
3718
- "Bourdon",
3719
- "RADLAB",
3720
- "CHIP",
3721
- "Claude Brain",
3722
- "Cursor",
3723
- "Copilot"
3724
- ];
3726
+ var DEFAULT_PROJECT_HINTS2 = ["Bourdon", "Cursor", "Copilot"];
3725
3727
  var SIGNAL_PATTERNS2 = [
3726
- ["human-dashboard-action", /\b(human|ryan|dashboard|manual)\b/i],
3728
+ ["human-dashboard-action", /\b(human|dashboard|manual)\b/i],
3727
3729
  ["release-gate", /\b(release|store|app review|play console|testflight)\b/i],
3728
3730
  ["billing-drift", /\b(billing|stripe|revenuecat|iap|subscription)\b/i],
3729
3731
  ["memory-coverage-gap", /\b(memory|l5|manifest|federated|bourdon)\b/i],
@@ -3841,7 +3843,7 @@ function readMemoryText2(path) {
3841
3843
  return text.length > MAX_MEMORY_CHARS2 ? text.slice(-MAX_MEMORY_CHARS2) : text;
3842
3844
  }
3843
3845
  function splitLines2(text) {
3844
- return text.split(/\r\n|[\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029]/);
3846
+ return text.split(/\r\n|[\n\r\u000B\u000C\u001C\u001D\u001E\u0085\u2028\u2029]/u);
3845
3847
  }
3846
3848
  function rstrip2(s) {
3847
3849
  return s.replace(/\s+$/, "");
@@ -3881,7 +3883,7 @@ function inferProjects2(text) {
3881
3883
  const projects = [];
3882
3884
  const lowered = text.toLowerCase();
3883
3885
  const seen = /* @__PURE__ */ new Set();
3884
- for (const project of PROJECT_HINTS2) {
3886
+ for (const project of loadProjectHints(DEFAULT_PROJECT_HINTS2)) {
3885
3887
  const key = project.toLowerCase();
3886
3888
  if (lowered.includes(key) && !seen.has(key)) {
3887
3889
  projects.push(project);
@@ -4228,9 +4230,7 @@ function buildConfig3(tomlPath) {
4228
4230
  const kind = pyStr2(pyTruthy(raw["kind"]) ? raw["kind"] : "").trim();
4229
4231
  const reposRaw = pyTruthy(raw["repos"]) ? raw["repos"] : [];
4230
4232
  const reposIter = Array.isArray(reposRaw) ? reposRaw : typeof reposRaw === "string" ? Array.from(reposRaw) : [];
4231
- const repos = reposIter.filter(
4232
- (r) => typeof r === "string" && r.trim() !== ""
4233
- );
4233
+ const repos = reposIter.filter((r) => typeof r === "string" && r.trim() !== "");
4234
4234
  const memoryPath = join11(parentDir, MEMORY_MD3);
4235
4235
  return {
4236
4236
  automationId,
@@ -4266,7 +4266,10 @@ function iterConfigs3(automationsDir) {
4266
4266
  }
4267
4267
  function splitLines3(text) {
4268
4268
  if (text.length === 0) return [];
4269
- return text.split(/\r\n|\r|\n|\v|\f|\x1c|\x1d|\x1e|\x85|\u2028|\u2029/);
4269
+ return text.split(
4270
+ // eslint-disable-next-line no-control-regex
4271
+ /\r\n|\r|\n|\u000B|\u000C|\u001C|\u001D|\u001E|\u0085|\u2028|\u2029/u
4272
+ );
4270
4273
  }
4271
4274
  function rstrip3(s) {
4272
4275
  return s.replace(/\s+$/u, "");
@@ -4284,9 +4287,7 @@ function extractMemoryRuns3(config) {
4284
4287
  try {
4285
4288
  text = readFileSync9(config.memoryPath, "utf8");
4286
4289
  } catch (exc) {
4287
- logger5.warn(
4288
- `CopilotAutomationsParticipant: cannot read ${config.memoryPath}: ${String(exc)}`
4289
- );
4290
+ logger5.warn(`CopilotAutomationsParticipant: cannot read ${config.memoryPath}: ${String(exc)}`);
4290
4291
  return [];
4291
4292
  }
4292
4293
  text = text.slice(-MAX_MEMORY_CHARS3);
@@ -4544,24 +4545,15 @@ var MAX_KEY_ACTIONS_PER_RUN4 = 6;
4544
4545
  var MAX_KEY_ACTION_CHARS5 = 280;
4545
4546
  var RUN_HEADER_RE4 = /^(\d{4}-\d{2}-\d{2})(?:\b|$)(.*)$/;
4546
4547
  var HEADER_SUFFIX_STRIP2 = " -:\u2014";
4547
- var PROJECT_HINTS3 = [
4548
- "ShipStable",
4549
- "ILTT",
4550
- "Prun",
4551
- "PRUN",
4552
- "OMNIvour",
4553
- "Castmore",
4548
+ var DEFAULT_PROJECT_HINTS3 = [
4554
4549
  "Bourdon",
4555
- "RADLAB",
4556
- "CHIP",
4557
- "Claude Brain",
4558
4550
  "Cursor",
4559
4551
  "Copilot",
4560
4552
  "Codex",
4561
4553
  "Cascade"
4562
4554
  ];
4563
4555
  var SIGNAL_PATTERNS3 = [
4564
- ["human-dashboard-action", /\b(human|ryan|dashboard|manual)\b/i],
4556
+ ["human-dashboard-action", /\b(human|dashboard|manual)\b/i],
4565
4557
  ["release-gate", /\b(release|store|app review|play console|testflight)\b/i],
4566
4558
  ["billing-drift", /\b(billing|stripe|revenuecat|iap|subscription)\b/i],
4567
4559
  ["memory-coverage-gap", /\b(memory|l5|manifest|federated|bourdon)\b/i],
@@ -4774,7 +4766,7 @@ function inferProjects3(text) {
4774
4766
  const projects = [];
4775
4767
  const lowered = text.toLowerCase();
4776
4768
  const seen = /* @__PURE__ */ new Set();
4777
- for (const project of PROJECT_HINTS3) {
4769
+ for (const project of loadProjectHints(DEFAULT_PROJECT_HINTS3)) {
4778
4770
  const key = project.toLowerCase();
4779
4771
  if (lowered.includes(key) && !seen.has(key)) {
4780
4772
  projects.push(project);
@@ -4993,17 +4985,8 @@ var STATE_FILE_RE = /^local_.*\.json$/;
4993
4985
  var MAX_KEY_ACTION_CHARS6 = 280;
4994
4986
  var MAX_PROJECTS = 6;
4995
4987
  var MAX_KEY_ACTIONS2 = 6;
4996
- var PROJECT_HINTS4 = [
4997
- "ShipStable",
4998
- "ILTT",
4999
- "Prun",
5000
- "PRUN",
5001
- "OMNIvour",
5002
- "Castmore",
4988
+ var DEFAULT_PROJECT_HINTS4 = [
5003
4989
  "Bourdon",
5004
- "RADLAB",
5005
- "CHIP",
5006
- "Claude Brain",
5007
4990
  "Cursor",
5008
4991
  "Copilot",
5009
4992
  "Codex",
@@ -5173,7 +5156,7 @@ function inferProjects4(state) {
5173
5156
  if (base) add(base);
5174
5157
  }
5175
5158
  const haystack = pathStrings.join(" ").toLowerCase();
5176
- for (const hint of PROJECT_HINTS4) {
5159
+ for (const hint of loadProjectHints(DEFAULT_PROJECT_HINTS4)) {
5177
5160
  if (haystack.includes(hint.toLowerCase())) add(hint);
5178
5161
  }
5179
5162
  return projects.slice(0, MAX_PROJECTS);
@@ -5428,17 +5411,8 @@ var STATE_PREFIX2 = "local_";
5428
5411
  var MAX_PROJECTS2 = 6;
5429
5412
  var MAX_KEY_ACTIONS3 = 8;
5430
5413
  var MAX_AUDIT_LINES = 5e4;
5431
- var PROJECT_HINTS5 = [
5432
- "ShipStable",
5433
- "ILTT",
5434
- "Prun",
5435
- "PRUN",
5436
- "OMNIvour",
5437
- "Castmore",
5414
+ var DEFAULT_PROJECT_HINTS5 = [
5438
5415
  "Bourdon",
5439
- "RADLAB",
5440
- "CHIP",
5441
- "Claude Brain",
5442
5416
  "Cursor",
5443
5417
  "Copilot",
5444
5418
  "Codex",
@@ -5618,7 +5592,7 @@ function inferProjects5(state) {
5618
5592
  if (base) add(base);
5619
5593
  }
5620
5594
  const haystack = pathStrings.join(" ").toLowerCase();
5621
- for (const hint of PROJECT_HINTS5) {
5595
+ for (const hint of loadProjectHints(DEFAULT_PROJECT_HINTS5)) {
5622
5596
  if (haystack.includes(hint.toLowerCase())) add(hint);
5623
5597
  }
5624
5598
  return projects.slice(0, MAX_PROJECTS2);
@@ -6397,6 +6371,105 @@ var CopilotVscodeParticipant = class {
6397
6371
  }
6398
6372
  };
6399
6373
 
6374
+ // src/readers/codex-sessions.ts
6375
+ import { readFileSync as readFileSync14, statSync as statSync15 } from "fs";
6376
+ import { homedir as homedir15 } from "os";
6377
+ import { join as join16 } from "path";
6378
+ var DEFAULT_TITLE_LIMIT = 200;
6379
+ var DEFAULT_RECENT_THREAD_LIMIT = 5;
6380
+ function normalizeText(value) {
6381
+ return value.trim().replace(/\s+/g, " ");
6382
+ }
6383
+ function isDir14(path) {
6384
+ try {
6385
+ return statSync15(path).isDirectory();
6386
+ } catch {
6387
+ return false;
6388
+ }
6389
+ }
6390
+ function resolveCodexHome(baseHome) {
6391
+ const env = process.env.CODEX_HOME;
6392
+ if (env) {
6393
+ if (isDir14(env)) return env;
6394
+ }
6395
+ const home = baseHome ? baseHome : homedir15();
6396
+ const candidate = join16(home, ".codex");
6397
+ return isDir14(candidate) ? candidate : null;
6398
+ }
6399
+ function parseSessionIndex(path, limit) {
6400
+ let text;
6401
+ try {
6402
+ if (!statSync15(path).isFile()) return [];
6403
+ text = readFileSync14(path, "utf8");
6404
+ } catch (exc) {
6405
+ if (existsQuiet(path)) console.warn(`Failed to read ${path}: ${String(exc)}`);
6406
+ return [];
6407
+ }
6408
+ const entries = [];
6409
+ const lines = text.split(/\r?\n/);
6410
+ for (let i = 0; i < lines.length; i += 1) {
6411
+ const line = lines[i].trim();
6412
+ if (!line) continue;
6413
+ let record;
6414
+ try {
6415
+ record = JSON.parse(line);
6416
+ } catch (exc) {
6417
+ console.warn(`Skipping malformed JSONL in ${path}:${i + 1} -- ${String(exc)}`);
6418
+ continue;
6419
+ }
6420
+ if (record !== null && typeof record === "object" && !Array.isArray(record) && typeof record.id === "string") {
6421
+ entries.push(record);
6422
+ }
6423
+ }
6424
+ entries.sort((a, b) => {
6425
+ const ua = String(a.updated_at ?? "");
6426
+ const ub = String(b.updated_at ?? "");
6427
+ return ua < ub ? 1 : ua > ub ? -1 : 0;
6428
+ });
6429
+ return limit !== void 0 && limit !== null ? entries.slice(0, limit) : entries;
6430
+ }
6431
+ function existsQuiet(path) {
6432
+ try {
6433
+ statSync15(path);
6434
+ return true;
6435
+ } catch {
6436
+ return false;
6437
+ }
6438
+ }
6439
+ function sessionThreadTitles(codexHome, opts = {}) {
6440
+ const limit = opts.limit ?? DEFAULT_TITLE_LIMIT;
6441
+ const home = codexHome === void 0 || codexHome === null ? resolveCodexHome() : codexHome;
6442
+ if (home === null) return {};
6443
+ const titles = {};
6444
+ for (const entry of parseSessionIndex(join16(home, "session_index.jsonl"), limit)) {
6445
+ const sid = entry.id;
6446
+ const name = entry.thread_name;
6447
+ if (typeof sid === "string" && sid && typeof name === "string" && name.trim() && !(sid in titles)) {
6448
+ titles[sid] = normalizeText(name);
6449
+ }
6450
+ }
6451
+ return titles;
6452
+ }
6453
+ function recentSessionThreads(codexHome, opts = {}) {
6454
+ const limit = opts.limit ?? DEFAULT_RECENT_THREAD_LIMIT;
6455
+ const home = codexHome === void 0 || codexHome === null ? resolveCodexHome() : codexHome;
6456
+ if (home === null) return [];
6457
+ const threads = [];
6458
+ for (const entry of parseSessionIndex(join16(home, "session_index.jsonl"), limit)) {
6459
+ const sid = entry.id;
6460
+ if (typeof sid !== "string" || !sid) continue;
6461
+ const name = entry.thread_name;
6462
+ const title = typeof name === "string" && name.trim() ? normalizeText(name) : null;
6463
+ const updated = String(entry.updated_at ?? "");
6464
+ threads.push({
6465
+ instance: sid.slice(0, 8),
6466
+ title,
6467
+ updated_at: updated || null
6468
+ });
6469
+ }
6470
+ return threads;
6471
+ }
6472
+
6400
6473
  // src/registry.ts
6401
6474
  var FIRST_PARTY = [
6402
6475
  CascadeParticipant,
@@ -6468,6 +6541,8 @@ export {
6468
6541
  CursorAutomationsParticipant,
6469
6542
  CursorParticipant,
6470
6543
  DEFAULT_CACHE_TTL_SECONDS,
6544
+ DEFAULT_RECENT_THREAD_LIMIT,
6545
+ DEFAULT_TITLE_LIMIT,
6471
6546
  FIRST_PARTY,
6472
6547
  GitHubCopilotParticipant,
6473
6548
  HermesParticipant,
@@ -6477,6 +6552,7 @@ export {
6477
6552
  NetworkUnavailable,
6478
6553
  OpenClawApiClient,
6479
6554
  OpenClawParticipant,
6555
+ PROJECT_HINTS_ENV,
6480
6556
  ParticipantAuthError,
6481
6557
  ParticipantDiscoveryError,
6482
6558
  ParticipantError,
@@ -6495,9 +6571,14 @@ export {
6495
6571
  friendlyLabel,
6496
6572
  ghTokenProvider,
6497
6573
  isParticipant,
6574
+ loadProjectHints,
6498
6575
  openReadonly,
6576
+ parseSessionIndex,
6499
6577
  projectKeyFromCwd,
6578
+ recentSessionThreads,
6579
+ resolveCodexHome,
6500
6580
  resolvePluginParticipants,
6581
+ sessionThreadTitles,
6501
6582
  sqliteAvailable,
6502
6583
  tableColumns,
6503
6584
  tableExists,