@cotal-ai/pi 0.28.0-hack-20260823234508 → 0.28.1

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
@@ -89,7 +89,7 @@ function configFromEnv(env = process.env) {
89
89
  if (!name)
90
90
  throw new Error("COTAL_NAME, COTAL_AGENT_FILE or COTAL_LINK is required \u2014 a Cotal session needs an explicit identity from its launcher");
91
91
  const subscribe = splitList(env.COTAL_SUBSCRIBE);
92
- const resolvedSubscribe = subscribe.length ? subscribe : def?.subscribe ?? link?.channels ?? ["general"];
92
+ const resolvedSubscribe = subscribe.length ? subscribe : def?.subscribe ?? link?.channels ?? [];
93
93
  const allowSub = splitList(env.COTAL_ALLOW_SUBSCRIBE);
94
94
  const resolvedAllowSub = allowSub.length ? allowSub : def?.allowSubscribe ?? resolvedSubscribe;
95
95
  for (const ch of resolvedSubscribe)
@@ -15963,7 +15963,7 @@ import { isConcreteChannel as isConcreteChannel3, channelInAllow as channelInAll
15963
15963
 
15964
15964
  // ../connector-core/dist/docs-bundle.generated.js
15965
15965
  var DOCS_BUNDLE = {
15966
- "version": "0.27.0",
15966
+ "version": "0.28.1",
15967
15967
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
15968
15968
  "pages": [
15969
15969
  {
@@ -13615,11 +13615,11 @@ var require_connect = __commonJS({
13615
13615
  "../../node_modules/.pnpm/@nats-io+transport-node@3.4.0/node_modules/@nats-io/transport-node/lib/connect.js"(exports) {
13616
13616
  "use strict";
13617
13617
  Object.defineProperty(exports, "__esModule", { value: true });
13618
- exports.connect = connect8;
13618
+ exports.connect = connect7;
13619
13619
  var node_transport_1 = require_node_transport();
13620
13620
  var nats_base_client_1 = require_nats_base_client();
13621
13621
  var nats_base_client_2 = require_nats_base_client();
13622
- function connect8(opts = {}) {
13622
+ function connect7(opts = {}) {
13623
13623
  if ((0, nats_base_client_2.hasWsProtocol)(opts)) {
13624
13624
  return Promise.reject(nats_base_client_2.errors.InvalidArgumentError.format(`servers`, `node client doesn't support websockets, use the 'wsconnect' function instead`));
13625
13625
  }
@@ -35856,49 +35856,33 @@ var SYS_LIMITS = { ...BASE_LIMITS, mem_storage: 0, disk_storage: 0 };
35856
35856
  var import_nkeys4 = __toESM(require_mod2(), 1);
35857
35857
 
35858
35858
  // ../../packages/core/dist/channels.js
35859
- var import_kv4 = __toESM(require_mod6(), 1);
35860
- var import_transport_node13 = __toESM(require_transport_node(), 1);
35861
- function parseDuration(s) {
35862
- const m = /^(\d+)(s|m|h|d)$/.exec(s.trim());
35863
- if (!m)
35864
- throw new Error(`invalid duration "${s}" - expected <number><s|m|h|d>, e.g. "24h"`);
35865
- const n = Number(m[1]);
35866
- const unit = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 }[m[2]];
35867
- return n * unit;
35868
- }
35869
- function effectiveReplay(cfg, defaults) {
35870
- return cfg?.replay ?? defaults?.replay ?? true;
35871
- }
35872
- function effectiveReplayWindowMs(cfg, defaults) {
35873
- const w = cfg?.replayWindow ?? defaults?.replayWindow;
35874
- return w === void 0 ? void 0 : parseDuration(w);
35875
- }
35876
- function effectiveDeliveryClass(cfg, defaults) {
35877
- return cfg?.deliveryClass ?? defaults?.deliveryClass ?? "durable";
35878
- }
35879
- async function openChannelRegistry(nc, space, opts = {}) {
35880
- const kvm = new import_kv4.Kvm(nc);
35881
- return opts.create ? kvm.create(channelBucket(space)) : kvm.open(channelBucket(space));
35882
- }
35883
- async function readChannelConfig(kv, channel) {
35884
- return decode2(kv, channel);
35885
- }
35886
- async function readChannelDefaults(kv) {
35887
- return decode2(kv, CHANNEL_DEFAULTS_KEY);
35888
- }
35889
- async function decode2(kv, key) {
35890
- const e = await kv.get(key);
35891
- if (!e || e.operation === "DEL" || e.operation === "PURGE")
35892
- return void 0;
35893
- try {
35894
- return e.json();
35895
- } catch {
35896
- return void 0;
35897
- }
35859
+ var import_kv7 = __toESM(require_mod6(), 1);
35860
+ var import_transport_node15 = __toESM(require_transport_node(), 1);
35861
+
35862
+ // ../../packages/core/dist/endpoint.js
35863
+ var import_transport_node14 = __toESM(require_transport_node(), 1);
35864
+ var import_nats_core = __toESM(require_mod3(), 1);
35865
+ import { EventEmitter } from "node:events";
35866
+ import { randomUUID } from "node:crypto";
35867
+ import { createConnection } from "node:net";
35868
+
35869
+ // ../../packages/core/dist/artifact.js
35870
+ var ARTIFACT_PART_KIND = "artifact";
35871
+ function isArtifactPart(value) {
35872
+ if (!value || typeof value !== "object")
35873
+ return false;
35874
+ const p = value;
35875
+ return p.kind === ARTIFACT_PART_KIND && typeof p.name === "string" && p.name.length > 0 && typeof p.mediaType === "string" && p.mediaType.length > 0 && typeof p.digest === "string" && isContractDigest(p.digest) && typeof p.size === "number" && Number.isSafeInteger(p.size) && p.size >= 0;
35898
35876
  }
35899
35877
 
35878
+ // ../../packages/core/dist/endpoint.js
35879
+ var import_jetstream13 = __toESM(require_mod4(), 1);
35880
+ var import_jetstream14 = __toESM(require_mod4(), 1);
35881
+ var import_kv6 = __toESM(require_mod6(), 1);
35882
+ var import_internal2 = __toESM(require_internal_mod3(), 1);
35883
+
35900
35884
  // ../../packages/core/dist/members.js
35901
- var import_kv5 = __toESM(require_mod6(), 1);
35885
+ var import_kv4 = __toESM(require_mod6(), 1);
35902
35886
  var StaleMembershipWrite = class extends Error {
35903
35887
  constructor(channel, owner, attempted, current) {
35904
35888
  super(`stale membership write for ${channel}/${owner}: generation ${attempted} < current ${current}`);
@@ -35906,7 +35890,7 @@ var StaleMembershipWrite = class extends Error {
35906
35890
  }
35907
35891
  };
35908
35892
  async function openMembersRegistry(nc, space, opts = {}) {
35909
- const kvm = new import_kv5.Kvm(nc);
35893
+ const kvm = new import_kv4.Kvm(nc);
35910
35894
  return opts.create ? kvm.create(membersBucket(space)) : kvm.open(membersBucket(space));
35911
35895
  }
35912
35896
  async function readMember(kv, channel, owner, lifecycleUid) {
@@ -36006,312 +35990,14 @@ function durableEligible(rec, seq) {
36006
35990
  return true;
36007
35991
  }
36008
35992
 
36009
- // ../../packages/core/dist/membership-feed.js
36010
- var import_transport_node14 = __toESM(require_transport_node(), 1);
36011
- var import_kv6 = __toESM(require_mod6(), 1);
36012
-
36013
- // ../../packages/core/dist/evict.js
36014
- var import_transport_node15 = __toESM(require_transport_node(), 1);
36015
-
36016
35993
  // ../../packages/core/dist/lease.js
36017
- var import_kv7 = __toESM(require_mod6(), 1);
36018
- var import_transport_node16 = __toESM(require_transport_node(), 1);
35994
+ var import_kv5 = __toESM(require_mod6(), 1);
35995
+ var import_transport_node13 = __toESM(require_transport_node(), 1);
36019
35996
  async function openDeliveryRegistry(nc, space) {
36020
- return new import_kv7.Kvm(nc).open(deliveryBucket(space));
36021
- }
36022
-
36023
- // ../../packages/core/dist/agent-file.js
36024
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
36025
- var import_yaml = __toESM(require_dist(), 1);
36026
- function parseFrontmatter(src, path) {
36027
- let doc;
36028
- try {
36029
- doc = (0, import_yaml.parse)(src);
36030
- } catch (e) {
36031
- throw new Error(`agent file ${path}: invalid YAML frontmatter; ${e.message}`);
36032
- }
36033
- if (doc === null || doc === void 0)
36034
- return {};
36035
- if (typeof doc !== "object" || Array.isArray(doc))
36036
- throw new Error(`agent file ${path}: frontmatter must be a YAML mapping (key: value pairs)`);
36037
- return doc;
36038
- }
36039
- function loadAgentFile(path) {
36040
- const src = readFileSync(path, "utf8");
36041
- const m = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(src);
36042
- if (!m)
36043
- throw new Error(`agent file ${path}: missing "---" frontmatter block`);
36044
- const fm = parseFrontmatter(m[1], path);
36045
- const persona = m[2].trim();
36046
- const str2 = (k) => {
36047
- const v = fm[k];
36048
- if (v === void 0 || v === null)
36049
- return void 0;
36050
- if (typeof v === "object")
36051
- throw new Error(`agent file ${path}: "${k}" must be a scalar`);
36052
- return String(v);
36053
- };
36054
- const list = (k) => {
36055
- const v = fm[k];
36056
- if (v === void 0 || v === null)
36057
- return void 0;
36058
- return (Array.isArray(v) ? v : [v]).map((x) => {
36059
- if (x === null || typeof x === "object")
36060
- throw new Error(`agent file ${path}: "${k}" list items must be scalars`);
36061
- return String(x);
36062
- });
36063
- };
36064
- const name = str2("name");
36065
- if (!name)
36066
- throw new Error(`agent file ${path}: "name" is required`);
36067
- assertValidName(name);
36068
- const kind = str2("kind");
36069
- if (kind && kind !== "agent" && kind !== "endpoint")
36070
- throw new Error(`agent file ${path}: "kind" must be "agent" or "endpoint"`);
36071
- for (const old of ["channels", "publish"])
36072
- if (old in fm)
36073
- throw new Error(`agent file ${path}: "${old}" was renamed - use "subscribe"/"allowSubscribe" (read) and "allowPublish" (post)`);
36074
- const subscribe = list("subscribe");
36075
- const allowSubscribe = list("allowSubscribe");
36076
- const allowPublish = list("allowPublish");
36077
- const quiet = list("quiet");
36078
- const muted = list("muted");
36079
- for (const ch of [...subscribe ?? [], ...allowSubscribe ?? [], ...allowPublish ?? []])
36080
- try {
36081
- assertValidChannel(ch);
36082
- } catch (e) {
36083
- throw new Error(`agent file ${path}: ${e.message}`);
36084
- }
36085
- const effSubscribe = subscribe?.length ? subscribe : ["general"];
36086
- const effAllow = allowSubscribe?.length ? allowSubscribe : effSubscribe;
36087
- for (const ch of effSubscribe)
36088
- if (!channelInAllow(effAllow, ch))
36089
- throw new Error(`agent file ${path}: subscribe channel "${ch}" is not within allowSubscribe [${effAllow.join(", ")}]`);
36090
- const both = (quiet ?? []).filter((c) => (muted ?? []).includes(c));
36091
- if (both.length)
36092
- throw new Error(`agent file ${path}: channel(s) [${both.join(", ")}] are in both quiet and muted - pick one`);
36093
- for (const [field, chans] of [["quiet", quiet], ["muted", muted]])
36094
- for (const ch of chans ?? []) {
36095
- try {
36096
- assertValidChannel(ch);
36097
- } catch (e) {
36098
- throw new Error(`agent file ${path}: ${e.message}`);
36099
- }
36100
- if (!isConcreteChannel(ch))
36101
- throw new Error(`agent file ${path}: ${field} channel "${ch}" must be a concrete channel (no wildcard)`);
36102
- if (!channelInAllow(effAllow, ch))
36103
- throw new Error(`agent file ${path}: ${field} channel "${ch}" is not within your read ACL / allowSubscribe [${effAllow.join(", ")}]`);
36104
- }
36105
- const launchOptionsRaw = fm["launchOptions"];
36106
- let launchOptions;
36107
- if (launchOptionsRaw !== void 0 && launchOptionsRaw !== null) {
36108
- if (typeof launchOptionsRaw !== "object" || Array.isArray(launchOptionsRaw))
36109
- throw new Error(`agent file ${path}: "launchOptions" must be a mapping of key: value pairs`);
36110
- launchOptions = launchOptionsRaw;
36111
- }
36112
- const known = /* @__PURE__ */ new Set(["name", "role", "kind", "description", "tags", "subscribe", "allowSubscribe", "allowPublish", "quiet", "muted", "model", "variant", "launchOptions", "capabilities", "owner"]);
36113
- const meta3 = {};
36114
- for (const [k, v] of Object.entries(fm))
36115
- if (!known.has(k) && v !== null && typeof v !== "object")
36116
- meta3[k] = String(v);
36117
- return {
36118
- name,
36119
- role: str2("role"),
36120
- kind,
36121
- description: str2("description"),
36122
- tags: list("tags"),
36123
- subscribe,
36124
- allowSubscribe,
36125
- allowPublish,
36126
- quiet,
36127
- muted,
36128
- model: str2("model"),
36129
- variant: str2("variant"),
36130
- launchOptions,
36131
- capabilities: list("capabilities"),
36132
- owner: str2("owner"),
36133
- meta: Object.keys(meta3).length ? meta3 : void 0,
36134
- persona: persona || void 0
36135
- };
36136
- }
36137
-
36138
- // ../../packages/core/dist/secret-fs.js
36139
- import { chmodSync, mkdirSync as mkdirSync2, renameSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
36140
- import { execFileSync } from "node:child_process";
36141
- import { join } from "node:path";
36142
- var isWin = process.platform === "win32";
36143
- function sys32(exe) {
36144
- const root = process.env.SystemRoot || process.env.windir || "C:\\Windows";
36145
- return join(root, "System32", exe);
36146
- }
36147
- var cachedSid;
36148
- function ownerSid() {
36149
- if (cachedSid)
36150
- return cachedSid;
36151
- const out = execFileSync(sys32("whoami.exe"), ["/user", "/fo", "csv", "/nh"], { encoding: "utf8" });
36152
- const sid = out.trim().split(",").pop()?.replace(/^"|"$/g, "").trim();
36153
- if (!sid || !/^S-1-/.test(sid))
36154
- throw new Error(`could not determine the current user's SID from \`whoami\` (got: ${out.trim()})`);
36155
- cachedSid = sid;
36156
- return sid;
36157
- }
36158
- var BROAD_SIDS = ["S-1-1-0", "S-1-5-11", "S-1-5-32-545"];
36159
- function hardenPrivate(path, kind) {
36160
- if (!isWin) {
36161
- chmodSync(path, kind === "dir" ? 448 : 384);
36162
- return;
36163
- }
36164
- const perm = kind === "dir" ? "(OI)(CI)(F)" : "(F)";
36165
- const removeBroad = BROAD_SIDS.flatMap((sid) => ["/remove:g", `*${sid}`]);
36166
- const grant = (sid) => ["/grant:r", `*${sid}:${perm}`];
36167
- try {
36168
- execFileSync(sys32("icacls.exe"), [
36169
- path,
36170
- "/inheritance:r",
36171
- ...removeBroad,
36172
- ...grant(ownerSid()),
36173
- ...grant("S-1-5-18"),
36174
- ...grant("S-1-5-32-544")
36175
- ], { stdio: ["ignore", "ignore", "pipe"] });
36176
- } catch (e) {
36177
- throw new Error(`failed to harden ${kind} "${path}" to private via icacls: ${e.message.trim()}. Cotal will not leave a secret with a permissive ACL - ensure the path is on an NTFS volume and %SystemRoot%\\System32\\icacls.exe is available.`);
36178
- }
36179
- }
36180
- function writeSecretFile(path, data) {
36181
- writeFileSync2(path, data, { mode: 384 });
36182
- if (!isWin)
36183
- return;
36184
- try {
36185
- hardenPrivate(path, "file");
36186
- } catch (e) {
36187
- try {
36188
- unlinkSync(path);
36189
- } catch {
36190
- }
36191
- throw e;
36192
- }
36193
- }
36194
- function writeSecretFileAtomic(path, data) {
36195
- const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
36196
- try {
36197
- writeSecretFile(tmp, data);
36198
- renameSync(tmp, path);
36199
- } catch (e) {
36200
- try {
36201
- unlinkSync(tmp);
36202
- } catch {
36203
- }
36204
- throw e;
36205
- }
36206
- }
36207
- function mkSecretDir(path) {
36208
- mkdirSync2(path, { recursive: true, mode: 448 });
36209
- hardenPrivate(path, "dir");
36210
- }
36211
-
36212
- // ../../packages/core/dist/launch-material.js
36213
- import { mkdtempSync, readFileSync as readFileSync2, realpathSync, rmSync, rmdirSync, statSync } from "node:fs";
36214
- import { tmpdir } from "node:os";
36215
- import { basename, dirname, join as join2, resolve } from "node:path";
36216
- var DIR_PREFIX = "cotal-launch-";
36217
- var MATERIAL_FILE = "material.json";
36218
- var LAUNCH_MATERIAL_ENV = "COTAL_LAUNCH_MATERIAL";
36219
- function readLaunchMaterial(path) {
36220
- let raw;
36221
- try {
36222
- if (process.platform !== "win32") {
36223
- const mode = statSync(path).mode & 511;
36224
- if (mode & 63)
36225
- throw new Error(`is readable beyond its owner (mode ${mode.toString(8)}) - refusing to read connection material out of a file other local users can open`);
36226
- }
36227
- raw = readFileSync2(path, "utf8");
36228
- } catch (e) {
36229
- throw new Error(`launch material: cannot read ${path} (${e instanceof Error ? e.message : String(e)})`);
36230
- }
36231
- let parsed;
36232
- try {
36233
- parsed = JSON.parse(raw);
36234
- } catch {
36235
- throw new Error(`launch material: ${path} is not valid JSON`);
36236
- }
36237
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
36238
- throw new Error(`launch material: ${path} must contain a JSON object`);
36239
- return validate(parsed, path);
36240
- }
36241
- function validate(raw, path) {
36242
- const material = {};
36243
- const str2 = (key) => {
36244
- const v = raw[key];
36245
- if (v === void 0)
36246
- return;
36247
- if (typeof v !== "string" || !v.trim())
36248
- throw new Error(`launch material: ${path} has a ${key} that is not a non-empty string`);
36249
- material[key] = v;
36250
- };
36251
- str2("servers");
36252
- str2("creds");
36253
- str2("token");
36254
- str2("controlToken");
36255
- if (raw.userAuth !== void 0) {
36256
- const u = raw.userAuth;
36257
- if (typeof u !== "object" || u === null || Array.isArray(u))
36258
- throw new Error(`launch material: ${path} has a userAuth that is not an object`);
36259
- const { owner, actor, sentinelCredsPath, bearerCmd } = u;
36260
- const named = { owner, actor, sentinelCredsPath };
36261
- for (const [k, v] of Object.entries(named))
36262
- if (typeof v !== "string" || !v.trim())
36263
- throw new Error(`launch material: ${path} has a userAuth.${k} that is not a non-empty string`);
36264
- if (!Array.isArray(bearerCmd) || bearerCmd.length === 0 || !bearerCmd.every((a) => typeof a === "string" && a))
36265
- throw new Error(`launch material: ${path} has a userAuth.bearerCmd that is not a non-empty array of strings`);
36266
- material.userAuth = {
36267
- owner,
36268
- actor,
36269
- sentinelCredsPath,
36270
- bearerCmd
36271
- };
36272
- }
36273
- if (Object.keys(material).length === 0)
36274
- throw new Error(`launch material: ${path} carries nothing this reader recognises. A launch that references material and supplies none is a broken launcher, not an open-mode launch, so it is refused rather than defaulted.`);
36275
- return material;
36276
- }
36277
- function discardLaunchMaterial(path) {
36278
- const file2 = resolve(path);
36279
- try {
36280
- rmSync(file2, { force: true });
36281
- } catch {
36282
- }
36283
- const dir = dirname(file2);
36284
- if (basename(file2) !== MATERIAL_FILE || !basename(dir).startsWith(DIR_PREFIX))
36285
- return;
36286
- try {
36287
- if (realpathSync(dirname(dir)) !== realpathSync(tmpdir()))
36288
- return;
36289
- rmdirSync(dir);
36290
- } catch {
36291
- }
36292
- }
36293
-
36294
- // ../../packages/core/dist/endpoint.js
36295
- var import_transport_node17 = __toESM(require_transport_node(), 1);
36296
- var import_nats_core = __toESM(require_mod3(), 1);
36297
- import { EventEmitter } from "node:events";
36298
- import { randomUUID } from "node:crypto";
36299
- import { createConnection } from "node:net";
36300
-
36301
- // ../../packages/core/dist/artifact.js
36302
- var ARTIFACT_PART_KIND = "artifact";
36303
- function isArtifactPart(value) {
36304
- if (!value || typeof value !== "object")
36305
- return false;
36306
- const p = value;
36307
- return p.kind === ARTIFACT_PART_KIND && typeof p.name === "string" && p.name.length > 0 && typeof p.mediaType === "string" && p.mediaType.length > 0 && typeof p.digest === "string" && isContractDigest(p.digest) && typeof p.size === "number" && Number.isSafeInteger(p.size) && p.size >= 0;
35997
+ return new import_kv5.Kvm(nc).open(deliveryBucket(space));
36308
35998
  }
36309
35999
 
36310
36000
  // ../../packages/core/dist/endpoint.js
36311
- var import_jetstream13 = __toESM(require_mod4(), 1);
36312
- var import_jetstream14 = __toESM(require_mod4(), 1);
36313
- var import_kv8 = __toESM(require_mod6(), 1);
36314
- var import_internal2 = __toESM(require_internal_mod3(), 1);
36315
36001
  var DEFAULT_SERVER = "nats://127.0.0.1:4222";
36316
36002
  var PLANE3_FRAME_HEADER = "Cotal-Delivery-Frame";
36317
36003
  var READER_MAX_REDELIVERIES = 10;
@@ -36562,7 +36248,7 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
36562
36248
  this.user = opts.user;
36563
36249
  this.pass = opts.pass;
36564
36250
  this.tls = opts.tls ?? false;
36565
- this.channels = opts.channels ?? ["general"];
36251
+ this.channels = opts.channels ?? [];
36566
36252
  this.heartbeatMs = opts.heartbeatMs ?? 2e3;
36567
36253
  this.ttlMs = opts.ttlMs ?? 6e3;
36568
36254
  this.doRegister = opts.registerPresence ?? true;
@@ -36825,7 +36511,7 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
36825
36511
  this.watchStatus();
36826
36512
  this.js = (0, import_jetstream13.jetstream)(this.nc);
36827
36513
  if (this.doWatch || this.doRegister) {
36828
- const kvm = new import_kv8.Kvm(this.nc);
36514
+ const kvm = new import_kv6.Kvm(this.nc);
36829
36515
  this.kv = this.authed ? await kvm.open(presenceBucket(this.space)) : await kvm.create(presenceBucket(this.space), { ttl: this.ttlMs });
36830
36516
  }
36831
36517
  if (this.doWatch) {
@@ -37089,7 +36775,9 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
37089
36775
  // ---- messaging -----------------------------------------------------------
37090
36776
  /** Multicast: broadcast to everyone on a channel. */
37091
36777
  async multicast(text, opts) {
37092
- const channel = opts?.channel ?? this.channels.find(isConcreteChannel) ?? "general";
36778
+ const channel = opts?.channel ?? this.channels.find(isConcreteChannel);
36779
+ if (!channel)
36780
+ throw new Error("send() needs a channel: this endpoint is on no concrete channel, so there is no default to fall back to - pass opts.channel");
37093
36781
  if (!isConcreteChannel(channel))
37094
36782
  throw new Error(`cannot publish to wildcard channel "${channel}" - pick a concrete sub-channel`);
37095
36783
  const msg = {
@@ -37205,7 +36893,7 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
37205
36893
  throw new Error(`expectedLastSubjectSeq must be a non-negative safe integer, got ${JSON.stringify(opts.expectedLastSubjectSeq)}`);
37206
36894
  if (!Array.isArray(opts.parts) || opts.parts.length === 0)
37207
36895
  throw new Error("encodedSize requires at least one part");
37208
- const mh = (0, import_transport_node17.headers)();
36896
+ const mh = (0, import_transport_node14.headers)();
37209
36897
  mh.set("Nats-Msg-Id", opts.id);
37210
36898
  mh.set("Nats-Expected-Last-Subject-Sequence", `${opts.expectedLastSubjectSeq}`);
37211
36899
  const headerBytes = mh.encode().length;
@@ -37711,7 +37399,7 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
37711
37399
  async membershipFeedRegistry() {
37712
37400
  if (!this.nc)
37713
37401
  throw new Error("endpoint not started");
37714
- this.membershipFeedKv ??= await new import_kv8.Kvm(this.nc).open(membershipBucket(this.space));
37402
+ this.membershipFeedKv ??= await new import_kv6.Kvm(this.nc).open(membershipBucket(this.space));
37715
37403
  return this.membershipFeedKv;
37716
37404
  }
37717
37405
  /**
@@ -38077,7 +37765,7 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
38077
37765
  for await (const s of this.nc.status()) {
38078
37766
  if (s.type !== "error")
38079
37767
  continue;
38080
- if (s.error instanceof import_transport_node17.PermissionViolationError && this.confirmingChatSubs.has(s.error.subject))
37768
+ if (s.error instanceof import_transport_node14.PermissionViolationError && this.confirmingChatSubs.has(s.error.subject))
38081
37769
  continue;
38082
37770
  this.emit("error", describeStatusError(s.error));
38083
37771
  }
@@ -38300,7 +37988,7 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
38300
37988
  throw new Error("endpoint not started");
38301
37989
  if (this.managerLeaseKv)
38302
37990
  return this.managerLeaseKv;
38303
- const kvm = new import_kv8.Kvm((0, import_jetstream13.jetstream)(this.nc, { timeout: MANAGER_LEASE_ATTEMPT_MS }));
37991
+ const kvm = new import_kv6.Kvm((0, import_jetstream13.jetstream)(this.nc, { timeout: MANAGER_LEASE_ATTEMPT_MS }));
38304
37992
  if (this.authed) {
38305
37993
  this.managerLeaseKv = await kvm.open(managerBucket(this.space));
38306
37994
  } else {
@@ -38530,7 +38218,7 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
38530
38218
  filter_subject: subject,
38531
38219
  ack_policy: import_jetstream13.AckPolicy.None,
38532
38220
  mem_storage: true,
38533
- inactive_threshold: (0, import_transport_node17.nanos)(3e4),
38221
+ inactive_threshold: (0, import_transport_node14.nanos)(3e4),
38534
38222
  deliver_policy: import_jetstream13.DeliverPolicy.StartSequence,
38535
38223
  opt_start_seq: fromSeqExcl + 1
38536
38224
  });
@@ -38992,7 +38680,7 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
38992
38680
  channel: entry.channel,
38993
38681
  msg: authenticatedChannelMessage(entry.msg, entry.channel)
38994
38682
  };
38995
- const frameHeaders = (0, import_transport_node17.headers)();
38683
+ const frameHeaders = (0, import_transport_node14.headers)();
38996
38684
  frameHeaders.set(PLANE3_FRAME_HEADER, "1");
38997
38685
  await this.js.publish(dlvSubject(this.space, pr.owner, pr.actor, pr.lifecycleUid), JSON.stringify(frame), {
38998
38686
  msgID: `${entry.msg.id}:${owner}:${pr.lifecycleUid}:${entry.generation}`,
@@ -39122,7 +38810,7 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
39122
38810
  * distinct from a responder that errored. nats.js surfaces it as NoRespondersError, or a RequestError
39123
38811
  * whose `isNoResponders()` is true. */
39124
38812
  isNoResponders(e) {
39125
- return e instanceof import_transport_node17.NoRespondersError || e instanceof import_transport_node17.RequestError && e.isNoResponders();
38813
+ return e instanceof import_transport_node14.NoRespondersError || e instanceof import_transport_node14.RequestError && e.isNoResponders();
39126
38814
  }
39127
38815
  /** Agent-side: this session's CURRENT durable memberships (channel + join generation) from the
39128
38816
  * manager — the agent holds no read on the privileged members KV. `undefined` ⇒ NO control responder
@@ -39465,7 +39153,7 @@ var CotalEndpoint = class _CotalEndpoint extends EventEmitter {
39465
39153
  filter_subject: subject,
39466
39154
  ack_policy: import_jetstream13.AckPolicy.None,
39467
39155
  mem_storage: true,
39468
- inactive_threshold: (0, import_transport_node17.nanos)(3e4),
39156
+ inactive_threshold: (0, import_transport_node14.nanos)(3e4),
39469
39157
  ..."time" in start ? { deliver_policy: import_jetstream13.DeliverPolicy.StartTime, opt_start_time: start.time.toISOString() } : { deliver_policy: import_jetstream13.DeliverPolicy.StartSequence, opt_start_seq: start.seq }
39470
39158
  });
39471
39159
  try {
@@ -39826,7 +39514,7 @@ function authOpts(a) {
39826
39514
  if (!a.sentinelCreds)
39827
39515
  throw new Error("user-mode bearer requires sentinelCreds");
39828
39516
  return {
39829
- authenticator: [(0, import_transport_node17.credsAuthenticator)(new TextEncoder().encode(a.sentinelCreds)), (0, import_transport_node17.tokenAuthenticator)(a.bearer)],
39517
+ authenticator: [(0, import_transport_node14.credsAuthenticator)(new TextEncoder().encode(a.sentinelCreds)), (0, import_transport_node14.tokenAuthenticator)(a.bearer)],
39830
39518
  tls
39831
39519
  };
39832
39520
  }
@@ -39834,7 +39522,7 @@ function authOpts(a) {
39834
39522
  if (a.token || a.user || a.pass)
39835
39523
  throw new Error("creds are mutually exclusive with token/user/pass auth");
39836
39524
  const creds = a.creds;
39837
- const authenticator = typeof creds === "function" ? (nonce3) => (0, import_transport_node17.credsAuthenticator)(new TextEncoder().encode(creds()))(nonce3) : (0, import_transport_node17.credsAuthenticator)(new TextEncoder().encode(creds));
39525
+ const authenticator = typeof creds === "function" ? (nonce3) => (0, import_transport_node14.credsAuthenticator)(new TextEncoder().encode(creds()))(nonce3) : (0, import_transport_node14.credsAuthenticator)(new TextEncoder().encode(creds));
39838
39526
  return { authenticator, tls };
39839
39527
  }
39840
39528
  return { token: a.token, user: a.user, pass: a.pass, tls };
@@ -39869,25 +39557,32 @@ function decodeBearerPrincipal(bearer) {
39869
39557
  return { owner, actor };
39870
39558
  }
39871
39559
  function describeStatusError(err2) {
39872
- if (err2 instanceof import_transport_node17.PermissionViolationError) {
39560
+ if (err2 instanceof import_transport_node14.PermissionViolationError) {
39873
39561
  return new Error(`NATS permission denied: cannot ${err2.operation} "${err2.subject}" - check this endpoint's ACLs (a denied peer looks "absent" rather than blocked)`, { cause: err2 });
39874
39562
  }
39875
39563
  return err2;
39876
39564
  }
39877
39565
  function isPermissionDenied(e) {
39878
- if (e instanceof import_transport_node17.PermissionViolationError)
39566
+ if (e instanceof import_transport_node14.PermissionViolationError)
39879
39567
  return true;
39880
- if (e?.cause instanceof import_transport_node17.PermissionViolationError)
39568
+ if (e?.cause instanceof import_transport_node14.PermissionViolationError)
39881
39569
  return true;
39882
39570
  return /permissions?\s+violation/i.test(String(e?.message ?? ""));
39883
39571
  }
39884
39572
  function isPublishPermissionDenied(e) {
39885
- const typed = e instanceof import_transport_node17.PermissionViolationError ? e : e?.cause instanceof import_transport_node17.PermissionViolationError ? e.cause : void 0;
39573
+ const typed = e instanceof import_transport_node14.PermissionViolationError ? e : e?.cause instanceof import_transport_node14.PermissionViolationError ? e.cause : void 0;
39886
39574
  return typed?.operation === "publish";
39887
39575
  }
39576
+ function wsServers(servers) {
39577
+ return /^wss?:\/\//i.test((servers.split(",")[0] ?? "").trim());
39578
+ }
39888
39579
  function dialerFor(servers) {
39889
- const first = (servers.split(",")[0] ?? "").trim();
39890
- return /^wss?:\/\//i.test(first) ? import_nats_core.wsconnect : import_transport_node17.connect;
39580
+ if (!wsServers(servers))
39581
+ return import_transport_node14.connect;
39582
+ return ((opts) => {
39583
+ const { tls: _tls, ...rest } = opts ?? {};
39584
+ return (0, import_nats_core.wsconnect)(rest);
39585
+ });
39891
39586
  }
39892
39587
  function hostPort(server) {
39893
39588
  const raw = (server.split(",")[0] ?? "").trim();
@@ -39952,13 +39647,331 @@ function classifyProbeFailure(e, opts) {
39952
39647
  } catch {
39953
39648
  }
39954
39649
  }
39955
- if (e instanceof import_transport_node17.UserAuthenticationExpiredError)
39650
+ if (e instanceof import_transport_node14.UserAuthenticationExpiredError)
39956
39651
  return { ok: false, reason: "stale-auth" };
39957
- if (e instanceof import_transport_node17.AuthorizationError)
39652
+ if (e instanceof import_transport_node14.AuthorizationError)
39958
39653
  return { ok: false, reason: "auth-required" };
39959
39654
  return { ok: false, reason: "unreachable" };
39960
39655
  }
39961
39656
 
39657
+ // ../../packages/core/dist/channels.js
39658
+ function parseDuration(s) {
39659
+ const m = /^(\d+)(s|m|h|d)$/.exec(s.trim());
39660
+ if (!m)
39661
+ throw new Error(`invalid duration "${s}" - expected <number><s|m|h|d>, e.g. "24h"`);
39662
+ const n = Number(m[1]);
39663
+ const unit = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 }[m[2]];
39664
+ return n * unit;
39665
+ }
39666
+ function effectiveReplay(cfg, defaults) {
39667
+ return cfg?.replay ?? defaults?.replay ?? true;
39668
+ }
39669
+ function effectiveReplayWindowMs(cfg, defaults) {
39670
+ const w = cfg?.replayWindow ?? defaults?.replayWindow;
39671
+ return w === void 0 ? void 0 : parseDuration(w);
39672
+ }
39673
+ function effectiveDeliveryClass(cfg, defaults) {
39674
+ return cfg?.deliveryClass ?? defaults?.deliveryClass ?? "durable";
39675
+ }
39676
+ async function openChannelRegistry(nc, space, opts = {}) {
39677
+ const kvm = new import_kv7.Kvm(nc);
39678
+ return opts.create ? kvm.create(channelBucket(space)) : kvm.open(channelBucket(space));
39679
+ }
39680
+ async function readChannelConfig(kv, channel) {
39681
+ return decode2(kv, channel);
39682
+ }
39683
+ async function readChannelDefaults(kv) {
39684
+ return decode2(kv, CHANNEL_DEFAULTS_KEY);
39685
+ }
39686
+ async function decode2(kv, key) {
39687
+ const e = await kv.get(key);
39688
+ if (!e || e.operation === "DEL" || e.operation === "PURGE")
39689
+ return void 0;
39690
+ try {
39691
+ return e.json();
39692
+ } catch {
39693
+ return void 0;
39694
+ }
39695
+ }
39696
+
39697
+ // ../../packages/core/dist/membership-feed.js
39698
+ var import_transport_node16 = __toESM(require_transport_node(), 1);
39699
+ var import_kv8 = __toESM(require_mod6(), 1);
39700
+
39701
+ // ../../packages/core/dist/evict.js
39702
+ var import_transport_node17 = __toESM(require_transport_node(), 1);
39703
+
39704
+ // ../../packages/core/dist/agent-file.js
39705
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
39706
+ var import_yaml = __toESM(require_dist(), 1);
39707
+ function parseFrontmatter(src, path) {
39708
+ let doc;
39709
+ try {
39710
+ doc = (0, import_yaml.parse)(src);
39711
+ } catch (e) {
39712
+ throw new Error(`agent file ${path}: invalid YAML frontmatter; ${e.message}`);
39713
+ }
39714
+ if (doc === null || doc === void 0)
39715
+ return {};
39716
+ if (typeof doc !== "object" || Array.isArray(doc))
39717
+ throw new Error(`agent file ${path}: frontmatter must be a YAML mapping (key: value pairs)`);
39718
+ return doc;
39719
+ }
39720
+ function loadAgentFile(path) {
39721
+ const src = readFileSync(path, "utf8");
39722
+ const m = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(src);
39723
+ if (!m)
39724
+ throw new Error(`agent file ${path}: missing "---" frontmatter block`);
39725
+ const fm = parseFrontmatter(m[1], path);
39726
+ const persona = m[2].trim();
39727
+ const str2 = (k) => {
39728
+ const v = fm[k];
39729
+ if (v === void 0 || v === null)
39730
+ return void 0;
39731
+ if (typeof v === "object")
39732
+ throw new Error(`agent file ${path}: "${k}" must be a scalar`);
39733
+ return String(v);
39734
+ };
39735
+ const list = (k) => {
39736
+ const v = fm[k];
39737
+ if (v === void 0 || v === null)
39738
+ return void 0;
39739
+ return (Array.isArray(v) ? v : [v]).map((x) => {
39740
+ if (x === null || typeof x === "object")
39741
+ throw new Error(`agent file ${path}: "${k}" list items must be scalars`);
39742
+ return String(x);
39743
+ });
39744
+ };
39745
+ const name = str2("name");
39746
+ if (!name)
39747
+ throw new Error(`agent file ${path}: "name" is required`);
39748
+ assertValidName(name);
39749
+ const kind = str2("kind");
39750
+ if (kind && kind !== "agent" && kind !== "endpoint")
39751
+ throw new Error(`agent file ${path}: "kind" must be "agent" or "endpoint"`);
39752
+ for (const old of ["channels", "publish"])
39753
+ if (old in fm)
39754
+ throw new Error(`agent file ${path}: "${old}" was renamed - use "subscribe"/"allowSubscribe" (read) and "allowPublish" (post)`);
39755
+ const subscribe = list("subscribe");
39756
+ const allowSubscribe = list("allowSubscribe");
39757
+ const allowPublish = list("allowPublish");
39758
+ const quiet = list("quiet");
39759
+ const muted = list("muted");
39760
+ for (const ch of [...subscribe ?? [], ...allowSubscribe ?? [], ...allowPublish ?? []])
39761
+ try {
39762
+ assertValidChannel(ch);
39763
+ } catch (e) {
39764
+ throw new Error(`agent file ${path}: ${e.message}`);
39765
+ }
39766
+ const effSubscribe = subscribe ?? [];
39767
+ const effAllow = allowSubscribe?.length ? allowSubscribe : effSubscribe;
39768
+ for (const ch of effSubscribe)
39769
+ if (!channelInAllow(effAllow, ch))
39770
+ throw new Error(`agent file ${path}: subscribe channel "${ch}" is not within allowSubscribe [${effAllow.join(", ")}]`);
39771
+ const both = (quiet ?? []).filter((c) => (muted ?? []).includes(c));
39772
+ if (both.length)
39773
+ throw new Error(`agent file ${path}: channel(s) [${both.join(", ")}] are in both quiet and muted - pick one`);
39774
+ for (const [field, chans] of [["quiet", quiet], ["muted", muted]])
39775
+ for (const ch of chans ?? []) {
39776
+ try {
39777
+ assertValidChannel(ch);
39778
+ } catch (e) {
39779
+ throw new Error(`agent file ${path}: ${e.message}`);
39780
+ }
39781
+ if (!isConcreteChannel(ch))
39782
+ throw new Error(`agent file ${path}: ${field} channel "${ch}" must be a concrete channel (no wildcard)`);
39783
+ if (!channelInAllow(effAllow, ch))
39784
+ throw new Error(`agent file ${path}: ${field} channel "${ch}" is not within your read ACL / allowSubscribe [${effAllow.join(", ")}]`);
39785
+ }
39786
+ const launchOptionsRaw = fm["launchOptions"];
39787
+ let launchOptions;
39788
+ if (launchOptionsRaw !== void 0 && launchOptionsRaw !== null) {
39789
+ if (typeof launchOptionsRaw !== "object" || Array.isArray(launchOptionsRaw))
39790
+ throw new Error(`agent file ${path}: "launchOptions" must be a mapping of key: value pairs`);
39791
+ launchOptions = launchOptionsRaw;
39792
+ }
39793
+ const known = /* @__PURE__ */ new Set(["name", "role", "kind", "description", "tags", "subscribe", "allowSubscribe", "allowPublish", "quiet", "muted", "model", "variant", "launchOptions", "capabilities", "owner"]);
39794
+ const meta3 = {};
39795
+ for (const [k, v] of Object.entries(fm))
39796
+ if (!known.has(k) && v !== null && typeof v !== "object")
39797
+ meta3[k] = String(v);
39798
+ return {
39799
+ name,
39800
+ role: str2("role"),
39801
+ kind,
39802
+ description: str2("description"),
39803
+ tags: list("tags"),
39804
+ subscribe,
39805
+ allowSubscribe,
39806
+ allowPublish,
39807
+ quiet,
39808
+ muted,
39809
+ model: str2("model"),
39810
+ variant: str2("variant"),
39811
+ launchOptions,
39812
+ capabilities: list("capabilities"),
39813
+ owner: str2("owner"),
39814
+ meta: Object.keys(meta3).length ? meta3 : void 0,
39815
+ persona: persona || void 0
39816
+ };
39817
+ }
39818
+
39819
+ // ../../packages/core/dist/secret-fs.js
39820
+ import { chmodSync, mkdirSync as mkdirSync2, renameSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
39821
+ import { execFileSync } from "node:child_process";
39822
+ import { join } from "node:path";
39823
+ var isWin = process.platform === "win32";
39824
+ function sys32(exe) {
39825
+ const root = process.env.SystemRoot || process.env.windir || "C:\\Windows";
39826
+ return join(root, "System32", exe);
39827
+ }
39828
+ var cachedSid;
39829
+ function ownerSid() {
39830
+ if (cachedSid)
39831
+ return cachedSid;
39832
+ const out = execFileSync(sys32("whoami.exe"), ["/user", "/fo", "csv", "/nh"], { encoding: "utf8" });
39833
+ const sid = out.trim().split(",").pop()?.replace(/^"|"$/g, "").trim();
39834
+ if (!sid || !/^S-1-/.test(sid))
39835
+ throw new Error(`could not determine the current user's SID from \`whoami\` (got: ${out.trim()})`);
39836
+ cachedSid = sid;
39837
+ return sid;
39838
+ }
39839
+ var BROAD_SIDS = ["S-1-1-0", "S-1-5-11", "S-1-5-32-545"];
39840
+ function hardenPrivate(path, kind) {
39841
+ if (!isWin) {
39842
+ chmodSync(path, kind === "dir" ? 448 : 384);
39843
+ return;
39844
+ }
39845
+ const perm = kind === "dir" ? "(OI)(CI)(F)" : "(F)";
39846
+ const removeBroad = BROAD_SIDS.flatMap((sid) => ["/remove:g", `*${sid}`]);
39847
+ const grant = (sid) => ["/grant:r", `*${sid}:${perm}`];
39848
+ try {
39849
+ execFileSync(sys32("icacls.exe"), [
39850
+ path,
39851
+ "/inheritance:r",
39852
+ ...removeBroad,
39853
+ ...grant(ownerSid()),
39854
+ ...grant("S-1-5-18"),
39855
+ ...grant("S-1-5-32-544")
39856
+ ], { stdio: ["ignore", "ignore", "pipe"] });
39857
+ } catch (e) {
39858
+ throw new Error(`failed to harden ${kind} "${path}" to private via icacls: ${e.message.trim()}. Cotal will not leave a secret with a permissive ACL - ensure the path is on an NTFS volume and %SystemRoot%\\System32\\icacls.exe is available.`);
39859
+ }
39860
+ }
39861
+ function writeSecretFile(path, data) {
39862
+ writeFileSync2(path, data, { mode: 384 });
39863
+ if (!isWin)
39864
+ return;
39865
+ try {
39866
+ hardenPrivate(path, "file");
39867
+ } catch (e) {
39868
+ try {
39869
+ unlinkSync(path);
39870
+ } catch {
39871
+ }
39872
+ throw e;
39873
+ }
39874
+ }
39875
+ function writeSecretFileAtomic(path, data) {
39876
+ const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
39877
+ try {
39878
+ writeSecretFile(tmp, data);
39879
+ renameSync(tmp, path);
39880
+ } catch (e) {
39881
+ try {
39882
+ unlinkSync(tmp);
39883
+ } catch {
39884
+ }
39885
+ throw e;
39886
+ }
39887
+ }
39888
+ function mkSecretDir(path) {
39889
+ mkdirSync2(path, { recursive: true, mode: 448 });
39890
+ hardenPrivate(path, "dir");
39891
+ }
39892
+
39893
+ // ../../packages/core/dist/launch-material.js
39894
+ import { mkdtempSync, readFileSync as readFileSync2, realpathSync, rmSync, rmdirSync, statSync } from "node:fs";
39895
+ import { tmpdir } from "node:os";
39896
+ import { basename, dirname, join as join2, resolve } from "node:path";
39897
+ var DIR_PREFIX = "cotal-launch-";
39898
+ var MATERIAL_FILE = "material.json";
39899
+ var LAUNCH_MATERIAL_ENV = "COTAL_LAUNCH_MATERIAL";
39900
+ function readLaunchMaterial(path) {
39901
+ let raw;
39902
+ try {
39903
+ if (process.platform !== "win32") {
39904
+ const mode = statSync(path).mode & 511;
39905
+ if (mode & 63)
39906
+ throw new Error(`is readable beyond its owner (mode ${mode.toString(8)}) - refusing to read connection material out of a file other local users can open`);
39907
+ }
39908
+ raw = readFileSync2(path, "utf8");
39909
+ } catch (e) {
39910
+ throw new Error(`launch material: cannot read ${path} (${e instanceof Error ? e.message : String(e)})`);
39911
+ }
39912
+ let parsed;
39913
+ try {
39914
+ parsed = JSON.parse(raw);
39915
+ } catch {
39916
+ throw new Error(`launch material: ${path} is not valid JSON`);
39917
+ }
39918
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
39919
+ throw new Error(`launch material: ${path} must contain a JSON object`);
39920
+ return validate(parsed, path);
39921
+ }
39922
+ function validate(raw, path) {
39923
+ const material = {};
39924
+ const str2 = (key) => {
39925
+ const v = raw[key];
39926
+ if (v === void 0)
39927
+ return;
39928
+ if (typeof v !== "string" || !v.trim())
39929
+ throw new Error(`launch material: ${path} has a ${key} that is not a non-empty string`);
39930
+ material[key] = v;
39931
+ };
39932
+ str2("servers");
39933
+ str2("creds");
39934
+ str2("token");
39935
+ str2("controlToken");
39936
+ if (raw.userAuth !== void 0) {
39937
+ const u = raw.userAuth;
39938
+ if (typeof u !== "object" || u === null || Array.isArray(u))
39939
+ throw new Error(`launch material: ${path} has a userAuth that is not an object`);
39940
+ const { owner, actor, sentinelCredsPath, bearerCmd } = u;
39941
+ const named = { owner, actor, sentinelCredsPath };
39942
+ for (const [k, v] of Object.entries(named))
39943
+ if (typeof v !== "string" || !v.trim())
39944
+ throw new Error(`launch material: ${path} has a userAuth.${k} that is not a non-empty string`);
39945
+ if (!Array.isArray(bearerCmd) || bearerCmd.length === 0 || !bearerCmd.every((a) => typeof a === "string" && a))
39946
+ throw new Error(`launch material: ${path} has a userAuth.bearerCmd that is not a non-empty array of strings`);
39947
+ material.userAuth = {
39948
+ owner,
39949
+ actor,
39950
+ sentinelCredsPath,
39951
+ bearerCmd
39952
+ };
39953
+ }
39954
+ if (Object.keys(material).length === 0)
39955
+ throw new Error(`launch material: ${path} carries nothing this reader recognises. A launch that references material and supplies none is a broken launcher, not an open-mode launch, so it is refused rather than defaulted.`);
39956
+ return material;
39957
+ }
39958
+ function discardLaunchMaterial(path) {
39959
+ const file2 = resolve(path);
39960
+ try {
39961
+ rmSync(file2, { force: true });
39962
+ } catch {
39963
+ }
39964
+ const dir = dirname(file2);
39965
+ if (basename(file2) !== MATERIAL_FILE || !basename(dir).startsWith(DIR_PREFIX))
39966
+ return;
39967
+ try {
39968
+ if (realpathSync(dirname(dir)) !== realpathSync(tmpdir()))
39969
+ return;
39970
+ rmdirSync(dir);
39971
+ } catch {
39972
+ }
39973
+ }
39974
+
39962
39975
  // ../../packages/core/dist/spaces.js
39963
39976
  var import_transport_node18 = __toESM(require_transport_node(), 1);
39964
39977
  var import_jetstream15 = __toESM(require_mod4(), 1);
@@ -40159,7 +40172,7 @@ function configFromEnv(env = process.env) {
40159
40172
  if (!name)
40160
40173
  throw new Error("COTAL_NAME, COTAL_AGENT_FILE or COTAL_LINK is required \u2014 a Cotal session needs an explicit identity from its launcher");
40161
40174
  const subscribe = splitList(env.COTAL_SUBSCRIBE);
40162
- const resolvedSubscribe = subscribe.length ? subscribe : def?.subscribe ?? link?.channels ?? ["general"];
40175
+ const resolvedSubscribe = subscribe.length ? subscribe : def?.subscribe ?? link?.channels ?? [];
40163
40176
  const allowSub = splitList(env.COTAL_ALLOW_SUBSCRIBE);
40164
40177
  const resolvedAllowSub = allowSub.length ? allowSub : def?.allowSubscribe ?? resolvedSubscribe;
40165
40178
  for (const ch of resolvedSubscribe)
@@ -55865,7 +55878,7 @@ config(en_default());
55865
55878
 
55866
55879
  // ../connector-core/dist/docs-bundle.generated.js
55867
55880
  var DOCS_BUNDLE = {
55868
- "version": "0.27.0",
55881
+ "version": "0.28.1",
55869
55882
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
55870
55883
  "pages": [
55871
55884
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cotal-ai/pi",
3
- "version": "0.28.0-hack-20260823234508",
3
+ "version": "0.28.1",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,7 +24,7 @@
24
24
  "node": ">=20"
25
25
  },
26
26
  "peerDependencies": {
27
- "@cotal-ai/core": "0.28.0-hack-20260823234508",
27
+ "@cotal-ai/core": ">=0.1.0",
28
28
  "@earendil-works/pi-tui": ">=0.79.10"
29
29
  },
30
30
  "devDependencies": {
@@ -34,8 +34,8 @@
34
34
  "esbuild": "^0.28.0",
35
35
  "typebox": "^1.1.0",
36
36
  "zod": "^4.4.3",
37
- "@cotal-ai/core": "0.28.0-hack-20260823234508",
38
- "@cotal-ai/connector-core": "0.28.0-hack-20260823234508"
37
+ "@cotal-ai/core": "0.28.1",
38
+ "@cotal-ai/connector-core": "0.28.1"
39
39
  },
40
40
  "files": [
41
41
  "dist"