@m8t-stack/cli 0.2.20 → 0.2.21

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
@@ -1157,6 +1157,10 @@ async function enableHostedBrain(args) {
1157
1157
  memory: def.memory,
1158
1158
  env,
1159
1159
  metadata: {
1160
+ // Spread the current metadata first so unmanaged keys (a2a, a2aCard, …)
1161
+ // survive the relink version; the managed fields are re-asserted over the
1162
+ // spread, and createCoderVersion applies the `brain` arg last.
1163
+ ...current.metadata,
1160
1164
  source: "m8t-stack-POC",
1161
1165
  kind: "hosted",
1162
1166
  persona: current.metadata?.persona ?? "coding-agent",
@@ -1227,7 +1231,7 @@ var init_enable_hosted_brain = __esm({
1227
1231
  import { Builtins, Cli } from "clipanion";
1228
1232
 
1229
1233
  // src/lib/package-version.ts
1230
- var CLI_VERSION = "0.2.20";
1234
+ var CLI_VERSION = "0.2.21";
1231
1235
 
1232
1236
  // src/lib/render-error.ts
1233
1237
  init_errors();
@@ -22568,7 +22572,7 @@ init_errors();
22568
22572
  // ../../packages/brain/engine/dist/esm/types.js
22569
22573
  var ENGINE_VERSION = "0.1.0";
22570
22574
  var DEFAULT_SAFETY_LAG_SECONDS = 3600;
22571
- var SOURCES = ["webapp", "a2a", "mcp", "telegram"];
22575
+ var SOURCES = ["webapp", "a2a", "mcp", "telegram", "voice-relay"];
22572
22576
  var WORKER_ALIASES = { "azure-advisor": "azzy" };
22573
22577
  function canonicalWorker(pk) {
22574
22578
  const lower = pk.toLowerCase();
@@ -22632,9 +22636,11 @@ var TableCursor = class {
22632
22636
  throw e;
22633
22637
  }
22634
22638
  const watermarks = row.watermarks ? JSON.parse(row.watermarks) : {};
22639
+ const fetchFailures = row.fetchFailures ? JSON.parse(row.fetchFailures) : void 0;
22635
22640
  return {
22636
22641
  worker: canonical,
22637
22642
  watermarks,
22643
+ ...fetchFailures && Object.keys(fetchFailures).length > 0 ? { fetchFailures } : {},
22638
22644
  safetyLagSeconds: row.safetyLagSeconds ?? DEFAULT_SAFETY_LAG_SECONDS,
22639
22645
  engineVersion: row.engineVersion ?? ENGINE_VERSION,
22640
22646
  ...row.lastDreamAt ? { lastDreamAt: row.lastDreamAt } : {}
@@ -22657,9 +22663,12 @@ var TableCursor = class {
22657
22663
  safetyLagSeconds: cursor.safetyLagSeconds,
22658
22664
  engineVersion: cursor.engineVersion
22659
22665
  };
22666
+ if (cursor.fetchFailures && Object.keys(cursor.fetchFailures).length > 0) {
22667
+ entity.fetchFailures = JSON.stringify(cursor.fetchFailures);
22668
+ }
22660
22669
  if (cursor.lastDreamAt)
22661
22670
  entity.lastDreamAt = cursor.lastDreamAt;
22662
- await this.client.upsertEntity(entity);
22671
+ await this.client.upsertEntity(entity, "Replace");
22663
22672
  }
22664
22673
  async ensureTable() {
22665
22674
  try {
@@ -22695,9 +22704,22 @@ function computeWatermark(rows, now, safetyLagSeconds) {
22695
22704
  }
22696
22705
  async function commitCursorAdvance(plan, cursor) {
22697
22706
  const prior = await cursor.read(plan.worker);
22707
+ const watermarks = {};
22708
+ for (const [pk, watermark] of Object.entries(plan.watermarks)) {
22709
+ const priorWatermark = Object.hasOwn(prior.watermarks, pk) ? prior.watermarks[pk] : void 0;
22710
+ if (priorWatermark && watermark.ts <= priorWatermark.ts) {
22711
+ watermarks[pk] = {
22712
+ ts: watermark.ts,
22713
+ consumedRowKeys: [.../* @__PURE__ */ new Set([...priorWatermark.consumedRowKeys, ...watermark.consumedRowKeys])]
22714
+ };
22715
+ } else {
22716
+ watermarks[pk] = watermark;
22717
+ }
22718
+ }
22698
22719
  const next = {
22699
22720
  worker: plan.worker,
22700
- watermarks: plan.watermarks,
22721
+ watermarks,
22722
+ ...plan.fetchFailures && Object.keys(plan.fetchFailures).length > 0 ? { fetchFailures: plan.fetchFailures } : {},
22701
22723
  safetyLagSeconds: prior.safetyLagSeconds || DEFAULT_SAFETY_LAG_SECONDS,
22702
22724
  engineVersion: ENGINE_VERSION,
22703
22725
  lastDreamAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -22951,6 +22973,7 @@ function normalize(group, items, enrichment) {
22951
22973
 
22952
22974
  // ../../packages/brain/engine/dist/esm/pipeline.js
22953
22975
  var isKnownSource = (s) => SOURCES.includes(s);
22976
+ var MAX_CONV_FETCH_ATTEMPTS = 3;
22954
22977
  async function runPipeline(args) {
22955
22978
  const { worker, sources, now, since, reset } = args;
22956
22979
  const monotonicNow = args.monotonicNow ?? Date.now;
@@ -22977,6 +23000,7 @@ async function runPipeline(args) {
22977
23000
  let recovered = 0;
22978
23001
  const consumedRowsByPk = {};
22979
23002
  const failedTsByPk = {};
23003
+ const newFailures = {};
22980
23004
  const window2 = windowFor(rows, now, since);
22981
23005
  for (const g of groups) {
22982
23006
  const pk = g.worker;
@@ -23067,8 +23091,17 @@ async function runPipeline(args) {
23067
23091
  else
23068
23092
  recovered += 1;
23069
23093
  } else {
23070
- skips.addSkip(outcome, sampleId(g), fetchError?.message);
23071
- if (outcome === "conv-fetch-failed" || outcome === "auth-failed") {
23094
+ let lastError = fetchError?.message;
23095
+ if (outcome === "conv-fetch-failed") {
23096
+ const id = conversationId ?? "";
23097
+ const next = (cursor.fetchFailures?.[id] ?? 0) + 1;
23098
+ newFailures[id] = next;
23099
+ if (next >= MAX_CONV_FETCH_ATTEMPTS) {
23100
+ lastError = `terminal after ${String(next)} cycles \u2014 watermark released`;
23101
+ }
23102
+ }
23103
+ skips.addSkip(outcome, sampleId(g), lastError);
23104
+ if (outcome === "auth-failed" || outcome === "conv-fetch-failed" && conversationId && newFailures[conversationId] < MAX_CONV_FETCH_ATTEMPTS) {
23072
23105
  const cur = failedTsByPk[pk];
23073
23106
  if (!cur || g.startedAt < cur)
23074
23107
  failedTsByPk[pk] = g.startedAt;
@@ -23088,7 +23121,7 @@ async function runPipeline(args) {
23088
23121
  latencyMs: Math.round(monotonicNow() - t0)
23089
23122
  };
23090
23123
  assertInvariant(stats, groups.length);
23091
- const advance = buildAdvancePlan(target, cursor, physicalPks, consumedRowsByPk, failedTsByPk, now, safetyLag);
23124
+ const advance = buildAdvancePlan(target, cursor, physicalPks, consumedRowsByPk, failedTsByPk, newFailures, now, safetyLag);
23092
23125
  const out = {
23093
23126
  worker: target,
23094
23127
  window: window2,
@@ -23167,7 +23200,7 @@ function windowFor(rows, now, since) {
23167
23200
  from = r.eventTimestamp;
23168
23201
  return { from, to };
23169
23202
  }
23170
- function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedTsByPk, now, safetyLagSeconds) {
23203
+ function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedTsByPk, fetchFailures, now, safetyLagSeconds) {
23171
23204
  const watermarks = {};
23172
23205
  const consumedKeysByPk = {};
23173
23206
  const priorTsByPk = {};
@@ -23191,6 +23224,7 @@ function buildAdvancePlan(worker, cursor, physicalPks, consumedRowsByPk, failedT
23191
23224
  watermarks,
23192
23225
  consumedRowsByPk: consumedKeysByPk,
23193
23226
  failedTsByPk,
23227
+ ...Object.keys(fetchFailures).length > 0 ? { fetchFailures } : {},
23194
23228
  now: now.toISOString(),
23195
23229
  safetyLagSeconds,
23196
23230
  priorTsByPk
@@ -24183,6 +24217,7 @@ function narrowAdvance(src, kept) {
24183
24217
  watermarks,
24184
24218
  consumedRowsByPk,
24185
24219
  failedTsByPk: src.failedTsByPk,
24220
+ ...src.fetchFailures ? { fetchFailures: src.fetchFailures } : {},
24186
24221
  now,
24187
24222
  safetyLagSeconds,
24188
24223
  priorTsByPk
@@ -24200,7 +24235,13 @@ function filterAdvance(src, keptRowsByPk) {
24200
24235
  consumedRowsByPk[pk] = (src.consumedRowsByPk[pk] ?? []).filter((rk) => keep.has(rk));
24201
24236
  watermarks[pk] = { ts: wm.ts, consumedRowKeys: wm.consumedRowKeys.filter((rk) => keep.has(rk)) };
24202
24237
  }
24203
- return { worker: src.worker, watermarks, consumedRowsByPk, failedTsByPk: src.failedTsByPk };
24238
+ return {
24239
+ worker: src.worker,
24240
+ watermarks,
24241
+ consumedRowsByPk,
24242
+ failedTsByPk: src.failedTsByPk,
24243
+ ...src.fetchFailures ? { fetchFailures: src.fetchFailures } : {}
24244
+ };
24204
24245
  }
24205
24246
 
24206
24247
  // ../../packages/brain/engine/dist/esm/dream/index.js
@@ -24218,6 +24259,18 @@ async function runDream(input, deps, seams = defaultDreamSeams()) {
24218
24259
  });
24219
24260
  }
24220
24261
  input = capped;
24262
+ if (input.conversations.length === 0) {
24263
+ await commitCursorAdvance(input.advance, deps.cursor);
24264
+ deps.logger.info({
24265
+ at: "runDream",
24266
+ worker: input.worker,
24267
+ terminal: "no-corpus",
24268
+ skipped: input.stats.skipped,
24269
+ advanced: true,
24270
+ skipLedger: input.skipLedger.map((s) => `${s.reason}:${String(s.count)}`)
24271
+ });
24272
+ return { worker: input.worker, applied: [], digest, advanced: true };
24273
+ }
24221
24274
  const proposed = await seams.propose(input, deps);
24222
24275
  digest.push({ kind: "cost", model: proposed.cost.model, inputTokens: proposed.cost.inputTokens, outputTokens: proposed.cost.outputTokens, ms: proposed.cost.ms });
24223
24276
  if (!proposed.deltas) {
@@ -26439,6 +26492,7 @@ function writeWebEnvLocal(args) {
26439
26492
  `AZURE_TENANT_ID=${args.tenantId}`,
26440
26493
  `AZURE_CLIENT_ID=${args.clientId}`,
26441
26494
  `FOUNDRY_PROJECT_ENDPOINT=${args.foundryEndpoint}`,
26495
+ "VOICE_RELAY_PUBLIC_URL=ws://localhost:8790",
26442
26496
  "STORAGE_ACCOUNT_NAME=",
26443
26497
  "M8T_DISABLE_WORKER=1",
26444
26498
  "M8T_ONBOARDING=1",
@@ -26493,11 +26547,16 @@ function onboardingUiPaths(home = os17.homedir()) {
26493
26547
  pidPath: path35.join(dir, "onboarding-ui.pid")
26494
26548
  };
26495
26549
  }
26496
- async function serveOnboardingUiDetached(args) {
26497
- const { logPath, pidPath } = onboardingUiPaths();
26498
- const portNum = Number(args.port);
26499
- const isPortOpen = () => new Promise((resolve3) => {
26500
- const s = net.createConnection({ host: "127.0.0.1", port: portNum });
26550
+ function onboardingRelayPaths(home = os17.homedir()) {
26551
+ const dir = path35.join(home, ".m8t-stack");
26552
+ return {
26553
+ logPath: path35.join(dir, "onboarding-relay.log"),
26554
+ pidPath: path35.join(dir, "onboarding-relay.pid")
26555
+ };
26556
+ }
26557
+ function isLocalPortOpen(port) {
26558
+ return new Promise((resolve3) => {
26559
+ const s = net.createConnection({ host: "127.0.0.1", port });
26501
26560
  s.setTimeout(1e3);
26502
26561
  s.on("connect", () => {
26503
26562
  s.destroy();
@@ -26511,6 +26570,11 @@ async function serveOnboardingUiDetached(args) {
26511
26570
  resolve3(false);
26512
26571
  });
26513
26572
  });
26573
+ }
26574
+ async function serveOnboardingUiDetached(args) {
26575
+ const { logPath, pidPath } = onboardingUiPaths();
26576
+ const portNum = Number(args.port);
26577
+ const isPortOpen = () => isLocalPortOpen(portNum);
26514
26578
  if (await isPortOpen()) {
26515
26579
  return { alreadyRunning: true, logPath };
26516
26580
  }
@@ -26541,6 +26605,46 @@ async function serveOnboardingUiDetached(args) {
26541
26605
  }
26542
26606
  return { alreadyRunning: false, logPath };
26543
26607
  }
26608
+ async function serveOnboardingRelayDetached(args) {
26609
+ const { logPath, pidPath } = onboardingRelayPaths();
26610
+ const portNum = 8790;
26611
+ if (await isLocalPortOpen(portNum)) {
26612
+ return { alreadyRunning: true, logPath };
26613
+ }
26614
+ fs32.mkdirSync(path35.dirname(logPath), { recursive: true });
26615
+ const fd = fs32.openSync(logPath, "a");
26616
+ const child = spawn7("pnpm", ["--filter", "web", "exec", "tsx", "voice-relay-entry.ts"], {
26617
+ cwd: args.repoRoot,
26618
+ detached: true,
26619
+ stdio: ["ignore", fd, fd],
26620
+ env: {
26621
+ ...process.env,
26622
+ FOUNDRY_PROJECT_ENDPOINT: args.foundryEndpoint,
26623
+ AZURE_TENANT_ID: args.tenantId,
26624
+ AZURE_CLIENT_ID: args.clientId,
26625
+ RELAY_ALLOWED_ORIGINS: "http://localhost:3000",
26626
+ RELAY_PORT: "8790"
26627
+ },
26628
+ shell: false
26629
+ });
26630
+ fs32.closeSync(fd);
26631
+ if (child.pid == null) {
26632
+ throw new LocalCliError({
26633
+ code: "BOOTSTRAP_UI_RELAY_SPAWN_FAILED",
26634
+ message: "Could not start the voice relay (pnpm did not spawn).",
26635
+ hint: "Check that pnpm + Node 20+ are installed; see the log at " + logPath + "."
26636
+ });
26637
+ }
26638
+ child.unref();
26639
+ fs32.writeFileSync(pidPath, String(child.pid), "utf8");
26640
+ const deadline = Date.now() + 45e3;
26641
+ const sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
26642
+ while (Date.now() < deadline) {
26643
+ await sleep3(500);
26644
+ if (await isLocalPortOpen(portNum)) break;
26645
+ }
26646
+ return { alreadyRunning: false, logPath };
26647
+ }
26544
26648
  function autoOpenOnboardingUi(url, open = tryOpenUrl) {
26545
26649
  try {
26546
26650
  const result = open(url);
@@ -26551,8 +26655,7 @@ function autoOpenOnboardingUi(url, open = tryOpenUrl) {
26551
26655
  } catch {
26552
26656
  }
26553
26657
  }
26554
- function stopOnboardingUi(home = os17.homedir()) {
26555
- const { pidPath } = onboardingUiPaths(home);
26658
+ function stopPidFile(pidPath) {
26556
26659
  let pidStr;
26557
26660
  try {
26558
26661
  pidStr = fs32.readFileSync(pidPath, "utf8").trim();
@@ -26573,6 +26676,11 @@ function stopOnboardingUi(home = os17.homedir()) {
26573
26676
  }
26574
26677
  return true;
26575
26678
  }
26679
+ function stopOnboardingUi(home = os17.homedir()) {
26680
+ const uiStopped = stopPidFile(onboardingUiPaths(home).pidPath);
26681
+ const relayStopped = stopPidFile(onboardingRelayPaths(home).pidPath);
26682
+ return uiStopped || relayStopped;
26683
+ }
26576
26684
 
26577
26685
  // src/lib/simple-stacey.ts
26578
26686
  var SIMPLE_STACEY_PERSONA = "startup-advisor-intake";
@@ -26734,10 +26842,26 @@ var BootstrapUiCommand = class extends M8tCommand {
26734
26842
  return 0;
26735
26843
  }
26736
26844
  if (this.foreground === true) {
26845
+ out("starting the voice relay on :8790 in the background\u2026");
26846
+ await serveOnboardingRelayDetached({
26847
+ repoRoot,
26848
+ foundryEndpoint: endpoint,
26849
+ tenantId: account.tenantId,
26850
+ clientId: state.appRegClientId
26851
+ });
26852
+ out("voice relay on :8790");
26737
26853
  out("starting the webapp on :3000 (Ctrl-C to stop)\u2026");
26738
26854
  await runInherit("pnpm", ["--filter", "web", "dev"], repoRoot, "BOOTSTRAP_UI_DEV_FAILED");
26739
26855
  return 0;
26740
26856
  }
26857
+ out("starting the voice relay on :8790 in the background\u2026");
26858
+ await serveOnboardingRelayDetached({
26859
+ repoRoot,
26860
+ foundryEndpoint: endpoint,
26861
+ tenantId: account.tenantId,
26862
+ clientId: state.appRegClientId
26863
+ });
26864
+ out("voice relay on :8790");
26741
26865
  out("starting the webapp on :3000 in the background\u2026");
26742
26866
  const { alreadyRunning, logPath } = await serveOnboardingUiDetached({ repoRoot, port: this.port });
26743
26867
  if (alreadyRunning) {