@m8t-stack/cli 0.2.68 → 0.2.69

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
@@ -1364,7 +1364,7 @@ var init_enable_hosted_brain = __esm({
1364
1364
  import { Builtins, Cli } from "clipanion";
1365
1365
 
1366
1366
  // src/lib/package-version.ts
1367
- var CLI_VERSION = "0.2.68";
1367
+ var CLI_VERSION = "0.2.69";
1368
1368
 
1369
1369
  // src/lib/render-error.ts
1370
1370
  init_errors();
@@ -29792,7 +29792,7 @@ function renderFounderRecord(block, inputs, now = (/* @__PURE__ */ new Date()).t
29792
29792
  const subscription = (inputs.subscriptionId ?? "").trim();
29793
29793
  const advisorRendered = advisorName || advisorEmail ? [advisorName, advisorEmail ? `<${advisorEmail}>` : ""].filter(Boolean).join(" ") : NOT_CAPTURED;
29794
29794
  const request = block.pending_requests?.[0];
29795
- const requestLines = request === void 0 ? [] : (() => {
29795
+ const requestLines2 = request === void 0 ? [] : (() => {
29796
29796
  const modelLabel = request.model.trim() ? `\`${request.model.trim()}\`` : "(model not recorded)";
29797
29797
  const consentLabel = request.consent === "submit" ? "submit the request" : "prepare it only, don't submit";
29798
29798
  const addressLine = request.company_address === null ? "not provided \u2014 the founder skipped it" : [
@@ -29832,7 +29832,7 @@ function renderFounderRecord(block, inputs, now = (/* @__PURE__ */ new Date()).t
29832
29832
  `- **Microsoft Startup Advisor (SA):** ${advisorRendered}`,
29833
29833
  `- **Azure subscription:** ${subscription || NOT_CAPTURED}`,
29834
29834
  ...bullet("Team size", block.team_size),
29835
- ...requestLines,
29835
+ ...requestLines2,
29836
29836
  ``
29837
29837
  ].join("\n");
29838
29838
  const idxAdvisor = advisorEmail || advisorName || "\u2014";
@@ -33165,7 +33165,7 @@ var TelemetryEnrollCommand = class extends M8tCommand {
33165
33165
  };
33166
33166
 
33167
33167
  // src/commands/companion/bridge.ts
33168
- import { Command as Command61 } from "clipanion";
33168
+ import { Command as Command61, Option as Option58 } from "clipanion";
33169
33169
 
33170
33170
  // ../../packages/companion-bridge-contract/src/index.ts
33171
33171
  var COMPANION_MESSAGE_MAX_CODE_POINTS = 32768;
@@ -33719,7 +33719,7 @@ async function rosterCompanions(sink, deps = {}) {
33719
33719
  const { controller, timer } = createDeadline(deps);
33720
33720
  try {
33721
33721
  const { token, origin } = await acquireContext(deps);
33722
- const agents = await fetchAgents(
33722
+ const agents = await (deps.fetchAgents ?? fetchAgents)(
33723
33723
  deps.fetch ?? fetch,
33724
33724
  origin,
33725
33725
  token,
@@ -33871,14 +33871,14 @@ async function dispatchConversation(request, sink, deps, consume, readDesktopMar
33871
33871
  try {
33872
33872
  const { token, origin } = await acquireContext(deps);
33873
33873
  const headers = authenticatedHeaders(token);
33874
- const agents = await fetchAgents(
33874
+ const agents = await (deps.fetchAgents ?? fetchAgents)(
33875
33875
  fetchImpl,
33876
33876
  origin,
33877
33877
  token,
33878
33878
  controller.signal
33879
33879
  );
33880
33880
  const agentName = resolveAgentName(agents, request.personaKey);
33881
- const conversationId = await resolveConversationId(
33881
+ const conversationId = await (deps.resolveConversationId ?? resolveConversationId)(
33882
33882
  fetchImpl,
33883
33883
  origin,
33884
33884
  headers,
@@ -33982,14 +33982,14 @@ async function historyCompanionMessages(request, sink, deps = {}) {
33982
33982
  try {
33983
33983
  const { token, origin } = await acquireContext(deps);
33984
33984
  const headers = authenticatedHeaders(token);
33985
- const agents = await fetchAgents(
33985
+ const agents = await (deps.fetchAgents ?? fetchAgents)(
33986
33986
  fetchImpl,
33987
33987
  origin,
33988
33988
  token,
33989
33989
  controller.signal
33990
33990
  );
33991
33991
  const agentName = resolveAgentName(agents, request.personaKey);
33992
- const conversationId = await resolveConversationId(
33992
+ const conversationId = await (deps.resolveConversationId ?? resolveConversationId)(
33993
33993
  fetchImpl,
33994
33994
  origin,
33995
33995
  headers,
@@ -34042,6 +34042,182 @@ function companionUpdateAvailable(update) {
34042
34042
  return update.available !== null && update.available !== update.installed;
34043
34043
  }
34044
34044
 
34045
+ // src/lib/companion-bridge-serve.ts
34046
+ var TOKEN_TTL_MS = 10 * 6e4;
34047
+ var CONTEXT_TTL_MS = 5 * 6e4;
34048
+ var STALE_CONTEXT_REASONS = /* @__PURE__ */ new Set([
34049
+ "not-authorized",
34050
+ "not-connected",
34051
+ "mate-unavailable"
34052
+ ]);
34053
+ var ServeContext = class {
34054
+ constructor(now, base) {
34055
+ this.now = now;
34056
+ this.base = base;
34057
+ }
34058
+ now;
34059
+ base;
34060
+ token = null;
34061
+ agents = /* @__PURE__ */ new Map();
34062
+ conversations = /* @__PURE__ */ new Map();
34063
+ cacheServed = false;
34064
+ /** Starts a request (or a retry) with a clean served-from-cache slate. */
34065
+ beginRequest() {
34066
+ this.cacheServed = false;
34067
+ }
34068
+ /** Whether the request in flight consumed anything cached. */
34069
+ servedFromCache() {
34070
+ return this.cacheServed;
34071
+ }
34072
+ /** Drops every held value so the next resolution starts from nothing. */
34073
+ invalidate() {
34074
+ this.token = null;
34075
+ this.agents.clear();
34076
+ this.conversations.clear();
34077
+ }
34078
+ fresh(entry, ttl) {
34079
+ return entry !== null && entry !== void 0 && this.now() - entry.at < ttl;
34080
+ }
34081
+ /** The chat dependencies with the caching wrappers layered in. */
34082
+ chatDeps() {
34083
+ return {
34084
+ ...this.base,
34085
+ getFoundryToken: async () => {
34086
+ if (this.fresh(this.token, TOKEN_TTL_MS)) {
34087
+ this.cacheServed = true;
34088
+ return this.token.value;
34089
+ }
34090
+ const value = await (this.base.getFoundryToken ?? getFoundryToken)();
34091
+ this.token = { value, at: this.now() };
34092
+ return value;
34093
+ },
34094
+ fetchAgents: async (fetchImpl, origin, token, signal) => {
34095
+ const held = this.agents.get(origin);
34096
+ if (this.fresh(held, CONTEXT_TTL_MS)) {
34097
+ this.cacheServed = true;
34098
+ return held.value;
34099
+ }
34100
+ const value = await (this.base.fetchAgents ?? fetchAgents)(
34101
+ fetchImpl,
34102
+ origin,
34103
+ token,
34104
+ signal
34105
+ );
34106
+ this.agents.set(origin, { value, at: this.now() });
34107
+ return value;
34108
+ },
34109
+ resolveConversationId: async (fetchImpl, origin, headers, agentName, signal) => {
34110
+ const key2 = `${origin} ${agentName}`;
34111
+ const held = this.conversations.get(key2);
34112
+ if (this.fresh(held, CONTEXT_TTL_MS)) {
34113
+ this.cacheServed = true;
34114
+ return held.value;
34115
+ }
34116
+ const value = await (this.base.resolveConversationId ?? resolveConversationId)(
34117
+ fetchImpl,
34118
+ origin,
34119
+ headers,
34120
+ agentName,
34121
+ signal
34122
+ );
34123
+ this.conversations.set(key2, { value, at: this.now() });
34124
+ return value;
34125
+ }
34126
+ };
34127
+ }
34128
+ };
34129
+ async function* requestLines(stdin) {
34130
+ stdin.setEncoding("utf8");
34131
+ let buffered = "";
34132
+ for await (const chunk of stdin) {
34133
+ buffered += String(chunk);
34134
+ for (; ; ) {
34135
+ const breakAt = buffered.indexOf("\n");
34136
+ if (breakAt === -1) break;
34137
+ const line2 = buffered.slice(0, breakAt).replace(/\r$/u, "");
34138
+ buffered = buffered.slice(breakAt + 1);
34139
+ yield line2;
34140
+ }
34141
+ if (buffered.length > COMPANION_BRIDGE_LINE_MAX_LENGTH + 1) {
34142
+ throw new Error("request exceeds bridge bound");
34143
+ }
34144
+ }
34145
+ if (buffered.length > 0) yield buffered.replace(/\r$/u, "");
34146
+ }
34147
+ async function dispatchRequest(request, sink, handlers) {
34148
+ if (request.type === "roster") return handlers.roster(sink);
34149
+ if (request.type === "update") {
34150
+ const terminal = await handlers.update();
34151
+ sink(terminal);
34152
+ return terminal;
34153
+ }
34154
+ if (request.type === "history") return handlers.history(request, sink);
34155
+ if (request.type === "converse") return handlers.converse(request, sink);
34156
+ return handlers.send(request, sink);
34157
+ }
34158
+ async function handleWithContext(request, sink, handlers, context) {
34159
+ context.beginRequest();
34160
+ const held = { failure: null, streamed: false };
34161
+ const firstAttempt = (event) => {
34162
+ if (!held.streamed && held.failure === null && event.type === "failed" && STALE_CONTEXT_REASONS.has(event.reason) && context.servedFromCache()) {
34163
+ held.failure = event;
34164
+ return;
34165
+ }
34166
+ held.streamed = true;
34167
+ if (held.failure !== null) {
34168
+ sink(held.failure);
34169
+ held.failure = null;
34170
+ }
34171
+ sink(event);
34172
+ };
34173
+ const terminal = await dispatchRequest(request, firstAttempt, handlers);
34174
+ if (held.failure === null) {
34175
+ if (terminal.type === "indeterminate" && context.servedFromCache()) {
34176
+ context.invalidate();
34177
+ }
34178
+ return;
34179
+ }
34180
+ context.invalidate();
34181
+ context.beginRequest();
34182
+ await dispatchRequest(request, sink, handlers);
34183
+ }
34184
+ async function runCompanionBridgeServe(stdin, stdout, stderr, deps = {}) {
34185
+ const context = new ServeContext(deps.now ?? Date.now, deps.chat ?? {});
34186
+ const chat = context.chatDeps();
34187
+ const handlers = {
34188
+ roster: (sink2) => rosterCompanions(sink2, chat),
34189
+ send: (request, sink2) => sendCompanionMessage(request, sink2, chat),
34190
+ converse: (request, sink2) => converseCompanionMessage(request, sink2, chat),
34191
+ history: (request, sink2) => historyCompanionMessages(request, sink2, chat),
34192
+ update: deps.update ?? (() => checkCompanionUpdate(defaultLocalCompanionInstallOptions()))
34193
+ };
34194
+ const sink = (event) => {
34195
+ stdout.write(`${serializeEvent(event)}
34196
+ `);
34197
+ };
34198
+ try {
34199
+ for await (const raw of requestLines(stdin)) {
34200
+ let request;
34201
+ try {
34202
+ request = parseRequestLine(raw);
34203
+ } catch {
34204
+ stderr.write("bridge request rejected\n");
34205
+ return 2;
34206
+ }
34207
+ try {
34208
+ await handleWithContext(request, sink, handlers, context);
34209
+ } catch {
34210
+ stderr.write("bridge request failed\n");
34211
+ return 3;
34212
+ }
34213
+ }
34214
+ } catch {
34215
+ stderr.write("bridge request rejected\n");
34216
+ return 2;
34217
+ }
34218
+ return 0;
34219
+ }
34220
+
34045
34221
  // src/commands/companion/bridge.ts
34046
34222
  var defaultDeps3 = {
34047
34223
  roster: rosterCompanions,
@@ -34109,7 +34285,20 @@ async function runCompanionBridge(stdin, stdout, stderr, deps = defaultDeps3) {
34109
34285
  }
34110
34286
  var CompanionBridgeCommand = class extends Command61 {
34111
34287
  static paths = [["companion", "_bridge"]];
34288
+ /**
34289
+ * One process serving many requests instead of one per request, so the
34290
+ * session keeps its authenticated context between them. A CLI predating the
34291
+ * flag rejects it outright, which is how the app knows to fall back.
34292
+ */
34293
+ serve = Option58.Boolean("--serve", false);
34112
34294
  async execute() {
34295
+ if (this.serve) {
34296
+ return runCompanionBridgeServe(
34297
+ this.context.stdin,
34298
+ this.context.stdout,
34299
+ this.context.stderr
34300
+ );
34301
+ }
34113
34302
  return runCompanionBridge(
34114
34303
  this.context.stdin,
34115
34304
  this.context.stdout,
@@ -34205,7 +34394,7 @@ var CompanionStatusCommand = class extends M8tCommand {
34205
34394
  };
34206
34395
 
34207
34396
  // src/commands/companion/repair.ts
34208
- import { Command as Command63, Option as Option58 } from "clipanion";
34397
+ import { Command as Command63, Option as Option59 } from "clipanion";
34209
34398
  async function runCompanionRepairCommand(stdout, repair) {
34210
34399
  const state = await repair();
34211
34400
  if (state.state === "not-released") {
@@ -34227,7 +34416,7 @@ var CompanionRepairCommand = class extends M8tCommand {
34227
34416
  static usage = Command63.Usage({
34228
34417
  description: "Restore the desktop companions and start-at-login state."
34229
34418
  });
34230
- resourceGroup = Option58.String("--resource-group", {
34419
+ resourceGroup = Option59.String("--resource-group", {
34231
34420
  description: "Which deployment to bind to, when the subscription holds more than one."
34232
34421
  });
34233
34422
  async executeCommand() {