@konstantdotcloud/boombox 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,7 +21,7 @@ boombox admin # opens the VM admin UI through a short-lived cloud grant
21
21
  boombox run bd_pre_meeting_brief --input meeting_uid=sample --input organizer=user@example.com --input attendees='["user@example.com"]' --input start_time=2026-06-02T15:00:00Z --input summary=Sample
22
22
  ```
23
23
 
24
- For MCP clients, add `boombox serve --mcp` after `boombox login` succeeds.
24
+ For MCP clients, add `boombox serve --mcp` after `boombox login` succeeds. The MCP server defaults to the `advanced` profile (cassette authoring + rack verbs included); set `GARY_MCP_PROFILE=andrew` or pass `--profile` to narrow or change it.
25
25
 
26
26
  ## Commands
27
27
 
@@ -33,6 +33,7 @@ For MCP clients, add `boombox serve --mcp` after `boombox login` succeeds.
33
33
  | `boombox run <cassette_name> [--input key=value ...] [--no-tail] [--json]` | Manually triggers a cassette through `/gateway/rack/run`, prompts for required missing inputs, then polls to a terminal state unless `--no-tail` is set. |
34
34
  | `boombox cassettes list` | Lists active cassettes available to the tenant. |
35
35
  | `boombox cassettes show <id> [--draft]` | Prints a cassette YAML projection. |
36
+ | `boombox cassettes publish <draft_id> --name <name> [--version <n>] [--json]` | Publishes a dry-run-approved cassette draft to the tenant tier via `POST /gateway/cassette/publish`; renders gate rejections (e.g. `dry-run-not-green`) with fix guidance. |
36
37
  | `boombox runs list [--cassette=X] [--since=24h] [--actor=Y] [--status=completed] [--limit=20]` | Lists recent runs with run id, cassette, actor, status, duration, and start time. |
37
38
  | `boombox runs show <run_id>` | Shows one run: spec hash, inputs, step trace, delivery receipts, error summary, and replay ref. |
38
39
  | `boombox logs tail [--cassette=X]` | Tails run/step events from the VM SSE stream. |
@@ -57,7 +58,7 @@ For MCP clients, add `boombox serve --mcp` after `boombox login` succeeds.
57
58
  [konstant]
58
59
  tenant_id = "example"
59
60
  api_key = "kn_example_***"
60
- gateway_url = "https://boombox.konstant.cloud/v2"
61
+ gateway_url = "https://boombox-example.exe.xyz"
61
62
 
62
63
  [runtime]
63
64
  default_kind = "vm"
package/dist/boombox.js CHANGED
@@ -36148,7 +36148,7 @@ var init_ask_gary = __esm({
36148
36148
  thread_id: external_exports2.string().optional().describe("Concrete thread_id to use instead of resolving a named alias. Useful when continuing an artifact discussion thread."),
36149
36149
  artifact_ref: external_exports2.string().optional().describe("Artifact id to pin as Gary context. Gary loads the artifact body and tags the resulting thread with artifact_ref."),
36150
36150
  fresh: external_exports2.boolean().optional().describe("If true, rotate the thread alias to a brand-new conversation, discarding prior history under that alias."),
36151
- model_tier: external_exports2.enum(["auto", "fast", "nano", "mini", "reason", "mid", "explore", "premium", "opus"]).optional().describe("Model tier override. Default 'explore' (Sonnet 4.6). Use 'premium' for GPT-5.5, 'opus' for Claude Opus 4.7."),
36151
+ model_tier: external_exports2.enum(["auto", "fast", "nano", "mini", "reason", "mid", "explore", "premium", "opus"]).optional().describe("Model tier override. Default 'explore' (Sonnet 4.6). Use 'premium' for Opus 4.8 at max thinking, 'opus' for Opus 4.8 standard."),
36152
36152
  thinking_level: external_exports2.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional().describe("Reasoning effort override. Default 'medium'."),
36153
36153
  intent: external_exports2.enum(["cassette_author"]).optional().describe("Set to cassette_author to load Gary cassette-authoring mode prompt/doctrine.")
36154
36154
  };
@@ -37341,12 +37341,6 @@ function registerCassetteAuthoringVerbs(server, gateway) {
37341
37341
  publishSchema,
37342
37342
  async (input) => renderGatewayResult("cassette_publish", await gateway.call("/gateway/cassette/publish", input))
37343
37343
  );
37344
- server.tool(
37345
- "cassette_request_publish",
37346
- "Request tenant_admin approval to publish a cassette draft when the caller lacks cassette.publish.",
37347
- requestPublishSchema,
37348
- async (input) => renderGatewayResult("cassette_request_publish", await gateway.call("/gateway/cassette/request-publish", input))
37349
- );
37350
37344
  server.tool(
37351
37345
  "cassette_get",
37352
37346
  "Get a cassette draft or published cassette as YAML plus describe payload.",
@@ -37399,7 +37393,7 @@ ${JSON.stringify(record2, null, 2)}`;
37399
37393
  function isRecord(value) {
37400
37394
  return value !== null && typeof value === "object" && !Array.isArray(value);
37401
37395
  }
37402
- var recordSchema, draftSchema, refineSchema, dryRunSchema, publishSchema, requestPublishSchema, getSchema, listDraftsSchema, listCapabilitiesSchema;
37396
+ var recordSchema, draftSchema, refineSchema, dryRunSchema, publishSchema, getSchema, listDraftsSchema, listCapabilitiesSchema;
37403
37397
  var init_cassette_authoring = __esm({
37404
37398
  "../../lib/gary-mcp/verbs/cassette-authoring.ts"() {
37405
37399
  "use strict";
@@ -37427,10 +37421,6 @@ var init_cassette_authoring = __esm({
37427
37421
  name: external_exports2.string().min(1),
37428
37422
  version: external_exports2.number().int().min(1).optional()
37429
37423
  };
37430
- requestPublishSchema = {
37431
- draft_id: external_exports2.string().min(1),
37432
- reason: external_exports2.string().min(1).optional()
37433
- };
37434
37424
  getSchema = {
37435
37425
  id: external_exports2.string().min(1).optional(),
37436
37426
  draft_id: external_exports2.string().min(1).optional()
@@ -37480,7 +37470,10 @@ function normalizeProfile(value) {
37480
37470
  }
37481
37471
  function guessPathPrefix(baseUrl) {
37482
37472
  if (!baseUrl) return "/api";
37483
- if (/\.fly\.dev/i.test(baseUrl)) return "";
37473
+ if (/\.exe\.(xyz|dev)/i.test(baseUrl)) {
37474
+ return /\/v2\/?$/.test(baseUrl) ? "/api" : "/v2/api";
37475
+ }
37476
+ if (/\.fly\.dev/i.test(baseUrl)) return "/api";
37484
37477
  if (/\.konstant\.cloud/i.test(baseUrl)) return "/api";
37485
37478
  if (/\.vercel\.app/i.test(baseUrl)) return "/api";
37486
37479
  return "";
@@ -37606,7 +37599,7 @@ var {
37606
37599
  init_esm_shims();
37607
37600
 
37608
37601
  // package.json
37609
- var version = "0.1.1";
37602
+ var version = "0.2.0";
37610
37603
 
37611
37604
  // src/lib/version.ts
37612
37605
  var BOOMBOX_VERSION = version;
@@ -42579,10 +42572,21 @@ function resolveGatewayTarget(config2) {
42579
42572
  function normalizeUrl(url) {
42580
42573
  return url.replace(/\/+$/, "");
42581
42574
  }
42575
+ function gatewayApiPrefix(baseUrl) {
42576
+ if (!baseUrl) return "/api";
42577
+ if (/\.exe\.(xyz|dev)/i.test(baseUrl)) {
42578
+ return /\/v2\/?$/.test(baseUrl) ? "/api" : "/v2/api";
42579
+ }
42580
+ return "/api";
42581
+ }
42582
+ function resolveGatewayApiBase(config2) {
42583
+ const origin = resolveGatewayTarget(config2).url;
42584
+ return `${origin}${gatewayApiPrefix(origin)}`;
42585
+ }
42582
42586
 
42583
42587
  // src/cli/_verify.ts
42584
42588
  async function verifyAuth(config2, fetchImpl = fetch) {
42585
- const url = `${resolveGateway(config2)}/api/gateway/rack/list`;
42589
+ const url = `${resolveGatewayApiBase(config2)}/gateway/rack/list`;
42586
42590
  let res;
42587
42591
  try {
42588
42592
  res = await fetchImpl(url, {
@@ -42634,7 +42638,7 @@ async function runInit(options = {}) {
42634
42638
  const preset = {
42635
42639
  tenant_id: options.tenantId ?? enrollPayload?.tenant_id ?? existing?.konstant.tenant_id ?? "",
42636
42640
  api_key: options.tenantApiKey ?? options.apiKey ?? enrollPayload?.tenant_api_key ?? enrollPayload?.api_key ?? existing?.konstant.api_key ?? "",
42637
- gateway_url: options.gatewayUrl ?? enrollPayload?.gateway_url ?? existing?.konstant.gateway_url ?? "https://boombox.konstant.cloud/v2",
42641
+ gateway_url: options.gatewayUrl ?? enrollPayload?.gateway_url ?? existing?.konstant.gateway_url ?? options.vmUrl ?? enrollPayload?.vm_url ?? existing?.runtime.vm_url ?? "",
42638
42642
  vm_url: options.vmUrl ?? enrollPayload?.vm_url ?? existing?.runtime.vm_url ?? ""
42639
42643
  };
42640
42644
  log("Welcome to Konstant Boombox.");
@@ -43299,7 +43303,6 @@ var open_default = open;
43299
43303
 
43300
43304
  // src/cli/enroll.ts
43301
43305
  var DEFAULT_AUTH_BASE = "https://boombox.konstant.cloud";
43302
- var DEFAULT_GATEWAY_BASE = "https://boombox.konstant.cloud/v2";
43303
43306
  var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
43304
43307
  async function runEnroll(options = {}) {
43305
43308
  const log = options.log ?? ((m) => console.log(m));
@@ -43325,8 +43328,13 @@ async function runEnroll(options = {}) {
43325
43328
  log,
43326
43329
  openBrowser: options.openBrowser
43327
43330
  });
43328
- const gatewayUrl = (options.gatewayUrl ?? payload.gateway_url ?? DEFAULT_GATEWAY_BASE).replace(/\/+$/, "");
43329
43331
  const vmUrl = (options.vmUrl ?? payload.vm_url)?.replace(/\/+$/, "");
43332
+ const gatewayUrl = (options.gatewayUrl ?? payload.gateway_url ?? vmUrl ?? "").replace(/\/+$/, "");
43333
+ if (!gatewayUrl) {
43334
+ throw new Error(
43335
+ "Enrollment returned no gateway: neither gateway_url nor vm_url present. Provision a tenant VM (Mode 2) \u2014 the shared cloud gateway (Mode 1) is retired."
43336
+ );
43337
+ }
43330
43338
  const apiKey = payload.tenant_api_key ?? payload.api_key;
43331
43339
  const httpPort = existing?.boombox.http_port ?? DEFAULT_HTTP_PORT;
43332
43340
  const config2 = BoomboxConfigSchema.parse({
@@ -47032,12 +47040,20 @@ function relativeToCwd(absPath) {
47032
47040
 
47033
47041
  // src/server/mcp-stdio.ts
47034
47042
  init_esm_shims();
47043
+ var DEFAULT_MCP_PROFILE = "advanced";
47044
+ function resolveMcpProfileSelection(flag) {
47045
+ if (flag === void 0) return void 0;
47046
+ return flag === "default" ? DEFAULT_MCP_PROFILE : flag;
47047
+ }
47035
47048
  async function startStdioMcp(config2) {
47036
47049
  process.env.GARY_MCP_GATEWAY_URL = resolveGateway(config2);
47037
47050
  process.env.GARY_MCP_API_KEY = config2.konstant.api_key;
47038
47051
  if (!process.env.KONSTANT_API_KEY) {
47039
47052
  process.env.KONSTANT_API_KEY = config2.konstant.api_key;
47040
47053
  }
47054
+ if (!(process.env.GARY_MCP_PROFILE ?? "").trim()) {
47055
+ process.env.GARY_MCP_PROFILE = DEFAULT_MCP_PROFILE;
47056
+ }
47041
47057
  const mod = await Promise.resolve().then(() => (init_gary_mcp(), gary_mcp_exports));
47042
47058
  await mod.startGaryMcpServer();
47043
47059
  }
@@ -47112,8 +47128,10 @@ async function runServe(options = {}) {
47112
47128
  log("Note: mcp_enabled=false in config; enabling for this session.");
47113
47129
  }
47114
47130
  if (enableMcp) {
47115
- const requestedProfile = options.profile === "default" ? "andrew" : options.profile;
47116
- process.env.GARY_MCP_PROFILE = requestedProfile ?? process.env.GARY_MCP_PROFILE ?? "andrew";
47131
+ const selectedProfile = resolveMcpProfileSelection(options.profile);
47132
+ if (selectedProfile !== void 0) {
47133
+ process.env.GARY_MCP_PROFILE = selectedProfile;
47134
+ }
47117
47135
  process.env.GARY_MCP_TENANT_ID = config2.konstant.tenant_id;
47118
47136
  }
47119
47137
  const handle = await serve2({
@@ -48246,6 +48264,7 @@ function createOpsContext(options = {}) {
48246
48264
  return {
48247
48265
  config: config2,
48248
48266
  gateway: resolveGateway(config2),
48267
+ gatewayApi: resolveGatewayApiBase(config2),
48249
48268
  apiKey: config2.konstant.api_key,
48250
48269
  tenant_id: config2.konstant.tenant_id,
48251
48270
  fetchImpl: options.fetchImpl ?? fetch,
@@ -48265,7 +48284,8 @@ function joinUrl(base, path4) {
48265
48284
  return `${cleanBase}${cleanPath}`;
48266
48285
  }
48267
48286
  async function fetchText(ctx, path4, options = {}) {
48268
- const url = joinUrl(ctx.gateway, path4);
48287
+ const base = path4.startsWith("/gateway") ? ctx.gatewayApi : ctx.gateway;
48288
+ const url = joinUrl(base, path4);
48269
48289
  const headers = {
48270
48290
  ...options.auth === false ? {} : authHeaders(ctx, options.accept ?? "application/json"),
48271
48291
  ...options.headers ?? {}
@@ -49179,6 +49199,96 @@ async function runCassettesDryRun(options) {
49179
49199
  }
49180
49200
  printSimulation(body, ctx);
49181
49201
  }
49202
+ async function runCassettesPublish(options) {
49203
+ const ctx = createOpsContext(options);
49204
+ const payload = {
49205
+ draft_id: options.draftId,
49206
+ name: options.name
49207
+ };
49208
+ if (options.version !== void 0) payload.version = options.version;
49209
+ let body;
49210
+ try {
49211
+ body = (await fetchJson(ctx, "/gateway/cassette/publish", { method: "POST", body: payload })).body;
49212
+ } catch (error2) {
49213
+ if (error2 instanceof OpsHttpError) {
49214
+ renderPublishRejection(error2.body, ctx, options, `HTTP ${error2.status}`);
49215
+ return 1;
49216
+ }
49217
+ throw error2;
49218
+ }
49219
+ const record2 = asRecord(body);
49220
+ if (record2 && (record2.ok === false || typeof record2.code === "string" && record2.ok !== true)) {
49221
+ renderPublishRejection(body, ctx, options, "rejected");
49222
+ return 1;
49223
+ }
49224
+ if (options.json) {
49225
+ ctx.log(JSON.stringify(body ?? null, null, 2));
49226
+ return 0;
49227
+ }
49228
+ const published = recordField(record2, "workflow") ?? recordField(record2, "published") ?? recordField(record2, "cassette") ?? record2 ?? {};
49229
+ printKeyValues([
49230
+ ["draft", options.draftId],
49231
+ ["workflow", field2(published, ["workflow_id", "id", "cassette_id"])],
49232
+ ["version", field2(published, ["version", "workflow_version"])],
49233
+ ["tier", field2(published, ["tier"])],
49234
+ ["status", field2(published, ["status"])]
49235
+ ], ctx.log);
49236
+ ctx.log("Published to the tenant tier.");
49237
+ return 0;
49238
+ }
49239
+ function publishRejectionHint(code, draftId) {
49240
+ switch (code.toLowerCase().replace(/_/g, "-")) {
49241
+ case "publish-blocked-draft-required":
49242
+ return `Publish requires a saved draft, not raw YAML. Save the draft first (cassette_draft / cassette_refine via MCP), then publish by draft_id (\`${draftId}\`).`;
49243
+ case "publish-blocked-dry-run-missing":
49244
+ return `This draft has no dry-run yet. Run one (cassette_dry_run via MCP, or \`boombox cassettes dry-run ${draftId} --draft\`) and get a ready_to_publish verdict before publishing.`;
49245
+ case "publish-blocked-dry-run-not-ready":
49246
+ case "dry-run-not-green":
49247
+ return `The draft's latest dry-run is not green. Re-run it (cassette_dry_run via MCP, or \`boombox cassettes dry-run ${draftId} --draft\`) until the verdict is ready_to_publish, then publish again.`;
49248
+ case "publish-blocked-dry-run-stale":
49249
+ case "dry-run-stale":
49250
+ // legacy aliases
49251
+ case "stale-dry-run":
49252
+ case "spec-hash-mismatch":
49253
+ return "The draft changed after its last green dry-run. Re-run the dry-run against the current draft revision, then publish again.";
49254
+ case "forbidden-authority":
49255
+ case "missing-authority":
49256
+ return "This API key lacks the cassette.publish grant. Use cassette_request_publish (MCP) to ask a tenant admin to publish, or have an admin add cassette.publish to your key.";
49257
+ case "publish-blocked-not-owner":
49258
+ case "forbidden-not-owner":
49259
+ case "forbidden":
49260
+ // legacy aliases
49261
+ case "draft-not-owned":
49262
+ return "This draft is not owned by your API key actor. Publish from the key that created the draft, or ask a tenant admin to publish it.";
49263
+ case "not-found":
49264
+ return `No draft "${draftId}" is visible to this key. Check \`boombox cassettes list --status draft\` (or cassette_list_drafts via MCP).`;
49265
+ case "publish-blocked-master-shadow":
49266
+ case "master-shadowing":
49267
+ // legacy aliases
49268
+ case "master-collision":
49269
+ return "The cassette id collides with a master/builtin cassette, which tenant publishes are not allowed to shadow. Rename the cassette and publish again.";
49270
+ case "publish-blocked-event-trigger":
49271
+ return "Tenant cassettes cannot publish with event triggers (those are reserved for master-tier cassettes). Remove the event trigger, or request an admin publish.";
49272
+ case "cassette-yaml-invalid":
49273
+ return "The draft YAML failed validation. Fix the reported errors (cassette_refine via MCP) and re-run a dry-run before publishing.";
49274
+ case "validation-error":
49275
+ return "The publish payload was rejected. Check the draft_id and --name values, then re-validate the draft before publishing.";
49276
+ default:
49277
+ return void 0;
49278
+ }
49279
+ }
49280
+ function renderPublishRejection(body, ctx, options, fallbackLabel) {
49281
+ if (options.json) {
49282
+ ctx.errLog(JSON.stringify(body ?? { code: fallbackLabel }, null, 2));
49283
+ return;
49284
+ }
49285
+ const record2 = asRecord(body);
49286
+ const code = stringField4(record2, "code") ?? fallbackLabel;
49287
+ const message = stringField4(record2, "message") ?? stringField4(record2, "error") ?? "no detail from gateway";
49288
+ ctx.errLog(`publish rejected (${code}): ${message}`);
49289
+ const hint = publishRejectionHint(code, options.draftId);
49290
+ if (hint) ctx.errLog(` fix: ${hint}`);
49291
+ }
49182
49292
  function extractCassettes(body) {
49183
49293
  const record2 = asRecord(body);
49184
49294
  const list = arrayField2(record2, "cassettes") ?? arrayField2(record2, "items") ?? arrayField2(record2, "drafts") ?? (Array.isArray(body) ? body : []);
@@ -49584,6 +49694,16 @@ cassettes.command("validate <id>").description("Run cassette oracle readiness ch
49584
49694
  cassettes.command("dry-run <id>").description("Run cassette v2 preview simulation with no durable side effects.").option("--draft", "load from cassette_drafts instead of published records").option("--json", "print raw JSON report").option("--config <path>", "override config path").action(async (id, opts) => {
49585
49695
  await runCassettesDryRun({ id, draft: opts.draft, json: opts.json, configPath: opts.config });
49586
49696
  });
49697
+ cassettes.command("publish <draft_id>").description("Publish a dry-run-approved cassette draft to the tenant tier.").requiredOption("--name <name>", "name for the published cassette").option("--version <n>", "explicit version (server assigns the next one when omitted)", parsePositiveIntFlag).option("--json", "print the raw JSON response").option("--config <path>", "override config path").action(async (draftId, opts) => {
49698
+ const code = await runCassettesPublish({
49699
+ draftId,
49700
+ name: opts.name,
49701
+ version: opts.version,
49702
+ json: opts.json,
49703
+ configPath: opts.config
49704
+ });
49705
+ if (code !== 0) process.exit(code);
49706
+ });
49587
49707
  var artifacts = program2.command("artifacts").description("Operate on artifacts.");
49588
49708
  artifacts.command("open <artifact_id>").description("Open an artifact URL in the system browser.").option("--config <path>", "override config path").action(async (artifactId, opts) => {
49589
49709
  await runArtifactsOpen({ artifactId, configPath: opts.config });
package/dist/index.js CHANGED
@@ -28219,7 +28219,7 @@ var init_ask_gary = __esm({
28219
28219
  thread_id: external_exports2.string().optional().describe("Concrete thread_id to use instead of resolving a named alias. Useful when continuing an artifact discussion thread."),
28220
28220
  artifact_ref: external_exports2.string().optional().describe("Artifact id to pin as Gary context. Gary loads the artifact body and tags the resulting thread with artifact_ref."),
28221
28221
  fresh: external_exports2.boolean().optional().describe("If true, rotate the thread alias to a brand-new conversation, discarding prior history under that alias."),
28222
- model_tier: external_exports2.enum(["auto", "fast", "nano", "mini", "reason", "mid", "explore", "premium", "opus"]).optional().describe("Model tier override. Default 'explore' (Sonnet 4.6). Use 'premium' for GPT-5.5, 'opus' for Claude Opus 4.7."),
28222
+ model_tier: external_exports2.enum(["auto", "fast", "nano", "mini", "reason", "mid", "explore", "premium", "opus"]).optional().describe("Model tier override. Default 'explore' (Sonnet 4.6). Use 'premium' for Opus 4.8 at max thinking, 'opus' for Opus 4.8 standard."),
28223
28223
  thinking_level: external_exports2.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional().describe("Reasoning effort override. Default 'medium'."),
28224
28224
  intent: external_exports2.enum(["cassette_author"]).optional().describe("Set to cassette_author to load Gary cassette-authoring mode prompt/doctrine.")
28225
28225
  };
@@ -29412,12 +29412,6 @@ function registerCassetteAuthoringVerbs(server, gateway) {
29412
29412
  publishSchema,
29413
29413
  async (input) => renderGatewayResult("cassette_publish", await gateway.call("/gateway/cassette/publish", input))
29414
29414
  );
29415
- server.tool(
29416
- "cassette_request_publish",
29417
- "Request tenant_admin approval to publish a cassette draft when the caller lacks cassette.publish.",
29418
- requestPublishSchema,
29419
- async (input) => renderGatewayResult("cassette_request_publish", await gateway.call("/gateway/cassette/request-publish", input))
29420
- );
29421
29415
  server.tool(
29422
29416
  "cassette_get",
29423
29417
  "Get a cassette draft or published cassette as YAML plus describe payload.",
@@ -29470,7 +29464,7 @@ ${JSON.stringify(record2, null, 2)}`;
29470
29464
  function isRecord(value) {
29471
29465
  return value !== null && typeof value === "object" && !Array.isArray(value);
29472
29466
  }
29473
- var recordSchema, draftSchema, refineSchema, dryRunSchema, publishSchema, requestPublishSchema, getSchema, listDraftsSchema, listCapabilitiesSchema;
29467
+ var recordSchema, draftSchema, refineSchema, dryRunSchema, publishSchema, getSchema, listDraftsSchema, listCapabilitiesSchema;
29474
29468
  var init_cassette_authoring = __esm({
29475
29469
  "../../lib/gary-mcp/verbs/cassette-authoring.ts"() {
29476
29470
  "use strict";
@@ -29498,10 +29492,6 @@ var init_cassette_authoring = __esm({
29498
29492
  name: external_exports2.string().min(1),
29499
29493
  version: external_exports2.number().int().min(1).optional()
29500
29494
  };
29501
- requestPublishSchema = {
29502
- draft_id: external_exports2.string().min(1),
29503
- reason: external_exports2.string().min(1).optional()
29504
- };
29505
29495
  getSchema = {
29506
29496
  id: external_exports2.string().min(1).optional(),
29507
29497
  draft_id: external_exports2.string().min(1).optional()
@@ -29551,7 +29541,10 @@ function normalizeProfile(value) {
29551
29541
  }
29552
29542
  function guessPathPrefix(baseUrl) {
29553
29543
  if (!baseUrl) return "/api";
29554
- if (/\.fly\.dev/i.test(baseUrl)) return "";
29544
+ if (/\.exe\.(xyz|dev)/i.test(baseUrl)) {
29545
+ return /\/v2\/?$/.test(baseUrl) ? "/api" : "/v2/api";
29546
+ }
29547
+ if (/\.fly\.dev/i.test(baseUrl)) return "/api";
29555
29548
  if (/\.konstant\.cloud/i.test(baseUrl)) return "/api";
29556
29549
  if (/\.vercel\.app/i.test(baseUrl)) return "/api";
29557
29550
  return "";
@@ -34581,7 +34574,7 @@ init_esm_shims();
34581
34574
  init_esm_shims();
34582
34575
 
34583
34576
  // package.json
34584
- var version = "0.1.1";
34577
+ var version = "0.2.0";
34585
34578
 
34586
34579
  // src/lib/version.ts
34587
34580
  var BOOMBOX_VERSION = version;
@@ -42608,6 +42601,17 @@ function resolveGatewayTarget(config2) {
42608
42601
  function normalizeUrl(url) {
42609
42602
  return url.replace(/\/+$/, "");
42610
42603
  }
42604
+ function gatewayApiPrefix(baseUrl) {
42605
+ if (!baseUrl) return "/api";
42606
+ if (/\.exe\.(xyz|dev)/i.test(baseUrl)) {
42607
+ return /\/v2\/?$/.test(baseUrl) ? "/api" : "/v2/api";
42608
+ }
42609
+ return "/api";
42610
+ }
42611
+ function resolveGatewayApiBase(config2) {
42612
+ const origin = resolveGatewayTarget(config2).url;
42613
+ return `${origin}${gatewayApiPrefix(origin)}`;
42614
+ }
42611
42615
 
42612
42616
  // src/server/proxy.ts
42613
42617
  init_esm_shims();
@@ -42880,12 +42884,20 @@ function relativeToCwd(absPath) {
42880
42884
 
42881
42885
  // src/server/mcp-stdio.ts
42882
42886
  init_esm_shims();
42887
+ var DEFAULT_MCP_PROFILE = "advanced";
42888
+ function resolveMcpProfileSelection(flag) {
42889
+ if (flag === void 0) return void 0;
42890
+ return flag === "default" ? DEFAULT_MCP_PROFILE : flag;
42891
+ }
42883
42892
  async function startStdioMcp(config2) {
42884
42893
  process.env.GARY_MCP_GATEWAY_URL = resolveGateway(config2);
42885
42894
  process.env.GARY_MCP_API_KEY = config2.konstant.api_key;
42886
42895
  if (!process.env.KONSTANT_API_KEY) {
42887
42896
  process.env.KONSTANT_API_KEY = config2.konstant.api_key;
42888
42897
  }
42898
+ if (!(process.env.GARY_MCP_PROFILE ?? "").trim()) {
42899
+ process.env.GARY_MCP_PROFILE = DEFAULT_MCP_PROFILE;
42900
+ }
42889
42901
  const mod = await Promise.resolve().then(() => (init_gary_mcp(), gary_mcp_exports));
42890
42902
  await mod.startGaryMcpServer();
42891
42903
  }
@@ -42925,7 +42937,7 @@ import { readFileSync as readFileSync3 } from "fs";
42925
42937
  // src/cli/_verify.ts
42926
42938
  init_esm_shims();
42927
42939
  async function verifyAuth(config2, fetchImpl = fetch) {
42928
- const url = `${resolveGateway(config2)}/api/gateway/rack/list`;
42940
+ const url = `${resolveGatewayApiBase(config2)}/gateway/rack/list`;
42929
42941
  let res;
42930
42942
  try {
42931
42943
  res = await fetchImpl(url, {
@@ -42977,7 +42989,7 @@ async function runInit(options = {}) {
42977
42989
  const preset = {
42978
42990
  tenant_id: options.tenantId ?? enrollPayload?.tenant_id ?? existing?.konstant.tenant_id ?? "",
42979
42991
  api_key: options.tenantApiKey ?? options.apiKey ?? enrollPayload?.tenant_api_key ?? enrollPayload?.api_key ?? existing?.konstant.api_key ?? "",
42980
- gateway_url: options.gatewayUrl ?? enrollPayload?.gateway_url ?? existing?.konstant.gateway_url ?? "https://boombox.konstant.cloud/v2",
42992
+ gateway_url: options.gatewayUrl ?? enrollPayload?.gateway_url ?? existing?.konstant.gateway_url ?? options.vmUrl ?? enrollPayload?.vm_url ?? existing?.runtime.vm_url ?? "",
42981
42993
  vm_url: options.vmUrl ?? enrollPayload?.vm_url ?? existing?.runtime.vm_url ?? ""
42982
42994
  };
42983
42995
  log("Welcome to Konstant Boombox.");
@@ -43339,8 +43351,10 @@ async function runServe(options = {}) {
43339
43351
  log("Note: mcp_enabled=false in config; enabling for this session.");
43340
43352
  }
43341
43353
  if (enableMcp) {
43342
- const requestedProfile = options.profile === "default" ? "andrew" : options.profile;
43343
- process.env.GARY_MCP_PROFILE = requestedProfile ?? process.env.GARY_MCP_PROFILE ?? "andrew";
43354
+ const selectedProfile = resolveMcpProfileSelection(options.profile);
43355
+ if (selectedProfile !== void 0) {
43356
+ process.env.GARY_MCP_PROFILE = selectedProfile;
43357
+ }
43344
43358
  process.env.GARY_MCP_TENANT_ID = config2.konstant.tenant_id;
43345
43359
  }
43346
43360
  const handle = await serve2({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@konstantdotcloud/boombox",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Local Boombox runtime for Konstant cassettes — CLI, stdio MCP server, and local Hono proxy.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",