@m8t-stack/cli 0.2.109 → 0.2.111

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/cli.js CHANGED
@@ -1454,7 +1454,7 @@ function installFoundryDnsShim() {
1454
1454
  }
1455
1455
 
1456
1456
  // src/lib/package-version.ts
1457
- var CLI_VERSION = "0.2.109";
1457
+ var CLI_VERSION = "0.2.111";
1458
1458
 
1459
1459
  // src/lib/render-error.ts
1460
1460
  init_errors();
@@ -15326,12 +15326,12 @@ function patchAgentYaml(agentName, patch, home) {
15326
15326
  }
15327
15327
 
15328
15328
  // src/lib/brain-link.ts
15329
- init_esm2();
15330
- init_esm();
15331
- init_errors();
15332
15329
  import * as path8 from "path";
15333
15330
  import * as fs8 from "fs";
15334
15331
  import { createHash, randomBytes as randomBytes2 } from "crypto";
15332
+ init_esm2();
15333
+ init_esm();
15334
+ init_errors();
15335
15335
 
15336
15336
  // src/lib/persona-render.ts
15337
15337
  init_errors();
@@ -15698,12 +15698,10 @@ function unwrapTemplateBlock(template, name) {
15698
15698
  return template.replace(`<!-- m8t:${name}:start -->`, "").replace(`<!-- m8t:${name}:end -->`, "").trim();
15699
15699
  }
15700
15700
  async function putLegacyGithubMcpConnection(args) {
15701
- const armToken = await args.credential.getToken(ARM_SCOPE3);
15702
- if (!armToken?.token) {
15703
- throw new LocalCliError({ code: "ARM_AUTH", message: "Could not acquire ARM token" });
15704
- }
15705
- const url = `https://management.azure.com${args.projectArmId}/connections/${args.connectionName}?api-version=${FOUNDRY_ARM_API}`;
15706
- const body = JSON.stringify({
15701
+ await putFoundryCustomKeysConnection({
15702
+ credential: args.credential,
15703
+ projectArmId: args.projectArmId,
15704
+ connectionName: args.connectionName,
15707
15705
  properties: {
15708
15706
  authType: "CustomKeys",
15709
15707
  category: "CustomKeys",
@@ -15713,27 +15711,12 @@ async function putLegacyGithubMcpConnection(args) {
15713
15711
  metadata: { managedBy: "m8t-brain-link", transport: "github-mcp" }
15714
15712
  }
15715
15713
  });
15716
- const res = await fetch(url, {
15717
- method: "PUT",
15718
- headers: { Authorization: `Bearer ${armToken.token}`, "Content-Type": "application/json" },
15719
- body
15720
- });
15721
- if (!res.ok) {
15722
- const text = await res.text();
15723
- throw new LocalCliError({
15724
- code: "CONN_CREATE_FAILED",
15725
- message: `PUT ${url}: HTTP ${res.status.toString()}
15726
- ${text.slice(0, 300)}`
15727
- });
15728
- }
15729
15714
  }
15730
15715
  async function putGatewayMcpConnection(args) {
15731
- const armToken = await args.credential.getToken(ARM_SCOPE3);
15732
- if (!armToken?.token) {
15733
- throw new LocalCliError({ code: "ARM_AUTH", message: "Could not acquire ARM token" });
15734
- }
15735
- const url = `https://management.azure.com${args.projectArmId}/connections/${args.connectionName}?api-version=${FOUNDRY_ARM_API}`;
15736
- const body = JSON.stringify({
15716
+ await putFoundryCustomKeysConnection({
15717
+ credential: args.credential,
15718
+ projectArmId: args.projectArmId,
15719
+ connectionName: args.connectionName,
15737
15720
  properties: {
15738
15721
  authType: "CustomKeys",
15739
15722
  category: "CustomKeys",
@@ -15743,20 +15726,79 @@ async function putGatewayMcpConnection(args) {
15743
15726
  metadata: { managedBy: "m8t-brain-link", transport: "gateway-mcp-v1" }
15744
15727
  }
15745
15728
  });
15746
- const res = await fetch(url, {
15747
- method: "PUT",
15748
- headers: { Authorization: `Bearer ${armToken.token}`, "Content-Type": "application/json" },
15749
- body
15750
- });
15729
+ }
15730
+ async function putFoundryCustomKeysConnection(args) {
15731
+ const armToken = await args.credential.getToken(ARM_SCOPE3);
15732
+ if (!armToken?.token) {
15733
+ throw new LocalCliError({ code: "ARM_AUTH", message: "Could not acquire ARM token" });
15734
+ }
15735
+ const url = `https://management.azure.com${args.projectArmId}/connections/${args.connectionName}?api-version=${FOUNDRY_ARM_API}`;
15736
+ const headers = { Authorization: `Bearer ${armToken.token}`, "Content-Type": "application/json" };
15737
+ const intended = {
15738
+ ...args.properties,
15739
+ metadata: {
15740
+ ...args.properties.metadata,
15741
+ // The other non-secret fields can match a stale connection from an older
15742
+ // attempt whose write-only bearer is different. This nonce proves the GET
15743
+ // observed this exact PUT, without exposing or attempting to read the key.
15744
+ provisioningNonce: randomBytes2(32).toString("base64url")
15745
+ }
15746
+ };
15747
+ let res;
15748
+ try {
15749
+ res = await fetch(url, { method: "PUT", headers, body: JSON.stringify({ properties: intended }) });
15750
+ } catch (error) {
15751
+ if (isAmbiguousConnectionPutError(error) && await exactConnectionExists({ url, authorization: headers.Authorization, intended })) return;
15752
+ throw error;
15753
+ }
15751
15754
  if (!res.ok) {
15752
- const text = await res.text();
15753
- throw new LocalCliError({
15755
+ const text = await res.text().catch((error) => `<response body unavailable: ${error instanceof Error ? error.message : String(error)}>`);
15756
+ const originalFailure = new LocalCliError({
15754
15757
  code: "CONN_CREATE_FAILED",
15755
15758
  message: `PUT ${url}: HTTP ${res.status.toString()}
15756
15759
  ${text.slice(0, 300)}`
15757
15760
  });
15761
+ if (isAmbiguousConnectionPutStatus(res.status) && await exactConnectionExists({ url, authorization: headers.Authorization, intended })) return;
15762
+ throw originalFailure;
15763
+ }
15764
+ }
15765
+ function isAmbiguousConnectionPutStatus(status) {
15766
+ return status === 408 || status === 429 || status >= 500;
15767
+ }
15768
+ function isAmbiguousConnectionPutError(error) {
15769
+ let current = error;
15770
+ const seen = /* @__PURE__ */ new Set();
15771
+ for (let depth = 0; depth < 5 && current !== void 0 && !seen.has(current); depth++) {
15772
+ seen.add(current);
15773
+ const classified = classifyFoundryError(current);
15774
+ if (classified.retryable && (classified.category === "transient" || classified.category === "rate_limit")) return true;
15775
+ current = isRecord2(current) ? current.cause : void 0;
15776
+ }
15777
+ return false;
15778
+ }
15779
+ async function exactConnectionExists(args) {
15780
+ try {
15781
+ const res = await fetch(args.url, {
15782
+ method: "GET",
15783
+ headers: { Authorization: args.authorization }
15784
+ });
15785
+ if (!res.ok) return false;
15786
+ const resource = await res.json();
15787
+ if (!isRecord2(resource) || !isRecord2(resource.properties)) return false;
15788
+ const { credentials: _writeOnlyCredentials, ...nonSecretIntended } = args.intended;
15789
+ return containsIntendedShape(resource.properties, nonSecretIntended);
15790
+ } catch {
15791
+ return false;
15758
15792
  }
15759
15793
  }
15794
+ function containsIntendedShape(actual, intended) {
15795
+ if (!isRecord2(intended)) return Object.is(actual, intended);
15796
+ if (!isRecord2(actual)) return false;
15797
+ return Object.entries(intended).every(([key2, value]) => Object.hasOwn(actual, key2) && containsIntendedShape(actual[key2], value));
15798
+ }
15799
+ function isRecord2(value) {
15800
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15801
+ }
15760
15802
  async function createBrainEnabledVersion(args) {
15761
15803
  const otherTools = (args.currentDefinition.tools ?? []).filter(
15762
15804
  (t) => !(t.type === "mcp" && t.server_label === "brain")
@@ -24328,8 +24370,8 @@ var PlatformRequestUpdateCommand = class extends M8tCommand {
24328
24370
  description: "Ask this installation's updater to converge to a version, exactly as the in-app button does.",
24329
24371
  details: "Writes the update request the updater job claims on its next tick. This is the ONLY privilege the requester holds \u2014 it does not deploy anything itself; the install's own updater fetches the release, applies it, health-gates it and rolls back on failure. With --wait, follows the request to a terminal state and exits non-zero if it did not succeed.",
24330
24372
  examples: [
24331
- ["Request an update", "m8t platform request-update --version 0.7.4 --resource-group rg-m8t --subscription <id>"],
24332
- ["Request it and wait", "m8t platform request-update --version 0.7.4 --wait --resource-group rg-m8t --subscription <id>"]
24373
+ ["Request an update", "m8t platform request-update --version 0.7.5 --resource-group rg-m8t --subscription <id>"],
24374
+ ["Request it and wait", "m8t platform request-update --version 0.7.5 --wait --resource-group rg-m8t --subscription <id>"]
24333
24375
  ]
24334
24376
  });
24335
24377
  version = Option35.String("--version", { description: "The platform version to converge to." });
@@ -30036,14 +30078,73 @@ function renderDigestMarkdown(digest, opts) {
30036
30078
 
30037
30079
  // ../../packages/brain/engine/dist/esm/dream/digest-commit.js
30038
30080
  var DIGEST_DIR = "artifacts/dream-digest";
30081
+ var ISO_UTC = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?Z$/;
30039
30082
  function digestPaths(cycle) {
30040
30083
  return { json: `${DIGEST_DIR}/${cycle}.json`, md: `${DIGEST_DIR}/${cycle}.md` };
30041
30084
  }
30085
+ function normalizeCycleTimestamp(cycle) {
30086
+ const match = ISO_UTC.exec(cycle);
30087
+ if (!match)
30088
+ return null;
30089
+ const parsed = new Date(cycle);
30090
+ if (!Number.isFinite(parsed.getTime()))
30091
+ return null;
30092
+ const [, year, month, day, hour, minute, second] = match.map(Number);
30093
+ if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() + 1 !== month || parsed.getUTCDate() !== day || parsed.getUTCHours() !== hour || parsed.getUTCMinutes() !== minute || parsed.getUTCSeconds() !== second)
30094
+ return null;
30095
+ return parsed.toISOString();
30096
+ }
30097
+ function oneLine(value, max = 240) {
30098
+ const withoutControls = Array.from(value, (char) => {
30099
+ const code = char.codePointAt(0) ?? 0;
30100
+ return code < 32 || code >= 127 && code <= 159 || code === 8232 || code === 8233 ? " " : char;
30101
+ }).join("");
30102
+ const collapsed = withoutControls.replace(/\s+/g, " ").trim();
30103
+ return Array.from(collapsed).slice(0, max).join("");
30104
+ }
30105
+ function yamlScalar(value) {
30106
+ return JSON.stringify(value).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
30107
+ }
30108
+ function digestSources(digest) {
30109
+ const refs = /* @__PURE__ */ new Set();
30110
+ for (const entry of digest.entries) {
30111
+ const evidence = entry.evidence;
30112
+ if (!Array.isArray(evidence))
30113
+ continue;
30114
+ for (const ref of evidence)
30115
+ if (typeof ref === "string" && ref.length > 0)
30116
+ refs.add(ref);
30117
+ }
30118
+ return [...refs];
30119
+ }
30120
+ function renderDreamDigestArtifact(digest, timestamp2) {
30121
+ const worker = oneLine(digest.worker) || "worker";
30122
+ const lines = [
30123
+ "---",
30124
+ "type: artifact",
30125
+ `title: ${yamlScalar(`Dream digest \u2014 ${worker}`)}`,
30126
+ `created: ${timestamp2}`,
30127
+ `updated: ${timestamp2}`,
30128
+ "tags:",
30129
+ " - dream-digest",
30130
+ "origin: dream"
30131
+ ];
30132
+ const sources = digestSources(digest);
30133
+ if (sources.length > 0) {
30134
+ lines.push("source:", ...sources.map((source) => ` - ${yamlScalar(source)}`));
30135
+ }
30136
+ lines.push("---", "");
30137
+ return `${lines.join("\n")}${renderDigestMarkdown({ ...digest, worker })}`;
30138
+ }
30042
30139
  async function commitDreamDigest(digest, brain, deps) {
30043
- const { json, md } = digestPaths(digest.cycle);
30044
- const jsonContent = JSON.stringify(digest, null, 2) + "\n";
30045
- const mdContent = renderDigestMarkdown(digest);
30046
30140
  try {
30141
+ const timestamp2 = normalizeCycleTimestamp(digest.cycle);
30142
+ if (timestamp2 === null) {
30143
+ return { committed: false, reason: "error", reconstructible: digest };
30144
+ }
30145
+ const { json, md } = digestPaths(digest.cycle);
30146
+ const jsonContent = JSON.stringify(digest, null, 2) + "\n";
30147
+ const mdContent = renderDreamDigestArtifact(digest, timestamp2);
30047
30148
  const expectedOldSha = await deps.fetchTip();
30048
30149
  const res = await brain.commitBatch({
30049
30150
  expectedOldSha,
@@ -30209,8 +30310,8 @@ function boundedField(value, max) {
30209
30310
  const isLineOrControl = code < 32 || code >= 127 && code <= 159 || code === 8232 || code === 8233;
30210
30311
  return isLineOrControl ? " " : char;
30211
30312
  }).join("");
30212
- const oneLine = withoutControls.replace(/\s+/g, " ").trim();
30213
- return oneLine.length <= max ? oneLine : `${oneLine.slice(0, Math.max(0, max - 1))}\u2026`;
30313
+ const oneLine2 = withoutControls.replace(/\s+/g, " ").trim();
30314
+ return oneLine2.length <= max ? oneLine2 : `${oneLine2.slice(0, Math.max(0, max - 1))}\u2026`;
30214
30315
  }
30215
30316
  function renderIndexEntry(entry, memory) {
30216
30317
  const file2 = memory.files.find((candidate2) => candidate2.path === entry.path);
@@ -30459,8 +30560,8 @@ function indexField(value, max) {
30459
30560
  const isLineOrControl = code < 32 || code >= 127 && code <= 159 || code === 8232 || code === 8233;
30460
30561
  return isLineOrControl ? " " : char;
30461
30562
  }).join("");
30462
- const oneLine = withoutControls.replace(/\s+/g, " ").trim();
30463
- return oneLine.length <= max ? oneLine : `${oneLine.slice(0, Math.max(0, max - 1))}\u2026`;
30563
+ const oneLine2 = withoutControls.replace(/\s+/g, " ").trim();
30564
+ return oneLine2.length <= max ? oneLine2 : `${oneLine2.slice(0, Math.max(0, max - 1))}\u2026`;
30464
30565
  }
30465
30566
  function indexSummary(body, title) {
30466
30567
  const summary = indexField(body, MAX_INDEX_SUMMARY_CHARS);
@@ -32618,7 +32719,7 @@ ${colors.error("\u2717")} The GitHub App on disk is installed on ${colors.field(
32618
32719
  // src/commands/bootstrap/launch.ts
32619
32720
  var DEFAULT_RG = "rg-m8t-stack";
32620
32721
  var DEFAULT_INSTALLER = "ghcr.io/m8t-labs/m8t-installer";
32621
- var DEFAULT_INSTALLER_TAG = "v0.1.76";
32722
+ var DEFAULT_INSTALLER_TAG = "v0.1.78";
32622
32723
  var ACI_NAME = "m8t-installer";
32623
32724
  var MI_NAME = "m8t-installer-mi";
32624
32725
  var BootstrapLaunchCommand = class extends M8tCommand {
@@ -32907,7 +33008,7 @@ var ONBOARDING_BLOCK_KEYS = [
32907
33008
  "advisor_name",
32908
33009
  "advisor_email"
32909
33010
  ];
32910
- function isRecord2(value) {
33011
+ function isRecord3(value) {
32911
33012
  return typeof value === "object" && value !== null && !Array.isArray(value);
32912
33013
  }
32913
33014
  function hasValidUniqueJsonKeys(source) {
@@ -33015,7 +33116,7 @@ var V3_COMPANY_KEYS = ["name", "one_liner"];
33015
33116
  var V3_ADDRESS_KEYS = ["address", "city", "postal_code", "country"];
33016
33117
  var V3_REQUEST_KEYS = ["type", "model", "region", "consent", "company_address"];
33017
33118
  function exactStringRecord(value, keys) {
33018
- if (!isRecord2(value)) return "non-string-value";
33119
+ if (!isRecord3(value)) return "non-string-value";
33019
33120
  const present = new Set(Object.keys(value));
33020
33121
  for (const key2 of keys) if (!present.has(key2)) return "missing-key";
33021
33122
  if (present.size !== keys.length) return "unexpected-key";
@@ -33027,7 +33128,7 @@ function canonicalPendingRequests(value) {
33027
33128
  if (value.length > 1) return { ok: false, reason: "too-many-pending-requests" };
33028
33129
  const requests = [];
33029
33130
  for (const entry of value) {
33030
- if (!isRecord2(entry)) return { ok: false, reason: "non-string-value" };
33131
+ if (!isRecord3(entry)) return { ok: false, reason: "non-string-value" };
33031
33132
  const present = new Set(Object.keys(entry));
33032
33133
  for (const key2 of V3_REQUEST_KEYS) {
33033
33134
  if (!present.has(key2)) return { ok: false, reason: "missing-key" };
@@ -33077,7 +33178,7 @@ function canonicalV3Block(value) {
33077
33178
  };
33078
33179
  }
33079
33180
  function canonicalBlock(value) {
33080
- if (!isRecord2(value)) return { ok: false, reason: "non-string-value" };
33181
+ if (!isRecord3(value)) return { ok: false, reason: "non-string-value" };
33081
33182
  if (value.schema_version === "3") return canonicalV3Block(value);
33082
33183
  if (value.schema_version !== "2") return { ok: false, reason: "unknown-schema-version" };
33083
33184
  const keys = new Set(Object.keys(value));
@@ -33122,7 +33223,7 @@ function parseOnboardingArtifactResult(machineText) {
33122
33223
  if (json.includes("m8t_onboarding")) return { ok: false, reason: "malformed-json" };
33123
33224
  continue;
33124
33225
  }
33125
- if (!isRecord2(parsed) || !Object.hasOwn(parsed, "m8t_onboarding")) continue;
33226
+ if (!isRecord3(parsed) || !Object.hasOwn(parsed, "m8t_onboarding")) continue;
33126
33227
  if (Object.keys(parsed).length !== 1) return { ok: false, reason: "unexpected-key" };
33127
33228
  const outcome = canonicalBlock(parsed.m8t_onboarding);
33128
33229
  if (!outcome.ok) return outcome;
@@ -33168,7 +33269,7 @@ async function readCursorPages(args) {
33168
33269
  } catch {
33169
33270
  return null;
33170
33271
  }
33171
- if (!isRecord2(body) || !Array.isArray(body.data)) return null;
33272
+ if (!isRecord3(body) || !Array.isArray(body.data)) return null;
33172
33273
  const page = body;
33173
33274
  all.push(...page.data);
33174
33275
  if (page.has_more !== true) {
@@ -33189,7 +33290,7 @@ function decodeFoundryUser(token) {
33189
33290
  if (parts.length !== 3 || parts.some((part) => part.length === 0) || !/^[A-Za-z0-9_-]+$/.test(parts[1] ?? "")) return null;
33190
33291
  try {
33191
33292
  const payload = JSON.parse(Buffer.from(parts[1] ?? "", "base64url").toString("utf8"));
33192
- if (!isRecord2(payload)) return null;
33293
+ if (!isRecord3(payload)) return null;
33193
33294
  const claim = payload.upn ?? payload.preferred_username ?? payload.email;
33194
33295
  return typeof claim === "string" && claim.trim().length > 0 ? claim : null;
33195
33296
  } catch {
@@ -33220,7 +33321,7 @@ async function findOnboardingProfile(args) {
33220
33321
  });
33221
33322
  if (!listed) return { ...EMPTY_PROFILE_RESULT };
33222
33323
  const conversations = orderNewest(listed.flatMap((value, ordinal) => {
33223
- if (!isRecord2(value) || typeof value.id !== "string" || value.id.length === 0 || !isRecord2(value.metadata)) return [];
33324
+ if (!isRecord3(value) || typeof value.id !== "string" || value.id.length === 0 || !isRecord3(value.metadata)) return [];
33224
33325
  const metadata = value.metadata;
33225
33326
  if (metadata.app !== "m8t-webapp" || metadata.agent !== INTAKE_AGENT_NAME) return [];
33226
33327
  return [{
@@ -33238,7 +33339,7 @@ async function findOnboardingProfile(args) {
33238
33339
  });
33239
33340
  if (!items) return { hadIntake: true, block: null, machineText: null, speechText: null, rejection: null };
33240
33341
  const assistantItems = orderNewest(items.flatMap((value, ordinal) => {
33241
- if (!isRecord2(value) || value.type !== "message" || value.role !== "assistant" || !Array.isArray(value.content)) return [];
33342
+ if (!isRecord3(value) || value.type !== "message" || value.role !== "assistant" || !Array.isArray(value.content)) return [];
33242
33343
  const id = typeof value.id === "string" ? value.id : "";
33243
33344
  return [{ value, id, createdAt: timestamp(value.created_at), ordinal }];
33244
33345
  }));
@@ -33247,7 +33348,7 @@ async function findOnboardingProfile(args) {
33247
33348
  for (const item of assistantItems) {
33248
33349
  const content = item.value.content;
33249
33350
  const machineText = content.flatMap((part) => {
33250
- if (!isRecord2(part)) return [];
33351
+ if (!isRecord3(part)) return [];
33251
33352
  if (typeof part.text === "string" && part.text.length > 0) return [part.text];
33252
33353
  if (typeof part.transcript === "string") return [part.transcript];
33253
33354
  return [];
@@ -33460,14 +33561,14 @@ function dir(home) {
33460
33561
  function file(home) {
33461
33562
  return path38.join(dir(home), ONBOARDING_PROFILE_FILE);
33462
33563
  }
33463
- function isRecord3(value) {
33564
+ function isRecord4(value) {
33464
33565
  return typeof value === "object" && value !== null && !Array.isArray(value);
33465
33566
  }
33466
33567
  function nonBlankString(value) {
33467
33568
  return typeof value === "string" && value.trim().length > 0;
33468
33569
  }
33469
33570
  function canonical(value) {
33470
- if (!isRecord3(value)) return null;
33571
+ if (!isRecord4(value)) return null;
33471
33572
  if (value.schemaVersion !== 1) return null;
33472
33573
  if (!nonBlankString(value.founderEmail)) return null;
33473
33574
  if (typeof value.founderName !== "string") return null;
@@ -33475,7 +33576,7 @@ function canonical(value) {
33475
33576
  if (value.advisor === void 0) return null;
33476
33577
  let advisor = null;
33477
33578
  if (value.advisor !== null) {
33478
- if (!isRecord3(value.advisor)) return null;
33579
+ if (!isRecord4(value.advisor)) return null;
33479
33580
  if (typeof value.advisor.name !== "string" || typeof value.advisor.email !== "string") return null;
33480
33581
  advisor = { name: value.advisor.name, email: value.advisor.email };
33481
33582
  }
@@ -35934,7 +36035,7 @@ var SHELL_UNSAFE = /[&|^<>"`$%\\\s]/;
35934
36035
  function chatInviteUrl() {
35935
36036
  return `https://raw.githubusercontent.com/${EZRA_REPO}/main/${CHAT_INVITE_PATH}`;
35936
36037
  }
35937
- function isRecord4(value) {
36038
+ function isRecord5(value) {
35938
36039
  return typeof value === "object" && value !== null && !Array.isArray(value);
35939
36040
  }
35940
36041
  async function fetchChatInvite(deps = {}) {
@@ -35955,7 +36056,7 @@ async function fetchChatInvite(deps = {}) {
35955
36056
  } catch {
35956
36057
  return { ok: false, reason: "unreachable" };
35957
36058
  }
35958
- if (!isRecord4(parsed)) return { ok: false, reason: "malformed" };
36059
+ if (!isRecord5(parsed)) return { ok: false, reason: "malformed" };
35959
36060
  if (parsed.schemaVersion !== 1) return { ok: false, reason: "unknown-schema" };
35960
36061
  if (parsed.enabled !== true) return { ok: false, reason: "disabled" };
35961
36062
  const raw = typeof parsed.inviteUrl === "string" ? parsed.inviteUrl.trim() : "";
@@ -36410,7 +36511,7 @@ var VERSION3 = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,63}$/u;
36410
36511
  function isVersionOrNull(value) {
36411
36512
  return value === null || typeof value === "string" && VERSION3.test(value);
36412
36513
  }
36413
- function isRecord5(value) {
36514
+ function isRecord6(value) {
36414
36515
  return typeof value === "object" && value !== null && !Array.isArray(value);
36415
36516
  }
36416
36517
  function hasExactKeys(value, keys) {
@@ -36435,11 +36536,11 @@ function isInstantOrNull(value) {
36435
36536
  return value === null || typeof value === "string" && INSTANT_SHAPE.test(value) && Number.isFinite(Date.parse(value));
36436
36537
  }
36437
36538
  function parseDecision(value) {
36438
- if (!isRecord5(value) || !isBoundedPlainString(value.callId, COMPANION_DECISION_CALL_ID_MAX_LENGTH) || !isBoundedPlainString(value.title, COMPANION_DECISION_TITLE_MAX_LENGTH) || !Array.isArray(value.options) || value.options.length < COMPANION_DECISION_OPTIONS_MIN || value.options.length > COMPANION_DECISION_OPTIONS_MAX) {
36539
+ if (!isRecord6(value) || !isBoundedPlainString(value.callId, COMPANION_DECISION_CALL_ID_MAX_LENGTH) || !isBoundedPlainString(value.title, COMPANION_DECISION_TITLE_MAX_LENGTH) || !Array.isArray(value.options) || value.options.length < COMPANION_DECISION_OPTIONS_MIN || value.options.length > COMPANION_DECISION_OPTIONS_MAX) {
36439
36540
  return eventError();
36440
36541
  }
36441
36542
  const options = value.options.map((option) => {
36442
- if (!isRecord5(option) || !hasExactKeys(option, ["label", "detail"]) || !isBoundedPlainString(option.label, COMPANION_DECISION_LABEL_MAX_LENGTH) || !isBoundedMessageText(option.detail, COMPANION_DECISION_DETAIL_MAX_CODE_POINTS)) {
36543
+ if (!isRecord6(option) || !hasExactKeys(option, ["label", "detail"]) || !isBoundedPlainString(option.label, COMPANION_DECISION_LABEL_MAX_LENGTH) || !isBoundedMessageText(option.detail, COMPANION_DECISION_DETAIL_MAX_CODE_POINTS)) {
36443
36544
  return eventError();
36444
36545
  }
36445
36546
  return { label: option.label, detail: option.detail };
@@ -36457,7 +36558,7 @@ function parseDecision(value) {
36457
36558
  return { ...base, status: "selected", optionIndex: value.optionIndex };
36458
36559
  }
36459
36560
  function parseArtifact(value) {
36460
- if (!isRecord5(value) || !isBoundedPlainString(value.name, COMPANION_ARTIFACT_NAME_MAX_LENGTH)) {
36561
+ if (!isRecord6(value) || !isBoundedPlainString(value.name, COMPANION_ARTIFACT_NAME_MAX_LENGTH)) {
36461
36562
  return eventError();
36462
36563
  }
36463
36564
  if (value.sizeBytes === void 0) {
@@ -36476,7 +36577,7 @@ function parseTurnArtifacts(value) {
36476
36577
  return value.map(parseArtifact);
36477
36578
  }
36478
36579
  function parseTurn(value) {
36479
- if (!isRecord5(value) || !isBoundedPlainString(value.id, COMPANION_TURN_ID_MAX_LENGTH) || value.role !== "user" && value.role !== "mate" || !isInstantOrNull(value.at)) {
36580
+ if (!isRecord6(value) || !isBoundedPlainString(value.id, COMPANION_TURN_ID_MAX_LENGTH) || value.role !== "user" && value.role !== "mate" || !isInstantOrNull(value.at)) {
36480
36581
  return eventError();
36481
36582
  }
36482
36583
  const keys = [
@@ -36555,7 +36656,7 @@ function isValidMateRoute(value) {
36555
36656
  }
36556
36657
  }
36557
36658
  function parseRequest(value) {
36558
- if (!isRecord5(value)) return requestError();
36659
+ if (!isRecord6(value)) return requestError();
36559
36660
  if (value.type === "roster") {
36560
36661
  if (!hasExactKeys(value, ["type"])) return requestError();
36561
36662
  return { type: "roster" };
@@ -36621,7 +36722,7 @@ function parseRequestLine(line2) {
36621
36722
  }
36622
36723
  }
36623
36724
  function parseMate(value) {
36624
- if (!isRecord5(value) || !hasExactKeys(value, [
36725
+ if (!isRecord6(value) || !hasExactKeys(value, [
36625
36726
  "personaKey",
36626
36727
  "agentName",
36627
36728
  "displayName",
@@ -36646,7 +36747,7 @@ function parseMate(value) {
36646
36747
  };
36647
36748
  }
36648
36749
  function parseEvent(value) {
36649
- if (!isRecord5(value)) return eventError();
36750
+ if (!isRecord6(value)) return eventError();
36650
36751
  if (value.type === "update") {
36651
36752
  if (!hasExactKeys(value, ["type", "installed", "available", "severity"]) || !isVersionOrNull(value.installed) || !isVersionOrNull(value.available) || !(value.severity === null || SEVERITIES2.has(value.severity))) {
36652
36753
  return eventError();
@@ -36785,7 +36886,7 @@ var PredispatchFailure = class extends Error {
36785
36886
  }
36786
36887
  reason;
36787
36888
  };
36788
- function isRecord6(value) {
36889
+ function isRecord7(value) {
36789
36890
  return typeof value === "object" && value !== null && !Array.isArray(value);
36790
36891
  }
36791
36892
  function hasControlCharacter(value) {
@@ -36855,16 +36956,16 @@ async function readJsonEnvelope(response) {
36855
36956
  if (error instanceof PredispatchFailure) throw error;
36856
36957
  throw new PredispatchFailure("not-connected");
36857
36958
  }
36858
- if (!isRecord6(envelope) || envelope.ok !== true || !("data" in envelope)) {
36959
+ if (!isRecord7(envelope) || envelope.ok !== true || !("data" in envelope)) {
36859
36960
  throw new PredispatchFailure("not-connected");
36860
36961
  }
36861
36962
  return envelope.data;
36862
36963
  }
36863
36964
  function decodeAgents(data) {
36864
- if (!isRecord6(data) || !Array.isArray(data.agents)) {
36965
+ if (!isRecord7(data) || !Array.isArray(data.agents)) {
36865
36966
  throw new PredispatchFailure("mate-unavailable");
36866
36967
  }
36867
- return data.agents.filter(isRecord6);
36968
+ return data.agents.filter(isRecord7);
36868
36969
  }
36869
36970
  function resolveAgentName(agents, personaKey) {
36870
36971
  const matches = agents.filter((agent) => agent.personaKey === personaKey);
@@ -36884,18 +36985,18 @@ function requireAgentName(agents, personaKey) {
36884
36985
  return name;
36885
36986
  }
36886
36987
  function decodeConversationId(data) {
36887
- if (!isRecord6(data) || typeof data.id !== "string" || !OPAQUE_ID.test(data.id)) {
36988
+ if (!isRecord7(data) || typeof data.id !== "string" || !OPAQUE_ID.test(data.id)) {
36888
36989
  throw new PredispatchFailure("not-connected");
36889
36990
  }
36890
36991
  return data.id;
36891
36992
  }
36892
36993
  function decodeLastMessageId(data) {
36893
- if (!isRecord6(data) || !Array.isArray(data.messages)) {
36994
+ if (!isRecord7(data) || !Array.isArray(data.messages)) {
36894
36995
  throw new PredispatchFailure("not-connected");
36895
36996
  }
36896
36997
  const messages = data.messages;
36897
36998
  const last = messages.at(-1);
36898
- if (!isRecord6(last) || typeof last.id !== "string" || !OPAQUE_ID.test(last.id)) {
36999
+ if (!isRecord7(last) || typeof last.id !== "string" || !OPAQUE_ID.test(last.id)) {
36899
37000
  return void 0;
36900
37001
  }
36901
37002
  return last.id;
@@ -36981,7 +37082,7 @@ function toCompanionArtifacts(data) {
36981
37082
  const artifacts = [];
36982
37083
  for (const entry of data) {
36983
37084
  if (artifacts.length >= COMPANION_ARTIFACTS_MAX) break;
36984
- if (!isRecord6(entry) || typeof entry.name !== "string") continue;
37085
+ if (!isRecord7(entry) || typeof entry.name !== "string") continue;
36985
37086
  const name = boundPlainLine(entry.name, COMPANION_ARTIFACT_NAME_MAX_LENGTH);
36986
37087
  if (name.length === 0) continue;
36987
37088
  const size = entry.size_bytes;
@@ -36995,12 +37096,12 @@ function decodeMessageInstant(value) {
36995
37096
  return typeof value === "number" && Number.isFinite(value) && value > 0 && value < EPOCH_SECONDS_LIMIT ? new Date(Math.round(value) * 1e3).toISOString() : null;
36996
37097
  }
36997
37098
  function decodeTurns(data, limit2) {
36998
- if (!isRecord6(data) || !Array.isArray(data.messages)) {
37099
+ if (!isRecord7(data) || !Array.isArray(data.messages)) {
36999
37100
  throw new PredispatchFailure("not-connected");
37000
37101
  }
37001
37102
  const turns = [];
37002
37103
  for (const entry of data.messages) {
37003
- if (!isRecord6(entry)) continue;
37104
+ if (!isRecord7(entry)) continue;
37004
37105
  if (entry.role !== "user" && entry.role !== "assistant") continue;
37005
37106
  if (typeof entry.id !== "string" || !OPAQUE_ID.test(entry.id)) continue;
37006
37107
  if (typeof entry.content !== "string") continue;
@@ -37027,12 +37128,12 @@ function decodeDurableDecision(entry) {
37027
37128
  return toCompanionDecision(frame.directive);
37028
37129
  }
37029
37130
  function decodeRichTurns(data, limit2) {
37030
- if (!isRecord6(data) || !Array.isArray(data.messages)) {
37131
+ if (!isRecord7(data) || !Array.isArray(data.messages)) {
37031
37132
  throw new PredispatchFailure("not-connected");
37032
37133
  }
37033
37134
  const turns = [];
37034
37135
  for (const entry of data.messages) {
37035
- if (!isRecord6(entry)) continue;
37136
+ if (!isRecord7(entry)) continue;
37036
37137
  if (entry.role !== "user" && entry.role !== "assistant") continue;
37037
37138
  if (typeof entry.id !== "string" || !OPAQUE_ID.test(entry.id)) continue;
37038
37139
  if (typeof entry.content !== "string") continue;
@@ -37180,7 +37281,7 @@ async function drainAcceptedSse(response) {
37180
37281
  continue;
37181
37282
  }
37182
37283
  const parsed = JSON.parse(data);
37183
- if (!isRecord6(parsed) || typeof parsed.type !== "string" || parsed.type === "error") {
37284
+ if (!isRecord7(parsed) || typeof parsed.type !== "string" || parsed.type === "error") {
37184
37285
  throw new Error("invalid stream event");
37185
37286
  }
37186
37287
  }
@@ -37228,7 +37329,7 @@ async function streamAcceptedSse(response, now, onText, onData) {
37228
37329
  return;
37229
37330
  }
37230
37331
  const parsed = JSON.parse(data);
37231
- if (!isRecord6(parsed) || typeof parsed.type !== "string" || parsed.type === "error") {
37332
+ if (!isRecord7(parsed) || typeof parsed.type !== "string" || parsed.type === "error") {
37232
37333
  throw new Error("invalid stream event");
37233
37334
  }
37234
37335
  if (parsed.type === "text-delta" && typeof parsed.delta === "string" && parsed.delta.length > 0) {
@@ -37452,7 +37553,7 @@ async function classifyDecideRefusal(response) {
37452
37553
  let reason;
37453
37554
  try {
37454
37555
  const envelope = JSON.parse(await readBoundedText(response));
37455
- if (isRecord6(envelope) && isRecord6(envelope.error) && isRecord6(envelope.error.details)) {
37556
+ if (isRecord7(envelope) && isRecord7(envelope.error) && isRecord7(envelope.error.details)) {
37456
37557
  reason = envelope.error.details.reason;
37457
37558
  }
37458
37559
  } catch {