@sjawhar/pi-legion-envoy 5.5.10 → 5.6.0

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/envoy.js CHANGED
@@ -30517,11 +30517,8 @@ var phaseHandoffSchema = exports_external.discriminatedUnion("phase", [
30517
30517
  var AGENT_TOPIC_PREFIX = "notifications.agent.";
30518
30518
  var ROLE_TOPIC_PREFIX = "notifications.role.";
30519
30519
  var LEGION_NOTICE_TOPIC_PREFIX = "notifications.legion.";
30520
- function legionNoticeSubject(project, issue2) {
30521
- return `${LEGION_NOTICE_TOPIC_PREFIX}${project}.${issue2}`;
30522
- }
30523
30520
  function legionControllerNoticeSubject(project) {
30524
- return legionNoticeSubject(project, "controller");
30521
+ return `${LEGION_NOTICE_TOPIC_PREFIX}${project}.controller`;
30525
30522
  }
30526
30523
  var DISPATCH_TOPIC_PREFIX = "notifications.dispatch.";
30527
30524
  var DISPATCH_ISSUE_TOPIC_PREFIX = `${DISPATCH_TOPIC_PREFIX}issue.`;
@@ -34382,6 +34379,39 @@ function subscriptionRemovedTopics(raw, sessionID) {
34382
34379
  return parsedPayload.data.topics ?? [];
34383
34380
  }
34384
34381
 
34382
+ // ../envoy-client/src/nats-auth.ts
34383
+ var import_nats = __toESM(require_mod4(), 1);
34384
+ var seedKeys = import_nats.nkeys;
34385
+ function natsAuthOptions(env) {
34386
+ const { NATS_NKEY_SEED_FILE: file2, NATS_NKEY_SEED: plain } = env;
34387
+ let seed;
34388
+ let source;
34389
+ if (file2 !== undefined) {
34390
+ if (file2 === "")
34391
+ throw new Error("NATS_NKEY_SEED_FILE is set but empty");
34392
+ seed = readSecretFile("NATS_NKEY_SEED_FILE", file2);
34393
+ source = `NATS_NKEY_SEED_FILE (${file2})`;
34394
+ } else if (plain !== undefined) {
34395
+ seed = plain.trim();
34396
+ if (seed.length === 0)
34397
+ throw new Error("NATS_NKEY_SEED is set but empty");
34398
+ source = "NATS_NKEY_SEED";
34399
+ } else {
34400
+ return {};
34401
+ }
34402
+ const bytes = new TextEncoder().encode(seed);
34403
+ let publicKey;
34404
+ try {
34405
+ publicKey = seedKeys.fromSeed(bytes).getPublicKey();
34406
+ } catch (error48) {
34407
+ throw new Error(`${source} does not hold a valid nkey seed: ${messageFor(error48)}`);
34408
+ }
34409
+ if (!publicKey.startsWith("U")) {
34410
+ throw new Error(`${source} holds an nkey seed that is not a user's (public key ${publicKey})`);
34411
+ }
34412
+ return { authenticator: import_nats.nkeyAuthenticator(bytes) };
34413
+ }
34414
+
34385
34415
  // ../envoy-client/src/tool-contract.ts
34386
34416
  var DELIVERY_CONTRACT = "Delivery is at-least-once, possibly out of order across topics; use id for dedupe and at for freshness.";
34387
34417
  var TOPIC_GUIDE = "Topic guide (all are under notifications.): agent.<session_id> (subscribe: own inbox); role.<role> " + "(publish-to; holders claim via envoy_role_set). > matches one or more trailing tokens and does not " + "match the base subject. Envoy registers the concrete base when you subscribe to <subject>.>, so " + "the recommended default remains github.<owner>.<repo>.pr.<n>.>. <owner> and <repo> are one token " + "each, with every dot in the name written _ (sjawhar/.github is github.sjawhar._github; " + "acme/site.io is github.acme.site_io), and a topic spelled with the dot receives nothing. " + "Default PR subscription: " + "github.<owner>.<repo>.pr.<n>.> (it receives the quiet PR family): pr.<n> (lifecycle: " + "opened/synchronize/closed; closed carries merged, merge_commit_sha, merged_by, head_sha), " + "pr.<n>.comment, pr.<n>.review, pr.<n>.mention, pr.<n>.checks (one head-checks settlement event: " + 'passed/failed/cancelled/skipped with failing names and URLs; re-fires with superseded_settlement: "true" ' + "when new runs appear for the same head). Other GitHub: issue.<n>, issue.<n>.comment, " + "issue.<n>.mention, mention, push.branch.<name>, push.tag.<name>, workflow.<file>.<action> (only " + "runs without an associated PR); slack.<team>.<channel>.message|mention and " + "slack.<team>.<channel>.thread.<ts>.message|mention; ghostwispr.<session>.<kind>; " + "whatsapp.<phone>.<jid>.<kind>; envoy.exceptions.<original-topic>.";
@@ -34767,7 +34797,7 @@ function sourceSession(sessionID) {
34767
34797
 
34768
34798
  // extensions/envoy.ts
34769
34799
  import { logger } from "@oh-my-pi/pi-utils";
34770
- var import_nats = __toESM(require_mod4(), 1);
34800
+ var import_nats2 = __toESM(require_mod4(), 1);
34771
34801
 
34772
34802
  // src/envoy-session.ts
34773
34803
  import path2 from "path";
@@ -34999,7 +35029,7 @@ async function copySessionID(copyToClipboard2, sessionID) {
34999
35029
  }
35000
35030
 
35001
35031
  // extensions/envoy.ts
35002
- var codec2 = import_nats.StringCodec();
35032
+ var codec2 = import_nats2.StringCodec();
35003
35033
  var NATS_RETRY_INTERVAL_MS = 15000;
35004
35034
  var CAPABILITIES_WITHOUT_BTW = DELIVERY_CAPABILITIES.filter((capability) => capability !== "btw");
35005
35035
  var ROLE_CLAIM_ENTRY = "envoy-role-claim";
@@ -35204,9 +35234,10 @@ function envoyExtension(pi) {
35204
35234
  const ensureConnection = async () => {
35205
35235
  if (connection?.isClosed() === false)
35206
35236
  return connection;
35207
- connection = await import_nats.connect({
35237
+ connection = await import_nats2.connect({
35208
35238
  servers: [...defaults.natsUrls],
35209
35239
  name: `omp-${sessionID || "unknown"}`,
35240
+ ...natsAuthOptions(process.env),
35210
35241
  reconnect: true,
35211
35242
  maxReconnectAttempts: -1,
35212
35243
  reconnectTimeWait: 2000
package/dist/legion.js CHANGED
@@ -16136,13 +16136,63 @@ function messageFor(error) {
16136
16136
  return error instanceof Error ? error.message : String(error);
16137
16137
  }
16138
16138
 
16139
- // extensions/legion.ts
16139
+ // ../envoy-client/src/nats-auth.ts
16140
16140
  var import_nats = __toESM(require_mod4(), 1);
16141
+
16142
+ // ../envoy-client/src/secret-file.ts
16143
+ import { readFileSync } from "fs";
16144
+ function readSecretFile(variable, filePath) {
16145
+ let contents;
16146
+ try {
16147
+ contents = readFileSync(filePath, "utf8");
16148
+ } catch (error) {
16149
+ throw new Error(`${variable} names ${filePath}, which could not be read: ${messageFor(error)}`);
16150
+ }
16151
+ const value = contents.trim();
16152
+ if (value.length === 0)
16153
+ throw new Error(`${variable} names ${filePath}, which is empty`);
16154
+ return value;
16155
+ }
16156
+
16157
+ // ../envoy-client/src/nats-auth.ts
16158
+ var seedKeys = import_nats.nkeys;
16159
+ function natsAuthOptions(env) {
16160
+ const { NATS_NKEY_SEED_FILE: file, NATS_NKEY_SEED: plain } = env;
16161
+ let seed;
16162
+ let source;
16163
+ if (file !== undefined) {
16164
+ if (file === "")
16165
+ throw new Error("NATS_NKEY_SEED_FILE is set but empty");
16166
+ seed = readSecretFile("NATS_NKEY_SEED_FILE", file);
16167
+ source = `NATS_NKEY_SEED_FILE (${file})`;
16168
+ } else if (plain !== undefined) {
16169
+ seed = plain.trim();
16170
+ if (seed.length === 0)
16171
+ throw new Error("NATS_NKEY_SEED is set but empty");
16172
+ source = "NATS_NKEY_SEED";
16173
+ } else {
16174
+ return {};
16175
+ }
16176
+ const bytes = new TextEncoder().encode(seed);
16177
+ let publicKey;
16178
+ try {
16179
+ publicKey = seedKeys.fromSeed(bytes).getPublicKey();
16180
+ } catch (error) {
16181
+ throw new Error(`${source} does not hold a valid nkey seed: ${messageFor(error)}`);
16182
+ }
16183
+ if (!publicKey.startsWith("U")) {
16184
+ throw new Error(`${source} holds an nkey seed that is not a user's (public key ${publicKey})`);
16185
+ }
16186
+ return { authenticator: import_nats.nkeyAuthenticator(bytes) };
16187
+ }
16188
+
16189
+ // extensions/legion.ts
16190
+ var import_nats2 = __toESM(require_mod4(), 1);
16141
16191
  import { logger } from "@oh-my-pi/pi-utils";
16142
16192
  // package.json
16143
16193
  var package_default = {
16144
16194
  name: "@sjawhar/pi-legion-envoy",
16145
- version: "5.5.10",
16195
+ version: "5.6.0",
16146
16196
  type: "module",
16147
16197
  omp: {
16148
16198
  extensions: [
@@ -30590,11 +30640,8 @@ var phaseHandoffSchema = exports_external.discriminatedUnion("phase", [
30590
30640
  var AGENT_TOPIC_PREFIX = "notifications.agent.";
30591
30641
  var ROLE_TOPIC_PREFIX = "notifications.role.";
30592
30642
  var LEGION_NOTICE_TOPIC_PREFIX = "notifications.legion.";
30593
- function legionNoticeSubject(project, issue2) {
30594
- return `${LEGION_NOTICE_TOPIC_PREFIX}${project}.${issue2}`;
30595
- }
30596
30643
  function legionControllerNoticeSubject(project) {
30597
- return legionNoticeSubject(project, "controller");
30644
+ return `${LEGION_NOTICE_TOPIC_PREFIX}${project}.controller`;
30598
30645
  }
30599
30646
  var DISPATCH_TOPIC_PREFIX = "notifications.dispatch.";
30600
30647
  var DISPATCH_ISSUE_TOPIC_PREFIX = `${DISPATCH_TOPIC_PREFIX}issue.`;
@@ -30960,21 +31007,6 @@ function zodSchemaApi(zod) {
30960
31007
  }
30961
31008
  };
30962
31009
  }
30963
- // ../envoy-client/src/secret-file.ts
30964
- import { readFileSync } from "fs";
30965
- function readSecretFile(variable, filePath) {
30966
- let contents;
30967
- try {
30968
- contents = readFileSync(filePath, "utf8");
30969
- } catch (error48) {
30970
- throw new Error(`${variable} names ${filePath}, which could not be read: ${messageFor(error48)}`);
30971
- }
30972
- const value = contents.trim();
30973
- if (value.length === 0)
30974
- throw new Error(`${variable} names ${filePath}, which is empty`);
30975
- return value;
30976
- }
30977
-
30978
31010
  // src/legion/classify.ts
30979
31011
  function classifySession(env) {
30980
31012
  if (env.LEGION_CONTROLLER !== undefined && env.LEGION_TREE !== undefined) {
@@ -31852,7 +31884,6 @@ async function bootstrapGoClaim(context, state) {
31852
31884
  secret: claim.secret
31853
31885
  });
31854
31886
  await claimEnvoyRole(sessionID, claim.claimToken, context);
31855
- await subscribeLegionNotice(sessionID, legionNoticeSubject(requiredEnvironment(process.env, "LEGION_PROJECT"), claim.role === "architect" ? claim.tree : claim.issue), context);
31856
31887
  await callGoReadyWithRetry("claims/ready", () => daemon.ready(ready));
31857
31888
  onEnvoyRoleRegained(async (role, reason) => {
31858
31889
  if (role !== claim.claimToken)
@@ -32705,7 +32736,7 @@ function legionExtension(pi) {
32705
32736
  const defaults = envoyDefaultsFromEnvironment(process.env);
32706
32737
  let controlConnection;
32707
32738
  let controlSubscription;
32708
- const controlCodec = import_nats.StringCodec();
32739
+ const controlCodec = import_nats2.StringCodec();
32709
32740
  let capability;
32710
32741
  let bootstrap;
32711
32742
  const checkSubagentSession = subagentSessionCheck();
@@ -32774,9 +32805,10 @@ function legionExtension(pi) {
32774
32805
  if (defaults.natsUrls.length === 0) {
32775
32806
  throw new Error("ENVOY_NATS_URL is required for Legion control directives");
32776
32807
  }
32777
- const connection = await import_nats.connect({
32808
+ const connection = await import_nats2.connect({
32778
32809
  servers: [...defaults.natsUrls],
32779
32810
  name: `legion-control-${sessionID}`,
32811
+ ...natsAuthOptions(process.env),
32780
32812
  reconnect: true,
32781
32813
  maxReconnectAttempts: -1,
32782
32814
  reconnectTimeWait: 2000
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/pi-legion-envoy",
3
- "version": "5.5.10",
3
+ "version": "5.6.0",
4
4
  "type": "module",
5
5
  "omp": {
6
6
  "extensions": [