perchai-cli 2.4.45 → 2.4.47

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.
Files changed (2) hide show
  1. package/dist/perch.mjs +892 -85
  2. package/package.json +1 -1
package/dist/perch.mjs CHANGED
@@ -75918,7 +75918,6 @@ function isTurnAbortedError(error) {
75918
75918
  var TURN_STOPPED_BY_USER_MESSAGE;
75919
75919
  var init_turnAbort = __esm({
75920
75920
  "features/perchTerminal/runtime/turnAbort.ts"() {
75921
- "use strict";
75922
75921
  TURN_STOPPED_BY_USER_MESSAGE = "Turn stopped by user.";
75923
75922
  }
75924
75923
  });
@@ -76224,7 +76223,6 @@ function getToolDisplayName(toolName) {
76224
76223
  var NON_MODULE_TOOL_OWNERS, TOOL_RISK, TOOL_DISPLAY_NAMES;
76225
76224
  var init_catalog = __esm({
76226
76225
  "features/perchTerminal/runtime/toolSystem/catalog.ts"() {
76227
- "use strict";
76228
76226
  init_toolNames();
76229
76227
  NON_MODULE_TOOL_OWNERS = {
76230
76228
  [TOOL_NAMES.listSources]: "lane",
@@ -84011,7 +84009,7 @@ function sanitizeModelBackendPreset(value) {
84011
84009
  if (value === "wandb_gemma") return "wandb_qwen";
84012
84010
  if (value === "wandb_glm") return "wandb_glm51";
84013
84011
  if (value === "bedrock_mistral_large_3") return "bedrock_qwen3_coder";
84014
- if (value === "router" || value === "gcp" || value === "modal" || value === "huggingface" || value === "fireworks_deepseek" || value === "wandb_qwen" || value === "wandb_minimax" || value === "wandb_kimi" || value === "wandb_glm51" || value === "wandb_nemotron_ultra" || value === "bedrock_glm5" || value === "bedrock_qwen3_coder" || value === "bedrock_gpt_oss_120b" || value === "bedrock_nemotron_super" || value === "bedrock_minimax_m2" || value === "bedrock_deepseek_v32" || value === "bedrock_qwen3_vl" || value === "codex_gpt55" || value === "codex_gpt54" || value === "codex_gpt54_mini" || value === "claude_haiku45" || value === "claude_sonnet46" || value === "claude_opus48") {
84012
+ if (value === "router" || value === "gcp" || value === "modal" || value === "huggingface" || value === "fireworks_deepseek" || value === "wandb_qwen" || value === "wandb_minimax" || value === "wandb_kimi" || value === "wandb_glm51" || value === "wandb_nemotron_ultra" || value === "wandb_deepseek_flash" || value === "wandb_deepseek_pro" || value === "bedrock_kimi_k25" || value === "bedrock_glm5" || value === "bedrock_qwen3_coder" || value === "bedrock_gpt_oss_120b" || value === "bedrock_nemotron_super" || value === "bedrock_minimax_m2" || value === "bedrock_deepseek_v32" || value === "bedrock_qwen3_vl" || value === "codex_gpt55" || value === "codex_gpt54" || value === "codex_gpt54_mini" || value === "claude_haiku45" || value === "claude_sonnet46" || value === "claude_opus48") {
84015
84013
  return value;
84016
84014
  }
84017
84015
  return null;
@@ -84123,7 +84121,7 @@ function resolveApiModelId(option, env4 = runtimeEnv()) {
84123
84121
  }
84124
84122
  return option.modelId;
84125
84123
  }
84126
- var DEFAULT_NIM_MODEL_ID, DEFAULT_FOUNDER_MODEL_OPTION_ID, ALL_MODEL_LANES, WORKER_LANES, REASONING_LANES, DEFAULT_GITHUB_GPT_41_ID, DEFAULT_GITHUB_GPT_41_MINI_ID, DEFAULT_GITHUB_GPT_4O_ID, DEFAULT_CODE_WORKER_MODEL_ID, GCP_SELF_HOSTED_OPTION_ID, DEFAULT_GCP_INFERENCE_MODEL, MODAL_SELF_HOSTED_OPTION_ID, MODAL_MIMO_OPTION_ID, DEFAULT_MODAL_INFERENCE_MODEL, HUGGINGFACE_KIMI_K25_OPTION_ID, WANDB_QWEN_36_35B_A3B_OPTION_ID, WANDB_MINIMAX_M25_OPTION_ID, WANDB_KIMI_K26_OPTION_ID, WANDB_GLM_51_OPTION_ID, WANDB_NEMOTRON_ULTRA_OPTION_ID, BEDROCK_GLM5_OPTION_ID, BEDROCK_QWEN3_CODER_480B_OPTION_ID, BEDROCK_GPT_OSS_120B_OPTION_ID, BEDROCK_NEMOTRON_SUPER_120B_OPTION_ID, BEDROCK_MINIMAX_M2_OPTION_ID, BEDROCK_DEEPSEEK_V32_OPTION_ID, BEDROCK_QWEN3_VL_235B_OPTION_ID, CODEX_GPT_55_OPTION_ID, CODEX_GPT_54_OPTION_ID, CODEX_GPT_54_MINI_OPTION_ID, CLAUDE_CODE_HAIKU_45_OPTION_ID, CLAUDE_CODE_SONNET_46_OPTION_ID, CLAUDE_CODE_OPUS_48_OPTION_ID, FIREWORKS_DEEPSEEK_V4_FLASH_OPTION_ID, FIREWORKS_DEEPSEEK_VISION_PRIMARY_OPTION_ID, FIREWORKS_DEEPSEEK_VISION_FALLBACK_OPTION_IDS, AUTO_ROUTER_EXCLUDED_BACKEND_OPTION_IDS, AI_GATEWAY_AUTO_ROUTER_OPTION_IDS, MODAL_MODELS, GCP_MODELS, HUGGINGFACE_MODELS, WANDB_MODELS, BEDROCK_MANTLE_MODELS, CODEX_OAUTH_MODELS, CLAUDE_CODE_OAUTH_MODELS, AI_GATEWAY_MODELS, OPENROUTER_MODELS, DEFAULT_OPERATOR_VISION_MODEL_ID, GITHUB_MODELS_VALIDATED_WORKERS, OPENAI_VALIDATED_WORKERS, RAW_FOUNDER_MODEL_OPTIONS, FOUNDER_MODEL_OPTIONS, DEFAULT_FOUNDER_MODEL_SELECTION;
84124
+ var DEFAULT_NIM_MODEL_ID, DEFAULT_FOUNDER_MODEL_OPTION_ID, ALL_MODEL_LANES, WORKER_LANES, REASONING_LANES, DEFAULT_GITHUB_GPT_41_ID, DEFAULT_GITHUB_GPT_41_MINI_ID, DEFAULT_GITHUB_GPT_4O_ID, DEFAULT_CODE_WORKER_MODEL_ID, GCP_SELF_HOSTED_OPTION_ID, DEFAULT_GCP_INFERENCE_MODEL, MODAL_SELF_HOSTED_OPTION_ID, MODAL_MIMO_OPTION_ID, DEFAULT_MODAL_INFERENCE_MODEL, HUGGINGFACE_KIMI_K25_OPTION_ID, WANDB_QWEN_36_35B_A3B_OPTION_ID, WANDB_MINIMAX_M25_OPTION_ID, WANDB_KIMI_K26_OPTION_ID, WANDB_GLM_51_OPTION_ID, WANDB_NEMOTRON_ULTRA_OPTION_ID, WANDB_DEEPSEEK_V4_FLASH_OPTION_ID, WANDB_DEEPSEEK_V4_PRO_OPTION_ID, BEDROCK_KIMI_K25_OPTION_ID, BEDROCK_GLM5_OPTION_ID, BEDROCK_QWEN3_CODER_480B_OPTION_ID, BEDROCK_GPT_OSS_120B_OPTION_ID, BEDROCK_NEMOTRON_SUPER_120B_OPTION_ID, BEDROCK_MINIMAX_M2_OPTION_ID, BEDROCK_DEEPSEEK_V32_OPTION_ID, BEDROCK_QWEN3_VL_235B_OPTION_ID, CODEX_GPT_55_OPTION_ID, CODEX_GPT_54_OPTION_ID, CODEX_GPT_54_MINI_OPTION_ID, CLAUDE_CODE_HAIKU_45_OPTION_ID, CLAUDE_CODE_SONNET_46_OPTION_ID, CLAUDE_CODE_OPUS_48_OPTION_ID, FIREWORKS_DEEPSEEK_V4_FLASH_OPTION_ID, FIREWORKS_DEEPSEEK_VISION_PRIMARY_OPTION_ID, FIREWORKS_DEEPSEEK_VISION_FALLBACK_OPTION_IDS, AUTO_ROUTER_EXCLUDED_BACKEND_OPTION_IDS, AI_GATEWAY_AUTO_ROUTER_OPTION_IDS, MODAL_MODELS, GCP_MODELS, HUGGINGFACE_MODELS, WANDB_MODELS, BEDROCK_MANTLE_MODELS, CODEX_OAUTH_MODELS, CLAUDE_CODE_OAUTH_MODELS, AI_GATEWAY_MODELS, OPENROUTER_MODELS, DEFAULT_OPERATOR_VISION_MODEL_ID, GITHUB_MODELS_VALIDATED_WORKERS, OPENAI_VALIDATED_WORKERS, RAW_FOUNDER_MODEL_OPTIONS, FOUNDER_MODEL_OPTIONS, DEFAULT_FOUNDER_MODEL_SELECTION;
84127
84125
  var init_modelRegistry = __esm({
84128
84126
  "features/perchTerminal/runtime/modelRegistry.ts"() {
84129
84127
  "use strict";
@@ -84169,6 +84167,18 @@ var init_modelRegistry = __esm({
84169
84167
  WANDB_KIMI_K26_OPTION_ID = "wandb-kimi-k2-6";
84170
84168
  WANDB_GLM_51_OPTION_ID = "wandb-zai-org-glm-5-1";
84171
84169
  WANDB_NEMOTRON_ULTRA_OPTION_ID = "wandb-nvidia-nvidia-nemotron-3-ultra-550b-a55b";
84170
+ WANDB_DEEPSEEK_V4_FLASH_OPTION_ID = makeModelOptionId(
84171
+ "wandb",
84172
+ "deepseek-ai/DeepSeek-V4-Flash"
84173
+ );
84174
+ WANDB_DEEPSEEK_V4_PRO_OPTION_ID = makeModelOptionId(
84175
+ "wandb",
84176
+ "deepseek-ai/DeepSeek-V4-Pro"
84177
+ );
84178
+ BEDROCK_KIMI_K25_OPTION_ID = makeModelOptionId(
84179
+ "bedrock_mantle",
84180
+ "moonshotai.kimi-k2.5"
84181
+ );
84172
84182
  BEDROCK_GLM5_OPTION_ID = makeModelOptionId("bedrock_mantle", "zai.glm-5");
84173
84183
  BEDROCK_QWEN3_CODER_480B_OPTION_ID = makeModelOptionId(
84174
84184
  "bedrock_mantle",
@@ -84233,6 +84243,9 @@ var init_modelRegistry = __esm({
84233
84243
  WANDB_KIMI_K26_OPTION_ID,
84234
84244
  WANDB_GLM_51_OPTION_ID,
84235
84245
  WANDB_NEMOTRON_ULTRA_OPTION_ID,
84246
+ WANDB_DEEPSEEK_V4_FLASH_OPTION_ID,
84247
+ WANDB_DEEPSEEK_V4_PRO_OPTION_ID,
84248
+ BEDROCK_KIMI_K25_OPTION_ID,
84236
84249
  BEDROCK_GLM5_OPTION_ID,
84237
84250
  BEDROCK_QWEN3_CODER_480B_OPTION_ID,
84238
84251
  BEDROCK_GPT_OSS_120B_OPTION_ID,
@@ -84459,9 +84472,79 @@ var init_modelRegistry = __esm({
84459
84472
  availabilityNote: "W&B Inference hosted Nemotron 3 Ultra. Text/tools use W&B; browser/image tasks use the NIM vision observer chain when selected."
84460
84473
  }),
84461
84474
  id: WANDB_NEMOTRON_ULTRA_OPTION_ID
84475
+ },
84476
+ {
84477
+ ...makeManualModelOption({
84478
+ providerId: "wandb",
84479
+ modelId: "deepseek-ai/DeepSeek-V4-Flash",
84480
+ label: "W&B \xB7 DeepSeek V4 Flash",
84481
+ providerLabel: "Weights & Biases",
84482
+ vendor: "DeepSeek",
84483
+ family: "V4 Flash",
84484
+ groupLabel: "Hosted / W&B Inference",
84485
+ contextWindow: 104e4,
84486
+ lanes: ALL_MODEL_LANES,
84487
+ reasoningSupport: "false",
84488
+ envKey: "WANDB_API_KEY",
84489
+ adapterStatus: "wired",
84490
+ modality: "chat",
84491
+ capabilities: ["code", "agentic_coding"],
84492
+ costTier: "standard",
84493
+ userFacing: true,
84494
+ manualOnly: true,
84495
+ availabilityNote: "W&B Inference hosted DeepSeek V4 Flash. Text/tools use WANDB_API_KEY; browser/image tasks use the NIM vision observer chain when the W&B DeepSeek Flash backend card is selected."
84496
+ }),
84497
+ id: WANDB_DEEPSEEK_V4_FLASH_OPTION_ID
84498
+ },
84499
+ {
84500
+ ...makeManualModelOption({
84501
+ providerId: "wandb",
84502
+ modelId: "deepseek-ai/DeepSeek-V4-Pro",
84503
+ label: "W&B \xB7 DeepSeek V4 Pro",
84504
+ providerLabel: "Weights & Biases",
84505
+ vendor: "DeepSeek",
84506
+ family: "V4 Pro",
84507
+ groupLabel: "Hosted / W&B Inference",
84508
+ contextWindow: 104e4,
84509
+ lanes: ALL_MODEL_LANES,
84510
+ reasoningSupport: "false",
84511
+ envKey: "WANDB_API_KEY",
84512
+ adapterStatus: "wired",
84513
+ modality: "chat",
84514
+ capabilities: ["code", "agentic_coding"],
84515
+ costTier: "premium",
84516
+ userFacing: true,
84517
+ manualOnly: true,
84518
+ availabilityNote: "W&B Inference hosted DeepSeek V4 Pro. Text/tools use WANDB_API_KEY; browser/image tasks use the NIM vision observer chain when the W&B DeepSeek Pro backend card is selected."
84519
+ }),
84520
+ id: WANDB_DEEPSEEK_V4_PRO_OPTION_ID
84462
84521
  }
84463
84522
  ];
84464
84523
  BEDROCK_MANTLE_MODELS = [
84524
+ {
84525
+ ...makeManualModelOption({
84526
+ providerId: "bedrock_mantle",
84527
+ modelId: "moonshotai.kimi-k2.5",
84528
+ label: "Bedrock Mantle \xB7 Kimi K2.5 Vision",
84529
+ providerLabel: "Bedrock Mantle",
84530
+ vendor: "Moonshot AI",
84531
+ family: "Kimi K2.5",
84532
+ groupLabel: "Hosted / Bedrock Mantle",
84533
+ contextWindow: 256e3,
84534
+ maxOutputTokens: 16e3,
84535
+ lanes: [...ALL_MODEL_LANES, "vision"],
84536
+ reasoningSupport: "false",
84537
+ envKey: "BEDROCK_MANTLE_API_KEY",
84538
+ adapterStatus: "wired",
84539
+ modality: "vision",
84540
+ capabilities: ["vision", "multimodal", "code", "agentic_coding"],
84541
+ costTier: "premium",
84542
+ userFacing: true,
84543
+ manualOnly: true,
84544
+ availabilityNote: "Bedrock Mantle Kimi K2.5 multimodal. Native vision on moonshotai.kimi-k2.5; uses BEDROCK_MANTLE_API_KEY and BEDROCK_MANTLE_BASE_URL if set."
84545
+ }),
84546
+ id: BEDROCK_KIMI_K25_OPTION_ID
84547
+ },
84465
84548
  {
84466
84549
  ...makeManualModelOption({
84467
84550
  providerId: "bedrock_mantle",
@@ -91025,6 +91108,7 @@ Final answers lead with findings, name artifacts or delivery status, and give on
91025
91108
  var MARKET_DESK_TOOL_NAMES;
91026
91109
  var init_marketDeskAccess = __esm({
91027
91110
  "features/perchTerminal/runtime/marketDesk/marketDeskAccess.ts"() {
91111
+ "use strict";
91028
91112
  init_toolNames();
91029
91113
  MARKET_DESK_TOOL_NAMES = /* @__PURE__ */ new Set([
91030
91114
  TOOL_NAMES.getMarketSignal,
@@ -91704,6 +91788,7 @@ function listFinancialPlaybooks() {
91704
91788
  var AP_AUDIT_PACKET_DEF, PLAYBOOKS;
91705
91789
  var init_registry2 = __esm({
91706
91790
  "features/perchTerminal/runtime/financialPlaybooks/registry.ts"() {
91791
+ "use strict";
91707
91792
  init_managedWorkflowRegistry2();
91708
91793
  init_toolNames();
91709
91794
  AP_AUDIT_PACKET_DEF = {
@@ -93085,7 +93170,7 @@ var init_agentSkillRegistry = __esm({
93085
93170
  "name": "wait-operator",
93086
93171
  "description": "Watch bounded external or local conditions, poll deployment and job status, wait through short-running tasks, and resume with verified state instead of guessing.",
93087
93172
  "path": "features/perchTerminal/agentPlatform/skills/wait-operator/SKILL.md",
93088
- "body": "\n# wait-operator\n\nUse this skill when the user asks Perch to wait, watch, poll, monitor, check back, or keep an eye on a deployment, CI run, background job, file creation, local server, browser page, or other condition.\n\n## Operating Rules\n\n- Treat waiting as an active bounded loop: define the condition, timeout, interval, and failure states before polling.\n- Never sleep indefinitely. Use short intervals and a clear maximum wait unless the user explicitly asks for a longer watch.\n- Prefer read-only checks: status commands, existing logs, HTTP status endpoints, browser observe/wait, or file existence checks.\n- For deployments and CI, distinguish pending, ready/success, failed, canceled, timed out, and unknown. Do not call a run ready from elapsed time alone.\n- Report the last observed state if the wait times out or credentials/session state blocks verification.\n- Avoid noisy transcript spam. Group repeated polling into a short progress summary unless the user asks to see every check.\n- If the user asks for a real follow-up after this turn rather than an in-turn wait, create or suggest the appropriate automation instead of pretending the current turn can run forever.\n\n## Verification\n\nFinish only after the watched condition is directly verified or a blocker is named. Include the evidence source: command status, page state, URL, log line, file path, or timestamped last check.",
93173
+ "body": "\n# wait-operator\n\nUse this skill when the user asks Perch to wait, watch, poll, monitor, check back, or keep an eye on a deployment, CI run, background job, file creation, local server, browser page, or other condition.\n\n## Operating Rules\n\n- **Background tasks (run_in_background):** after backgrounding a long-running command, call wait_for_background_task(taskId) to end your turn and be automatically woken with the result. NEVER busy-poll check_background_task in a loop \u2014 that wastes iterations and never triggers the wake path. One check is fine for a specific reason (e.g. reporting current progress on user request); repeated polling is always wrong.\n- Treat waiting as an active bounded loop: define the condition, timeout, interval, and failure states before polling.\n- Never sleep indefinitely. Use short intervals and a clear maximum wait unless the user explicitly asks for a longer watch.\n- Prefer read-only checks: status commands, existing logs, HTTP status endpoints, browser observe/wait, or file existence checks.\n- For deployments and CI, distinguish pending, ready/success, failed, canceled, timed out, and unknown. Do not call a run ready from elapsed time alone.\n- Report the last observed state if the wait times out or credentials/session state blocks verification.\n- Avoid noisy transcript spam. Group repeated polling into a short progress summary unless the user asks to see every check.\n- If the user asks for a real follow-up after this turn rather than an in-turn wait, create or suggest the appropriate automation instead of pretending the current turn can run forever.\n\n## Verification\n\nFinish only after the watched condition is directly verified or a blocker is named. Include the evidence source: command status, page state, URL, log line, file path, or timestamped last check.",
93089
93174
  "surface": {
93090
93175
  "gui": "supported",
93091
93176
  "cli": "supported"
@@ -115527,10 +115612,10 @@ function matchStringTarget(hostname, target) {
115527
115612
  }
115528
115613
  return false;
115529
115614
  }
115530
- function getDefaultPropagationTargets(supabaseUrl) {
115615
+ function getDefaultPropagationTargets(supabaseUrl2) {
115531
115616
  const targets = [];
115532
115617
  try {
115533
- const url = new URL(supabaseUrl);
115618
+ const url = new URL(supabaseUrl2);
115534
115619
  targets.push(url.hostname);
115535
115620
  } catch (error) {
115536
115621
  }
@@ -115627,8 +115712,8 @@ function applySettingDefaults(options, defaults) {
115627
115712
  else delete result2.accessToken;
115628
115713
  return result2;
115629
115714
  }
115630
- function validateSupabaseUrl(supabaseUrl) {
115631
- const trimmedUrl = supabaseUrl === null || supabaseUrl === void 0 ? void 0 : supabaseUrl.trim();
115715
+ function validateSupabaseUrl(supabaseUrl2) {
115716
+ const trimmedUrl = supabaseUrl2 === null || supabaseUrl2 === void 0 ? void 0 : supabaseUrl2.trim();
115632
115717
  if (!trimmedUrl) throw new Error("supabaseUrl is required.");
115633
115718
  if (!trimmedUrl.match(/^https?:\/\//i)) throw new Error("Invalid supabaseUrl: Must be a valid HTTP or HTTPS URL.");
115634
115719
  try {
@@ -115686,12 +115771,12 @@ var init_dist4 = __esm({
115686
115771
  resolveHeadersConstructor = () => {
115687
115772
  return Headers;
115688
115773
  };
115689
- fetchWithAuth = (supabaseKey, supabaseUrl, getAccessToken, customFetch, tracePropagationOptions) => {
115774
+ fetchWithAuth = (supabaseKey, supabaseUrl2, getAccessToken, customFetch, tracePropagationOptions) => {
115690
115775
  const fetch$1 = resolveFetch2(customFetch);
115691
115776
  const HeadersConstructor = resolveHeadersConstructor();
115692
115777
  const traceEnabled = (tracePropagationOptions === null || tracePropagationOptions === void 0 ? void 0 : tracePropagationOptions.enabled) === true;
115693
115778
  const respectSampling = (tracePropagationOptions === null || tracePropagationOptions === void 0 ? void 0 : tracePropagationOptions.respectSamplingDecision) !== false;
115694
- const traceTargets = traceEnabled ? getDefaultPropagationTargets(supabaseUrl) : null;
115779
+ const traceTargets = traceEnabled ? getDefaultPropagationTargets(supabaseUrl2) : null;
115695
115780
  return async (input, init) => {
115696
115781
  var _await$getAccessToken;
115697
115782
  const accessToken = (_await$getAccessToken = await getAccessToken()) !== null && _await$getAccessToken !== void 0 ? _await$getAccessToken : supabaseKey;
@@ -115902,11 +115987,11 @@ var init_dist4 = __esm({
115902
115987
  * const { data } = await supabase.from('profiles').select('*')
115903
115988
  * ```
115904
115989
  */
115905
- constructor(supabaseUrl, supabaseKey, options) {
115990
+ constructor(supabaseUrl2, supabaseKey, options) {
115906
115991
  var _settings$auth$storag, _settings$global$head;
115907
- this.supabaseUrl = supabaseUrl;
115992
+ this.supabaseUrl = supabaseUrl2;
115908
115993
  this.supabaseKey = supabaseKey;
115909
- const baseUrl = validateSupabaseUrl(supabaseUrl);
115994
+ const baseUrl = validateSupabaseUrl(supabaseUrl2);
115910
115995
  if (!supabaseKey) throw new Error("supabaseKey is required.");
115911
115996
  this.realtimeUrl = new URL("realtime/v1", baseUrl);
115912
115997
  this.realtimeUrl.protocol = this.realtimeUrl.protocol.replace("http", "ws");
@@ -115934,7 +116019,7 @@ var init_dist4 = __esm({
115934
116019
  throw new Error(`@supabase/supabase-js: Supabase Client is configured with the accessToken option, accessing supabase.auth.${String(prop)} is not possible`);
115935
116020
  } });
115936
116021
  }
115937
- this.fetch = fetchWithAuth(supabaseKey, supabaseUrl, this._getAccessToken.bind(this), settings.global.fetch, settings.tracePropagation);
116022
+ this.fetch = fetchWithAuth(supabaseKey, supabaseUrl2, this._getAccessToken.bind(this), settings.global.fetch, settings.tracePropagation);
115938
116023
  this.realtime = this._initRealtimeClient(_objectSpread23({
115939
116024
  headers: this.headers,
115940
116025
  accessToken: this._getAccessToken.bind(this),
@@ -116118,8 +116203,8 @@ var init_dist4 = __esm({
116118
116203
  }
116119
116204
  }
116120
116205
  };
116121
- createClient = (supabaseUrl, supabaseKey, options) => {
116122
- return new SupabaseClient(supabaseUrl, supabaseKey, options);
116206
+ createClient = (supabaseUrl2, supabaseKey, options) => {
116207
+ return new SupabaseClient(supabaseUrl2, supabaseKey, options);
116123
116208
  };
116124
116209
  if (shouldShowDeprecationWarning()) console.warn("\u26A0\uFE0F Node.js 18 and below are deprecated and will no longer be supported in future versions of @supabase/supabase-js. Please upgrade to Node.js 20 or later. For more information, visit: https://github.com/orgs/supabase/discussions/37217");
116125
116210
  }
@@ -116245,6 +116330,33 @@ var init_inferenceCost = __esm({
116245
116330
  outputUsdPer1k: 275e-5,
116246
116331
  cachedInputUsdPer1k: 15e-5
116247
116332
  },
116333
+ [WANDB_DEEPSEEK_V4_FLASH_OPTION_ID]: {
116334
+ modelOptionId: WANDB_DEEPSEEK_V4_FLASH_OPTION_ID,
116335
+ providerId: "wandb",
116336
+ modelId: "deepseek-ai/DeepSeek-V4-Flash",
116337
+ label: "W&B DeepSeek V4 Flash",
116338
+ inputUsdPer1k: 14e-5,
116339
+ outputUsdPer1k: 28e-5,
116340
+ cachedInputUsdPer1k: 7e-5
116341
+ },
116342
+ [WANDB_DEEPSEEK_V4_PRO_OPTION_ID]: {
116343
+ modelOptionId: WANDB_DEEPSEEK_V4_PRO_OPTION_ID,
116344
+ providerId: "wandb",
116345
+ modelId: "deepseek-ai/DeepSeek-V4-Pro",
116346
+ label: "W&B DeepSeek V4 Pro",
116347
+ inputUsdPer1k: 174e-5,
116348
+ outputUsdPer1k: 348e-5,
116349
+ cachedInputUsdPer1k: 14e-5
116350
+ },
116351
+ [BEDROCK_KIMI_K25_OPTION_ID]: {
116352
+ modelOptionId: BEDROCK_KIMI_K25_OPTION_ID,
116353
+ providerId: "bedrock_mantle",
116354
+ modelId: "moonshotai.kimi-k2.5",
116355
+ label: "Bedrock Mantle \xB7 Kimi K2.5 Vision",
116356
+ inputUsdPer1k: 6e-4,
116357
+ outputUsdPer1k: 3e-3,
116358
+ cachedInputUsdPer1k: 6e-4
116359
+ },
116248
116360
  [BEDROCK_GLM5_OPTION_ID]: {
116249
116361
  modelOptionId: BEDROCK_GLM5_OPTION_ID,
116250
116362
  providerId: "bedrock_mantle",
@@ -118546,8 +118658,15 @@ function buildBody(option, opts, model, stream, includeResponseFormat = true) {
118546
118658
  body.tool_choice = opts.toolChoice ?? "auto";
118547
118659
  }
118548
118660
  if (includeResponseFormat && opts.responseFormat) body.response_format = opts.responseFormat;
118549
- if (option.providerId === "wandb" && option.modelId.startsWith("Qwen/")) {
118550
- body.chat_template_kwargs = { enable_thinking: false };
118661
+ const reasoning = opts.reasoning;
118662
+ if (option.providerId === "wandb") {
118663
+ if (reasoning && typeof reasoning.enableThinking === "boolean") {
118664
+ body.chat_template_kwargs = { enable_thinking: reasoning.enableThinking };
118665
+ } else if (option.modelId.startsWith("Qwen/")) {
118666
+ body.chat_template_kwargs = { enable_thinking: false };
118667
+ }
118668
+ } else if (reasoning?.reasoningEffort && (option.providerId === "bedrock_mantle" || option.providerId === "cerebras")) {
118669
+ body.reasoning_effort = reasoning.reasoningEffort;
118551
118670
  }
118552
118671
  if (stream) {
118553
118672
  body.stream = true;
@@ -118994,7 +119113,80 @@ var init_autoRouter = __esm({
118994
119113
  }
118995
119114
  });
118996
119115
 
119116
+ // features/perchTerminal/runtime/roost.ts
119117
+ function normalizeRoostTier(value) {
119118
+ if (value === "max") return "pro_max";
119119
+ return isRoostTier(value) ? value : null;
119120
+ }
119121
+ function normalizeRoostModelChoice(value) {
119122
+ if (value === "internal") return "internal";
119123
+ return normalizeRoostTier(value);
119124
+ }
119125
+ function isRoostTier(value) {
119126
+ return value === "standard" || value === "standard_max" || value === "pro" || value === "pro_max";
119127
+ }
119128
+ var ROOST_TIER_LABELS;
119129
+ var init_roost = __esm({
119130
+ "features/perchTerminal/runtime/roost.ts"() {
119131
+ "use strict";
119132
+ init_modelRegistry();
119133
+ ROOST_TIER_LABELS = {
119134
+ standard: "Standard",
119135
+ standard_max: "Standard Max",
119136
+ pro: "Pro",
119137
+ pro_max: "Pro Max"
119138
+ };
119139
+ }
119140
+ });
119141
+
119142
+ // features/perchTerminal/runtime/roostUserSelectionClient.ts
119143
+ function coerceSelection(raw) {
119144
+ const choice = normalizeRoostModelChoice(raw?.choice);
119145
+ return {
119146
+ choice: choice ?? DEFAULT_ROOST_USER_SELECTION.choice,
119147
+ reasoningEnabled: typeof raw?.reasoningEnabled === "boolean" ? raw.reasoningEnabled : DEFAULT_ROOST_USER_SELECTION.reasoningEnabled
119148
+ };
119149
+ }
119150
+ function peekStoredRoostUserSelection() {
119151
+ if (typeof window === "undefined") return null;
119152
+ try {
119153
+ const raw = window.localStorage.getItem(ROOST_USER_SELECTION_STORAGE_KEY);
119154
+ if (!raw) return null;
119155
+ return coerceSelection(JSON.parse(raw));
119156
+ } catch {
119157
+ return null;
119158
+ }
119159
+ }
119160
+ function setRoostUserSelectionForNode(selection) {
119161
+ nodeSelectionOverride = selection ? coerceSelection(selection) : null;
119162
+ }
119163
+ function getEffectiveRoostUserSelection() {
119164
+ if (typeof window !== "undefined") return peekStoredRoostUserSelection();
119165
+ return nodeSelectionOverride;
119166
+ }
119167
+ var ROOST_USER_SELECTION_STORAGE_KEY, DEFAULT_ROOST_USER_SELECTION, nodeSelectionOverride;
119168
+ var init_roostUserSelectionClient = __esm({
119169
+ "features/perchTerminal/runtime/roostUserSelectionClient.ts"() {
119170
+ "use strict";
119171
+ init_roost();
119172
+ ROOST_USER_SELECTION_STORAGE_KEY = "perch.roostUserSelection.v1";
119173
+ DEFAULT_ROOST_USER_SELECTION = {
119174
+ choice: "standard",
119175
+ reasoningEnabled: true
119176
+ };
119177
+ nodeSelectionOverride = null;
119178
+ }
119179
+ });
119180
+
118997
119181
  // features/perchTerminal/runtime/modelRouter.ts
119182
+ function roostUserSelectionBodyFields() {
119183
+ const selection = getEffectiveRoostUserSelection();
119184
+ if (!selection) return {};
119185
+ return {
119186
+ roostModelChoice: selection.choice,
119187
+ roostReasoning: selection.reasoningEnabled
119188
+ };
119189
+ }
118998
119190
  async function callModelRouter(_config, request, opts) {
118999
119191
  const explicitProxyUrl = resolveModelCallProxyUrl(opts?.cliServerAppUrl ?? null);
119000
119192
  if (typeof window !== "undefined") {
@@ -119021,7 +119213,8 @@ async function callModelRouter(_config, request, opts) {
119021
119213
  responseFormat: request.responseFormat,
119022
119214
  preferredModelId: opts?.preferredModelId ?? null,
119023
119215
  avoidModelIds: opts?.avoidModelIds,
119024
- attribution: opts?.attribution ?? null
119216
+ attribution: opts?.attribution ?? null,
119217
+ reasoning: opts?.reasoning ?? null
119025
119218
  };
119026
119219
  try {
119027
119220
  if (request.onChunk || request.onReasoningChunk || request.onStreamEvent) {
@@ -119147,7 +119340,8 @@ async function callModelRouterViaServer(request, opts, endpoint = "/api/perch-te
119147
119340
  raceMode: opts?.raceMode,
119148
119341
  preferredModelId: opts?.preferredModelId ?? null,
119149
119342
  avoidModelIds: opts?.avoidModelIds ?? [],
119150
- attribution: opts?.attribution ?? null
119343
+ attribution: opts?.attribution ?? null,
119344
+ ...roostUserSelectionBodyFields()
119151
119345
  });
119152
119346
  const response = await fetchModelProxyWithRetry(endpoint, {
119153
119347
  method: "POST",
@@ -119415,6 +119609,7 @@ var init_modelRouter = __esm({
119415
119609
  init_modelRegistry();
119416
119610
  init_contextMeter();
119417
119611
  init_inferenceUsageRecorder();
119612
+ init_roostUserSelectionClient();
119418
119613
  init_providerModelStep();
119419
119614
  init_toolCallNormalizer();
119420
119615
  MODEL_CALL_PROXY_ENV = "PERCH_MODEL_CALL_PROXY_URL";
@@ -119434,7 +119629,7 @@ var init_accountHelpers = __esm({
119434
119629
 
119435
119630
  // features/perchTerminal/runtime/fireworksDeepSeekPreset.ts
119436
119631
  function usesNimVisionObserverPreset(selection) {
119437
- return selection?.modelBackendPreset === "fireworks_deepseek" || selection?.modelBackendPreset === "wandb_minimax" || selection?.modelBackendPreset === "wandb_glm51" || selection?.modelBackendPreset === "wandb_nemotron_ultra" || selection?.modelBackendPreset === "bedrock_glm5" || selection?.modelBackendPreset === "bedrock_qwen3_coder" || selection?.modelBackendPreset === "bedrock_gpt_oss_120b" || selection?.modelBackendPreset === "bedrock_nemotron_super" || selection?.modelBackendPreset === "bedrock_minimax_m2" || selection?.modelBackendPreset === "bedrock_deepseek_v32";
119632
+ return selection?.modelBackendPreset === "fireworks_deepseek" || selection?.modelBackendPreset === "wandb_minimax" || selection?.modelBackendPreset === "wandb_glm51" || selection?.modelBackendPreset === "wandb_nemotron_ultra" || selection?.modelBackendPreset === "wandb_deepseek_flash" || selection?.modelBackendPreset === "wandb_deepseek_pro" || selection?.modelBackendPreset === "bedrock_glm5" || selection?.modelBackendPreset === "bedrock_qwen3_coder" || selection?.modelBackendPreset === "bedrock_gpt_oss_120b" || selection?.modelBackendPreset === "bedrock_nemotron_super" || selection?.modelBackendPreset === "bedrock_minimax_m2" || selection?.modelBackendPreset === "bedrock_deepseek_v32";
119438
119633
  }
119439
119634
  function resolveVisionOptionChain(selection) {
119440
119635
  const chain2 = [];
@@ -128819,10 +129014,10 @@ var require_dist4 = __commonJS({
128819
129014
  }
128820
129015
  return false;
128821
129016
  }
128822
- function getDefaultPropagationTargets2(supabaseUrl) {
129017
+ function getDefaultPropagationTargets2(supabaseUrl2) {
128823
129018
  const targets = [];
128824
129019
  try {
128825
- const url = new URL(supabaseUrl);
129020
+ const url = new URL(supabaseUrl2);
128826
129021
  targets.push(url.hostname);
128827
129022
  } catch (error) {
128828
129023
  }
@@ -128888,12 +129083,12 @@ var require_dist4 = __commonJS({
128888
129083
  var resolveHeadersConstructor2 = () => {
128889
129084
  return Headers;
128890
129085
  };
128891
- var fetchWithAuth2 = (supabaseKey, supabaseUrl, getAccessToken, customFetch, tracePropagationOptions) => {
129086
+ var fetchWithAuth2 = (supabaseKey, supabaseUrl2, getAccessToken, customFetch, tracePropagationOptions) => {
128892
129087
  const fetch$1 = resolveFetch3(customFetch);
128893
129088
  const HeadersConstructor = resolveHeadersConstructor2();
128894
129089
  const traceEnabled = (tracePropagationOptions === null || tracePropagationOptions === void 0 ? void 0 : tracePropagationOptions.enabled) === true;
128895
129090
  const respectSampling = (tracePropagationOptions === null || tracePropagationOptions === void 0 ? void 0 : tracePropagationOptions.respectSamplingDecision) !== false;
128896
- const traceTargets = traceEnabled ? getDefaultPropagationTargets2(supabaseUrl) : null;
129091
+ const traceTargets = traceEnabled ? getDefaultPropagationTargets2(supabaseUrl2) : null;
128897
129092
  return async (input, init) => {
128898
129093
  var _await$getAccessToken;
128899
129094
  const accessToken = (_await$getAccessToken = await getAccessToken()) !== null && _await$getAccessToken !== void 0 ? _await$getAccessToken : supabaseKey;
@@ -128949,8 +129144,8 @@ var require_dist4 = __commonJS({
128949
129144
  else delete result2.accessToken;
128950
129145
  return result2;
128951
129146
  }
128952
- function validateSupabaseUrl2(supabaseUrl) {
128953
- const trimmedUrl = supabaseUrl === null || supabaseUrl === void 0 ? void 0 : supabaseUrl.trim();
129147
+ function validateSupabaseUrl2(supabaseUrl2) {
129148
+ const trimmedUrl = supabaseUrl2 === null || supabaseUrl2 === void 0 ? void 0 : supabaseUrl2.trim();
128954
129149
  if (!trimmedUrl) throw new Error("supabaseUrl is required.");
128955
129150
  if (!trimmedUrl.match(/^https?:\/\//i)) throw new Error("Invalid supabaseUrl: Must be a valid HTTP or HTTPS URL.");
128956
129151
  try {
@@ -129152,11 +129347,11 @@ var require_dist4 = __commonJS({
129152
129347
  * const { data } = await supabase.from('profiles').select('*')
129153
129348
  * ```
129154
129349
  */
129155
- constructor(supabaseUrl, supabaseKey, options) {
129350
+ constructor(supabaseUrl2, supabaseKey, options) {
129156
129351
  var _settings$auth$storag, _settings$global$head;
129157
- this.supabaseUrl = supabaseUrl;
129352
+ this.supabaseUrl = supabaseUrl2;
129158
129353
  this.supabaseKey = supabaseKey;
129159
- const baseUrl = validateSupabaseUrl2(supabaseUrl);
129354
+ const baseUrl = validateSupabaseUrl2(supabaseUrl2);
129160
129355
  if (!supabaseKey) throw new Error("supabaseKey is required.");
129161
129356
  this.realtimeUrl = new URL("realtime/v1", baseUrl);
129162
129357
  this.realtimeUrl.protocol = this.realtimeUrl.protocol.replace("http", "ws");
@@ -129184,7 +129379,7 @@ var require_dist4 = __commonJS({
129184
129379
  throw new Error(`@supabase/supabase-js: Supabase Client is configured with the accessToken option, accessing supabase.auth.${String(prop)} is not possible`);
129185
129380
  } });
129186
129381
  }
129187
- this.fetch = fetchWithAuth2(supabaseKey, supabaseUrl, this._getAccessToken.bind(this), settings.global.fetch, settings.tracePropagation);
129382
+ this.fetch = fetchWithAuth2(supabaseKey, supabaseUrl2, this._getAccessToken.bind(this), settings.global.fetch, settings.tracePropagation);
129188
129383
  this.realtime = this._initRealtimeClient(_objectSpread24({
129189
129384
  headers: this.headers,
129190
129385
  accessToken: this._getAccessToken.bind(this),
@@ -129368,8 +129563,8 @@ var require_dist4 = __commonJS({
129368
129563
  }
129369
129564
  }
129370
129565
  };
129371
- var createClient3 = (supabaseUrl, supabaseKey, options) => {
129372
- return new SupabaseClient2(supabaseUrl, supabaseKey, options);
129566
+ var createClient3 = (supabaseUrl2, supabaseKey, options) => {
129567
+ return new SupabaseClient2(supabaseUrl2, supabaseKey, options);
129373
129568
  };
129374
129569
  function shouldShowDeprecationWarning2() {
129375
129570
  if (typeof window !== "undefined") return false;
@@ -130430,13 +130625,13 @@ var require_createBrowserClient = __commonJS({
130430
130625
  var cookies_1 = require_cookies();
130431
130626
  var warnDeprecatedPackage_1 = require_warnDeprecatedPackage();
130432
130627
  var cachedBrowserClient;
130433
- function createBrowserClient2(supabaseUrl, supabaseKey, options) {
130628
+ function createBrowserClient2(supabaseUrl2, supabaseKey, options) {
130434
130629
  (0, warnDeprecatedPackage_1.warnIfUsingDeprecatedAuthHelpersPackage)();
130435
130630
  const shouldUseSingleton = options?.isSingleton === true || (!options || !("isSingleton" in options)) && (0, utils_1.isBrowser)();
130436
130631
  if (shouldUseSingleton && cachedBrowserClient) {
130437
130632
  return cachedBrowserClient;
130438
130633
  }
130439
- if (!supabaseUrl || !supabaseKey) {
130634
+ if (!supabaseUrl2 || !supabaseKey) {
130440
130635
  throw new Error(`@supabase/ssr: Your project's URL and API key are required to create a Supabase client!
130441
130636
 
130442
130637
  Check your Supabase project's API settings to find these values
@@ -130447,7 +130642,7 @@ https://supabase.com/dashboard/project/_/settings/api`);
130447
130642
  ...options,
130448
130643
  cookieEncoding: options?.cookieEncoding ?? "base64url"
130449
130644
  }, false);
130450
- const client = (0, supabase_js_1.createClient)(supabaseUrl, supabaseKey, {
130645
+ const client = (0, supabase_js_1.createClient)(supabaseUrl2, supabaseKey, {
130451
130646
  // TODO: resolve type error
130452
130647
  ...options,
130453
130648
  global: {
@@ -130483,15 +130678,15 @@ var require_createServerClient = __commonJS({
130483
130678
  "node_modules/@supabase/ssr/dist/main/createServerClient.js"(exports2) {
130484
130679
  "use strict";
130485
130680
  Object.defineProperty(exports2, "__esModule", { value: true });
130486
- exports2.createServerClient = createServerClient;
130681
+ exports2.createServerClient = createServerClient2;
130487
130682
  var supabase_js_1 = require_dist4();
130488
130683
  var version_1 = require_version3();
130489
130684
  var cookies_1 = require_cookies();
130490
130685
  var helpers_1 = require_helpers2();
130491
130686
  var warnDeprecatedPackage_1 = require_warnDeprecatedPackage();
130492
- function createServerClient(supabaseUrl, supabaseKey, options) {
130687
+ function createServerClient2(supabaseUrl2, supabaseKey, options) {
130493
130688
  (0, warnDeprecatedPackage_1.warnIfUsingDeprecatedAuthHelpersPackage)();
130494
- if (!supabaseUrl || !supabaseKey) {
130689
+ if (!supabaseUrl2 || !supabaseKey) {
130495
130690
  throw new Error(`Your project's URL and Key are required to create a Supabase client!
130496
130691
 
130497
130692
  Check your Supabase project's API settings to find these values
@@ -130502,7 +130697,7 @@ https://supabase.com/dashboard/project/_/settings/api`);
130502
130697
  ...options,
130503
130698
  cookieEncoding: options?.cookieEncoding ?? "base64url"
130504
130699
  }, true);
130505
- const client = (0, supabase_js_1.createClient)(supabaseUrl, supabaseKey, {
130700
+ const client = (0, supabase_js_1.createClient)(supabaseUrl2, supabaseKey, {
130506
130701
  // TODO: resolve type error
130507
130702
  ...options,
130508
130703
  global: {
@@ -130581,6 +130776,36 @@ var require_main4 = __commonJS({
130581
130776
  }
130582
130777
  });
130583
130778
 
130779
+ // lib/supabase/factory.ts
130780
+ function supabaseUrl() {
130781
+ return process.env.NEXT_PUBLIC_SUPABASE_URL;
130782
+ }
130783
+ function supabaseAnonKey() {
130784
+ return process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
130785
+ }
130786
+ function authCookieOptions() {
130787
+ const secure = process.env.NODE_ENV === "production";
130788
+ return {
130789
+ cookieOptions: {
130790
+ path: "/",
130791
+ sameSite: "lax",
130792
+ ...secure ? { secure: true } : {}
130793
+ }
130794
+ };
130795
+ }
130796
+ function createBrowserSupabaseClient() {
130797
+ return (0, import_ssr.createBrowserClient)(supabaseUrl(), supabaseAnonKey(), {
130798
+ isSingleton: true,
130799
+ ...authCookieOptions()
130800
+ });
130801
+ }
130802
+ var import_ssr;
130803
+ var init_factory = __esm({
130804
+ "lib/supabase/factory.ts"() {
130805
+ import_ssr = __toESM(require_main4());
130806
+ }
130807
+ });
130808
+
130584
130809
  // lib/supabase/client.ts
130585
130810
  function createClient2() {
130586
130811
  if (!isSupabaseConfigured()) {
@@ -130589,19 +130814,15 @@ function createClient2() {
130589
130814
  );
130590
130815
  }
130591
130816
  if (!browserClient) {
130592
- browserClient = (0, import_ssr.createBrowserClient)(
130593
- process.env.NEXT_PUBLIC_SUPABASE_URL,
130594
- process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
130595
- { isSingleton: true }
130596
- );
130817
+ browserClient = createBrowserSupabaseClient();
130597
130818
  }
130598
130819
  return browserClient;
130599
130820
  }
130600
- var import_ssr, browserClient;
130821
+ var browserClient;
130601
130822
  var init_client = __esm({
130602
130823
  "lib/supabase/client.ts"() {
130603
- import_ssr = __toESM(require_main4());
130604
130824
  init_config();
130825
+ init_factory();
130605
130826
  }
130606
130827
  });
130607
130828
 
@@ -135384,7 +135605,7 @@ function getDesktopToolDefinitions() {
135384
135605
  type: "function",
135385
135606
  function: {
135386
135607
  name: TOOL_NAMES.runInBackground,
135387
- description: "Launch a long-running shell command in the background. Returns immediately with a taskId; the command keeps running detached. Use check_background_task to poll, or wait_for_background_task to be woken when it finishes. Permission mode gates execution.",
135608
+ description: "Launch a long-running shell command in the background. Returns immediately with a taskId; the command keeps running detached. After launching, call wait_for_background_task(taskId) to end your turn and be automatically re-invoked when it finishes. Permission mode gates execution.",
135388
135609
  parameters: {
135389
135610
  type: "object",
135390
135611
  properties: {
@@ -135406,7 +135627,7 @@ function getDesktopToolDefinitions() {
135406
135627
  type: "function",
135407
135628
  function: {
135408
135629
  name: TOOL_NAMES.checkBackgroundTask,
135409
- description: "Check the status and recent output of a background task by taskId. Returns status (running/done/failed/killed/unknown), exit code, runtime, and an output preview.",
135630
+ description: "One-off status check for a background task. Returns status, exit code, runtime, and output preview. Do NOT call this repeatedly to wait for completion \u2014 use wait_for_background_task instead.",
135410
135631
  parameters: {
135411
135632
  type: "object",
135412
135633
  properties: {
@@ -135448,7 +135669,7 @@ function getDesktopToolDefinitions() {
135448
135669
  type: "function",
135449
135670
  function: {
135450
135671
  name: TOOL_NAMES.waitForBackgroundTask,
135451
- description: "Ask to be woken when a background task finishes. This does NOT block: it registers a wake, and you should end your turn. The runtime will re-invoke you with a system-initiated turn carrying the task result once it completes. Auto-wake only fires in autonomous permission modes.",
135672
+ description: "After launching long-running work, call this to end your turn and be automatically re-invoked when it finishes. This is how you wait \u2014 do NOT poll check_background_task in a loop. The runtime delivers a system-initiated turn with the result once the task completes. Auto-wake fires in autonomous permission modes (auto_review / take_the_wheel).",
135452
135673
  parameters: {
135453
135674
  type: "object",
135454
135675
  properties: {
@@ -138909,6 +139130,7 @@ function offSandboxEvent(runId, handler) {
138909
139130
  var LOCAL_WORKSPACE_ACCESS_UNAVAILABLE;
138910
139131
  var init_bridge = __esm({
138911
139132
  "features/perchTerminal/desktop/bridge.ts"() {
139133
+ "use strict";
138912
139134
  LOCAL_WORKSPACE_ACCESS_UNAVAILABLE = "Local workspace access is unavailable. Open Perch Desktop or update the app.";
138913
139135
  }
138914
139136
  });
@@ -197126,6 +197348,7 @@ function recordDispatchBatchResult(tasks, result2, ctx, opts = {}) {
197126
197348
  var lifecycleByRun, MAX_LIFECYCLE_RUNS;
197127
197349
  var init_workerLifecycle = __esm({
197128
197350
  "features/perchTerminal/runtime/workers/workerLifecycle.ts"() {
197351
+ "use strict";
197129
197352
  init_workerManifest();
197130
197353
  lifecycleByRun = /* @__PURE__ */ new Map();
197131
197354
  MAX_LIFECYCLE_RUNS = 200;
@@ -212049,9 +212272,13 @@ var init_backgroundWake = __esm({
212049
212272
  // features/perchTerminal/runtime/toolSystem/tools/background/index.ts
212050
212273
  var background_exports = {};
212051
212274
  __export(background_exports, {
212275
+ __resetPollTrackerForTests: () => __resetPollTrackerForTests,
212052
212276
  backgroundTools: () => backgroundTools
212053
212277
  });
212054
- var UNAVAILABLE, runInBackgroundTool, checkBackgroundTaskTool, listBackgroundTasksTool, killBackgroundTaskTool, waitForBackgroundTaskTool, backgroundTools;
212278
+ function __resetPollTrackerForTests() {
212279
+ pollTracker.clear();
212280
+ }
212281
+ var UNAVAILABLE, pollTracker, POLL_REDIRECT_THRESHOLD, runInBackgroundTool, checkBackgroundTaskTool, listBackgroundTasksTool, killBackgroundTaskTool, waitForBackgroundTaskTool, backgroundTools;
212055
212282
  var init_background = __esm({
212056
212283
  "features/perchTerminal/runtime/toolSystem/tools/background/index.ts"() {
212057
212284
  "use strict";
@@ -212060,6 +212287,8 @@ var init_background = __esm({
212060
212287
  init_backgroundWake();
212061
212288
  init_toolNames();
212062
212289
  UNAVAILABLE = "Background execution is unavailable on this surface. It requires the Perch CLI or Perch Desktop.";
212290
+ pollTracker = /* @__PURE__ */ new Map();
212291
+ POLL_REDIRECT_THRESHOLD = 2;
212063
212292
  runInBackgroundTool = {
212064
212293
  name: TOOL_NAMES.runInBackground,
212065
212294
  classification: { native: false },
@@ -212079,11 +212308,26 @@ var init_background = __esm({
212079
212308
  checkBackgroundTaskTool = {
212080
212309
  name: TOOL_NAMES.checkBackgroundTask,
212081
212310
  classification: { native: false },
212082
- handler: async (args) => {
212311
+ handler: async (args, ctx) => {
212083
212312
  const taskId = String(args.taskId ?? "").trim();
212084
212313
  if (!taskId) return { ok: false, error: "taskId must be a non-empty string." };
212085
212314
  const snapshot = await checkBackgroundTask({ taskId });
212086
212315
  if (snapshot === null) return { ok: false, error: `No background task found for ${taskId}.` };
212316
+ if (snapshot.status === "running") {
212317
+ const key = taskId;
212318
+ const count = (pollTracker.get(key) ?? 0) + 1;
212319
+ pollTracker.set(key, count);
212320
+ if (count >= POLL_REDIRECT_THRESHOLD) {
212321
+ const mode = normalizePermissionMode(ctx.permissionMode);
212322
+ const wakeAvailable = WAKE_ALLOWED_PERMISSION_MODES.has(mode);
212323
+ return {
212324
+ ok: true,
212325
+ task: snapshot,
212326
+ _pollRedirect: true,
212327
+ note: wakeAvailable ? `Stop polling \u2014 call wait_for_background_task("${taskId}") to end this turn and be automatically woken on completion.` : `This task is still running. Auto-wake is unavailable in "${mode}" mode. Tell the user to switch to auto_review or take_the_wheel for auto-wake, or end this turn and check back later.`
212328
+ };
212329
+ }
212330
+ }
212087
212331
  return { ok: true, task: snapshot };
212088
212332
  }
212089
212333
  };
@@ -223449,6 +223693,295 @@ var init_access = __esm({
223449
223693
  }
223450
223694
  });
223451
223695
 
223696
+ // lib/perch-ai/perchTokens.ts
223697
+ function usdToPerchTokens(usd) {
223698
+ if (typeof usd !== "number" || !Number.isFinite(usd) || usd <= 0) return 0;
223699
+ return Math.ceil(usd / PERCH_TOKEN_USD);
223700
+ }
223701
+ function nullableUsdToPerchTokens(usd) {
223702
+ const tokens = usdToPerchTokens(usd);
223703
+ return tokens > 0 ? tokens : null;
223704
+ }
223705
+ function usdLimitToPerchTokens(usd) {
223706
+ if (!Number.isFinite(usd) || usd <= 0) return 0;
223707
+ return Math.round(usd / PERCH_TOKEN_USD);
223708
+ }
223709
+ var PERCH_TOKEN_USD, DEFAULT_PILOT_DAILY_LIMIT_USD, DEFAULT_PILOT_MONTHLY_LIMIT_USD;
223710
+ var init_perchTokens = __esm({
223711
+ "lib/perch-ai/perchTokens.ts"() {
223712
+ PERCH_TOKEN_USD = 1e-3;
223713
+ DEFAULT_PILOT_DAILY_LIMIT_USD = 5;
223714
+ DEFAULT_PILOT_MONTHLY_LIMIT_USD = DEFAULT_PILOT_DAILY_LIMIT_USD * 30;
223715
+ }
223716
+ });
223717
+
223718
+ // features/perchTerminal/persistence/usagePersistence.ts
223719
+ function startOfLocalDay() {
223720
+ const date = /* @__PURE__ */ new Date();
223721
+ date.setHours(0, 0, 0, 0);
223722
+ return date.toISOString();
223723
+ }
223724
+ function startOfRollingWeek() {
223725
+ const date = /* @__PURE__ */ new Date();
223726
+ date.setDate(date.getDate() - 7);
223727
+ return date.toISOString();
223728
+ }
223729
+ function startOfLocalMonth() {
223730
+ const date = /* @__PURE__ */ new Date();
223731
+ date.setDate(1);
223732
+ date.setHours(0, 0, 0, 0);
223733
+ return date.toISOString();
223734
+ }
223735
+ function sumPt(rows, since) {
223736
+ const total = rows.filter((row) => Date.parse(row.created_at) >= Date.parse(since)).reduce((sum, row) => sum + row.total_pt, 0);
223737
+ return total > 0 ? total : null;
223738
+ }
223739
+ function filterInferenceRows(rows, since) {
223740
+ return rows.filter((row) => Date.parse(row.created_at) >= Date.parse(since));
223741
+ }
223742
+ function sumInferenceCost(rows, since) {
223743
+ const total = filterInferenceRows(rows, since).reduce(
223744
+ (sum, row) => sum + Number(row.estimated_cost_usd ?? 0),
223745
+ 0
223746
+ );
223747
+ return total > 0 ? total : null;
223748
+ }
223749
+ function sumInferenceTokens(rows, since) {
223750
+ const total = filterInferenceRows(rows, since).reduce(
223751
+ (sum, row) => sum + Number(row.total_tokens ?? 0),
223752
+ 0
223753
+ );
223754
+ return total > 0 ? total : null;
223755
+ }
223756
+ function countInferenceCalls(rows, since) {
223757
+ const total = filterInferenceRows(rows, since).length;
223758
+ return total > 0 ? total : null;
223759
+ }
223760
+ function createUsagePersistence(supabase) {
223761
+ return {
223762
+ async listRateCards() {
223763
+ const { data, error } = await supabase.from("perch_ai_token_rate_cards").select("*").order("created_at", { ascending: false });
223764
+ if (error) throw error;
223765
+ return data ?? [];
223766
+ },
223767
+ async listUsageRawEvents({
223768
+ userId,
223769
+ workspaceId,
223770
+ limit = 50
223771
+ }) {
223772
+ const { data, error } = await supabase.from("perch_ai_usage_raw_events").select("*").eq("user_id", userId).eq("workspace_id", workspaceId).order("created_at", { ascending: false }).limit(limit);
223773
+ if (error) throw error;
223774
+ return data ?? [];
223775
+ },
223776
+ async listTokenCalculations({
223777
+ userId,
223778
+ workspaceId,
223779
+ since,
223780
+ limit = 250
223781
+ }) {
223782
+ let query = supabase.from("perch_ai_token_calculations").select("*").eq("user_id", userId).eq("workspace_id", workspaceId).order("created_at", { ascending: false }).limit(limit);
223783
+ if (since) query = query.gte("created_at", since);
223784
+ const { data, error } = await query;
223785
+ if (error) throw error;
223786
+ return data ?? [];
223787
+ },
223788
+ async listInferenceUsageRows({
223789
+ userId,
223790
+ workspaceId,
223791
+ since,
223792
+ limit = 250
223793
+ }) {
223794
+ let query = supabase.from("perch_ai_inference_usage").select("*").eq("user_id", userId).eq("workspace_id", workspaceId).order("created_at", { ascending: false }).limit(limit);
223795
+ if (since) query = query.gte("created_at", since);
223796
+ const { data, error } = await query;
223797
+ if (error) throw error;
223798
+ return data ?? [];
223799
+ },
223800
+ async getUsageMeter({
223801
+ userId,
223802
+ workspaceId
223803
+ }) {
223804
+ const localDay = startOfLocalDay();
223805
+ const rollingWeek = startOfRollingWeek();
223806
+ const localMonth = startOfLocalMonth();
223807
+ const [rows, inferenceRows] = await Promise.all([
223808
+ this.listTokenCalculations({
223809
+ userId,
223810
+ workspaceId,
223811
+ since: localMonth,
223812
+ limit: 5e3
223813
+ }),
223814
+ this.listInferenceUsageRows({
223815
+ userId,
223816
+ workspaceId,
223817
+ since: localMonth,
223818
+ limit: 5e3
223819
+ })
223820
+ ]);
223821
+ const dailyUsd = sumInferenceCost(inferenceRows, localDay);
223822
+ const weeklyUsd = sumInferenceCost(inferenceRows, rollingWeek);
223823
+ const monthlyUsd = sumInferenceCost(inferenceRows, localMonth);
223824
+ return {
223825
+ dailyPt: nullableUsdToPerchTokens(dailyUsd) ?? sumPt(rows, localDay),
223826
+ weeklyPt: nullableUsdToPerchTokens(weeklyUsd) ?? sumPt(rows, rollingWeek),
223827
+ rows,
223828
+ dailyUsd,
223829
+ weeklyUsd,
223830
+ monthlyUsd,
223831
+ dailyTokens: sumInferenceTokens(inferenceRows, localDay),
223832
+ weeklyTokens: sumInferenceTokens(inferenceRows, rollingWeek),
223833
+ monthlyTokens: sumInferenceTokens(inferenceRows, localMonth),
223834
+ dailyCalls: countInferenceCalls(inferenceRows, localDay),
223835
+ weeklyCalls: countInferenceCalls(inferenceRows, rollingWeek),
223836
+ monthlyCalls: countInferenceCalls(inferenceRows, localMonth),
223837
+ inferenceRows
223838
+ };
223839
+ }
223840
+ };
223841
+ }
223842
+ var init_usagePersistence = __esm({
223843
+ "features/perchTerminal/persistence/usagePersistence.ts"() {
223844
+ init_perchTokens();
223845
+ }
223846
+ });
223847
+
223848
+ // features/perchTerminal/runtime/usage/usageAllowance.ts
223849
+ function readEntitlementNumber(value) {
223850
+ if (typeof value === "number" && Number.isFinite(value)) return value;
223851
+ if (typeof value === "string") {
223852
+ const parsed = Number(value);
223853
+ return Number.isFinite(parsed) ? parsed : null;
223854
+ }
223855
+ if (value && typeof value === "object") {
223856
+ const record = value;
223857
+ return readEntitlementNumber(record.usd) ?? readEntitlementNumber(record.amount) ?? readEntitlementNumber(record.value) ?? readEntitlementNumber(record.limit);
223858
+ }
223859
+ return null;
223860
+ }
223861
+ function readLimitUsd(entitlements, keys2, fallback) {
223862
+ for (const key of keys2) {
223863
+ const match = entitlements.find((entitlement) => entitlement.key === key);
223864
+ const value = match ? readEntitlementNumber(match.value_json) : null;
223865
+ if (value != null && value > 0) return value;
223866
+ }
223867
+ return fallback;
223868
+ }
223869
+ function isUnlimitedUsageSession(session) {
223870
+ if (!session) return false;
223871
+ return session.membershipRole === "admin" || session.membershipRole === "internal" || session.planCode === "internal";
223872
+ }
223873
+ function buildUsageAllowanceSnapshot(session, meter) {
223874
+ const unlimited = isUnlimitedUsageSession(session);
223875
+ const entitlements = session.entitlements ?? [];
223876
+ const dailyLimitUsd = readLimitUsd(
223877
+ entitlements,
223878
+ ["usage_daily_usd", "daily_usage_usd", "pilot_daily_usd", "user_daily_cap_usd"],
223879
+ DEFAULT_PILOT_DAILY_LIMIT_USD
223880
+ );
223881
+ const monthlyLimitUsd = readLimitUsd(
223882
+ entitlements,
223883
+ ["usage_monthly_usd", "monthly_usage_usd", "pilot_monthly_usd", "user_monthly_cap_usd"],
223884
+ DEFAULT_PILOT_MONTHLY_LIMIT_USD
223885
+ );
223886
+ return {
223887
+ unlimited,
223888
+ planLabel: session.planName ?? session.planCode ?? "Pilot",
223889
+ dailyUsedPt: meter?.dailyPt ?? usdToPerchTokens(meter?.dailyUsd),
223890
+ weeklyUsedPt: meter?.weeklyPt ?? usdToPerchTokens(meter?.weeklyUsd),
223891
+ monthlyUsedPt: usdToPerchTokens(meter?.monthlyUsd),
223892
+ dailyLimitPt: usdLimitToPerchTokens(dailyLimitUsd),
223893
+ monthlyLimitPt: usdLimitToPerchTokens(monthlyLimitUsd),
223894
+ dailyCalls: meter?.dailyCalls ?? null,
223895
+ weeklyCalls: meter?.weeklyCalls ?? null,
223896
+ monthlyCalls: meter?.monthlyCalls ?? null,
223897
+ dailyTokens: meter?.dailyTokens ?? null,
223898
+ weeklyTokens: meter?.weeklyTokens ?? null,
223899
+ monthlyTokens: meter?.monthlyTokens ?? null
223900
+ };
223901
+ }
223902
+ function formatInteger(value) {
223903
+ return Math.max(0, Math.round(value ?? 0)).toLocaleString("en-US");
223904
+ }
223905
+ function formatPt(value) {
223906
+ return `${formatInteger(value)} PT`;
223907
+ }
223908
+ function percentUsed(used, limit) {
223909
+ if (limit <= 0) return 0;
223910
+ return Math.max(0, Math.min(used / limit * 100, 100));
223911
+ }
223912
+ function renderTextBar(percent2, width = 24) {
223913
+ const clamped = Math.max(0, Math.min(100, percent2));
223914
+ const filled = Math.round(clamped / 100 * width);
223915
+ return `${"\u2588".repeat(filled)}${"\u2591".repeat(Math.max(0, width - filled))}`;
223916
+ }
223917
+ function formatAllowanceLine(label, usedPt, limitPt, unlimited) {
223918
+ const bar = renderTextBar(unlimited ? 100 : percentUsed(usedPt, limitPt));
223919
+ const amount = unlimited ? `${formatPt(usedPt)} / Unlimited` : `${formatPt(usedPt)} / ${formatPt(limitPt)} \xB7 ${Math.round(percentUsed(usedPt, limitPt))}%`;
223920
+ return `- ${label.padEnd(10)} ${bar} ${amount}`;
223921
+ }
223922
+ function formatUsageAllowanceText(allowance) {
223923
+ const allowanceLabel = allowance.unlimited ? `${allowance.planLabel} \xB7 unlimited allowance` : `${allowance.planLabel} \xB7 ${formatPt(allowance.dailyLimitPt)} daily allowance`;
223924
+ const lines = [
223925
+ "Perch Tokens",
223926
+ `- Plan: ${allowanceLabel}`,
223927
+ formatAllowanceLine("Today", allowance.dailyUsedPt, allowance.dailyLimitPt, allowance.unlimited),
223928
+ formatAllowanceLine("Month", allowance.monthlyUsedPt, allowance.monthlyLimitPt, allowance.unlimited),
223929
+ `- Activity ${formatInteger(allowance.monthlyCalls)} chats this month \xB7 ${formatPt(allowance.weeklyUsedPt)} in 7 days \xB7 ${formatInteger(allowance.weeklyTokens)} model tokens`
223930
+ ];
223931
+ return lines.join("\n");
223932
+ }
223933
+ async function fetchUsageAllowanceFromServer(input) {
223934
+ const appUrl = input.cliServerAppUrl?.trim();
223935
+ const token = input.cliServerAccessToken?.trim();
223936
+ if (!appUrl || !token || typeof fetch !== "function") return null;
223937
+ const controller = new AbortController();
223938
+ const timeout = setTimeout(() => controller.abort(), 5e3);
223939
+ try {
223940
+ const response = await fetch(`${appUrl.replace(/\/+$/, "")}/api/perchai/account`, {
223941
+ method: "GET",
223942
+ headers: {
223943
+ Accept: "application/json",
223944
+ Authorization: `Bearer ${token}`
223945
+ },
223946
+ signal: controller.signal
223947
+ });
223948
+ if (!response.ok) return null;
223949
+ const payload = await response.json();
223950
+ if (!payload.ok || !payload.session) return null;
223951
+ return buildUsageAllowanceSnapshot(payload.session, payload.usageMeter ?? null);
223952
+ } catch {
223953
+ return null;
223954
+ } finally {
223955
+ clearTimeout(timeout);
223956
+ }
223957
+ }
223958
+ async function resolveUsageAllowance(input) {
223959
+ if (input.supabase && input.userId && input.workspaceId) {
223960
+ try {
223961
+ const meter = await createUsagePersistence(input.supabase).getUsageMeter({
223962
+ userId: input.userId,
223963
+ workspaceId: input.workspaceId
223964
+ });
223965
+ return buildUsageAllowanceSnapshot(input.sessionContext, meter);
223966
+ } catch {
223967
+ return null;
223968
+ }
223969
+ }
223970
+ const viaServer = await fetchUsageAllowanceFromServer(input);
223971
+ if (viaServer) return viaServer;
223972
+ if (input.userId && input.workspaceId) {
223973
+ return buildUsageAllowanceSnapshot(input.sessionContext, null);
223974
+ }
223975
+ return null;
223976
+ }
223977
+ var init_usageAllowance = __esm({
223978
+ "features/perchTerminal/runtime/usage/usageAllowance.ts"() {
223979
+ "use strict";
223980
+ init_usagePersistence();
223981
+ init_perchTokens();
223982
+ }
223983
+ });
223984
+
223452
223985
  // features/perchTerminal/runtime/usage/usageSummary.ts
223453
223986
  function collectUsageRunIds(input) {
223454
223987
  const runIds = /* @__PURE__ */ new Set();
@@ -223495,10 +224028,14 @@ function summarizeInferenceUsageRows(rows, options = {}) {
223495
224028
  return summary;
223496
224029
  }
223497
224030
  function formatUsageSummaryText(summary) {
224031
+ const sections = [];
224032
+ if (summary.allowance) {
224033
+ sections.push(formatUsageAllowanceText(summary.allowance));
224034
+ }
223498
224035
  const lines = [
223499
224036
  "Usage this session",
223500
- `- Calls: ${formatInteger(summary.calls)}`,
223501
- `- Tokens: ${formatInteger(summary.totalTokens)} total (${formatInteger(summary.promptTokens)} input \xB7 ${formatInteger(summary.completionTokens)} output${summary.cachedTokens ? ` \xB7 ${formatInteger(summary.cachedTokens)} cached` : ""})`,
224037
+ `- Calls: ${formatInteger2(summary.calls)}`,
224038
+ `- Tokens: ${formatInteger2(summary.totalTokens)} total (${formatInteger2(summary.promptTokens)} input \xB7 ${formatInteger2(summary.completionTokens)} output${summary.cachedTokens ? ` \xB7 ${formatInteger2(summary.cachedTokens)} cached` : ""})`,
223502
224039
  `- Estimated cost: ${formatUsd(summary.estimatedCostUsd)}`
223503
224040
  ];
223504
224041
  if (summary.calls === 0) {
@@ -223508,11 +224045,12 @@ function formatUsageSummaryText(summary) {
223508
224045
  lines.push("", "Internal detail:");
223509
224046
  for (const row of summary.modelBreakdown.slice(0, 8)) {
223510
224047
  lines.push(
223511
- `- ${row.label}: ${formatInteger(row.totalTokens)} tokens \xB7 ${formatUsd(row.estimatedCostUsd)} \xB7 ${formatInteger(row.calls)} calls`
224048
+ `- ${row.label}: ${formatInteger2(row.totalTokens)} tokens \xB7 ${formatUsd(row.estimatedCostUsd)} \xB7 ${formatInteger2(row.calls)} calls`
223512
224049
  );
223513
224050
  }
223514
224051
  }
223515
- return lines.join("\n");
224052
+ sections.push(lines.join("\n"));
224053
+ return sections.join("\n\n");
223516
224054
  }
223517
224055
  function buildModelBreakdown(rows) {
223518
224056
  const byModel = /* @__PURE__ */ new Map();
@@ -223548,7 +224086,7 @@ function readNumber(value) {
223548
224086
  }
223549
224087
  return 0;
223550
224088
  }
223551
- function formatInteger(value) {
224089
+ function formatInteger2(value) {
223552
224090
  return Math.max(0, Math.round(value)).toLocaleString("en-US");
223553
224091
  }
223554
224092
  function formatUsd(value) {
@@ -223558,6 +224096,7 @@ function formatUsd(value) {
223558
224096
  var init_usageSummary = __esm({
223559
224097
  "features/perchTerminal/runtime/usage/usageSummary.ts"() {
223560
224098
  "use strict";
224099
+ init_usageAllowance();
223561
224100
  }
223562
224101
  });
223563
224102
 
@@ -223590,7 +224129,11 @@ async function runUsageTurn(input, deps) {
223590
224129
  recentMessages: input.recentMessages
223591
224130
  });
223592
224131
  const showModelDetails = canShowPerchDevTools(input.sessionContext.membershipRole);
223593
- const summary = await resolveUsageSummary(input, runIds, showModelDetails);
224132
+ const [summary, allowance] = await Promise.all([
224133
+ resolveUsageSummary(input, runIds, showModelDetails),
224134
+ resolveUsageAllowance(input)
224135
+ ]);
224136
+ summary.allowance = allowance;
223594
224137
  const assistantText = formatUsageSummaryText(summary);
223595
224138
  let assistantMessageId = null;
223596
224139
  if (input.workspaceId) {
@@ -223675,6 +224218,7 @@ var init_runUsageTurn = __esm({
223675
224218
  "features/perchTerminal/runtime/usage/runUsageTurn.ts"() {
223676
224219
  "use strict";
223677
224220
  init_access();
224221
+ init_usageAllowance();
223678
224222
  init_usageSummary();
223679
224223
  }
223680
224224
  });
@@ -225065,10 +225609,7 @@ async function runLiveAgentsLoop(input) {
225065
225609
  const { turn, deps, runId, onEvent } = input;
225066
225610
  try {
225067
225611
  const loopLane = "chat";
225068
- const selectedChatModel = resolveModelForLane(
225069
- turn.founderModelSelection,
225070
- loopLane
225071
- );
225612
+ const selectedChatModel = turn.activeContextModel ?? resolveModelForLane(turn.founderModelSelection, loopLane);
225072
225613
  const context = input.assembledContext;
225073
225614
  if (!context) {
225074
225615
  return {
@@ -230360,6 +230901,7 @@ async function runOperatorTurn(input, deps) {
230360
230901
  });
230361
230902
  try {
230362
230903
  const memoryRetriever = buildTurnMemoryRetriever(input);
230904
+ const inputContextModel = input.activeContextModel ?? null;
230363
230905
  const memoryContext = await buildMemoryContext({
230364
230906
  query: input.trimmedInput,
230365
230907
  userId: input.userId ?? (memoryRetriever && input.cliServerAccessToken?.trim() ? "cli_authenticated_user" : null),
@@ -230367,7 +230909,8 @@ async function runOperatorTurn(input, deps) {
230367
230909
  threadId: input.threadId,
230368
230910
  permanentMemories: input.permanentMemories,
230369
230911
  userMemories: input.userMemories,
230370
- retriever: memoryRetriever
230912
+ retriever: memoryRetriever,
230913
+ contextLimitTokens: inputContextModel ? getEffectiveContextWindow(inputContextModel) : void 0
230371
230914
  });
230372
230915
  const earlySession = input.threadId ? await loadThreadSession(input.threadId, { supabase: input.supabase ?? null }) : null;
230373
230916
  const {
@@ -230383,10 +230926,7 @@ async function runOperatorTurn(input, deps) {
230383
230926
  memoryContext,
230384
230927
  isSystemNotification
230385
230928
  });
230386
- const chatSelectedModelOption = resolveModelForLane(
230387
- enrichedInput.founderModelSelection,
230388
- "chat"
230389
- );
230929
+ const chatSelectedModelOption = enrichedInput.activeContextModel ?? resolveModelForLane(enrichedInput.founderModelSelection, "chat");
230390
230930
  const sources = await prepareTurnSources({ enrichedInput, deps });
230391
230931
  const toolDefinitions = prepareTurnToolDefinitions({
230392
230932
  enrichedInput,
@@ -230525,6 +231065,7 @@ var init_runOperatorTurn = __esm({
230525
231065
  init_liveAgentsLoop();
230526
231066
  init_turnAbort();
230527
231067
  init_modelRegistry();
231068
+ init_contextThresholds();
230528
231069
  init_threadSession();
230529
231070
  init_turnMemoryRetriever();
230530
231071
  init_turnBootstrap();
@@ -231787,7 +232328,7 @@ function runBackgroundCommand2(input) {
231787
232328
  const shell = input.shell || process.env.SHELL || "/bin/zsh";
231788
232329
  let child;
231789
232330
  try {
231790
- child = spawn2(shell, ["-lc", command], {
232331
+ child = spawn2(shell, ["-ilc", command], {
231791
232332
  cwd: input.cwd,
231792
232333
  env: process.env,
231793
232334
  stdio: ["ignore", "pipe", "pipe"],
@@ -233652,7 +234193,8 @@ async function runCliStandaloneOAuthLogin(input) {
233652
234193
  provider,
233653
234194
  options: {
233654
234195
  redirectTo: callback.redirectTo,
233655
- skipBrowserRedirect: true
234196
+ skipBrowserRedirect: true,
234197
+ data: { signup_source: "cli" }
233656
234198
  }
233657
234199
  });
233658
234200
  if (error || !data.url) {
@@ -233811,6 +234353,37 @@ var init_cliStandaloneOAuth = __esm({
233811
234353
  }
233812
234354
  });
233813
234355
 
234356
+ // lib/perchTerminal/statusLabels.ts
234357
+ function sectionLabel(sectionKey) {
234358
+ if (STATUS_LABELS[sectionKey]) return STATUS_LABELS[sectionKey];
234359
+ return sectionKey.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
234360
+ }
234361
+ var STATUS_LABELS;
234362
+ var init_statusLabels = __esm({
234363
+ "lib/perchTerminal/statusLabels.ts"() {
234364
+ STATUS_LABELS = {
234365
+ not_found: "Not found",
234366
+ not_initialized: "Not initialized",
234367
+ sent_raw: "Included",
234368
+ sent_compacted: "Summarized",
234369
+ output_reserve: "Reserved for response",
234370
+ excluded: "Excluded",
234371
+ skipped: "Skipped",
234372
+ reserved: "Reserved",
234373
+ generated: "Generated",
234374
+ error: "Error",
234375
+ completed: "Completed",
234376
+ failed: "Failed",
234377
+ running: "Running",
234378
+ pending: "Pending",
234379
+ blocked: "Blocked",
234380
+ in_progress: "In progress",
234381
+ sent: "Sent",
234382
+ compacted: "Summarized"
234383
+ };
234384
+ }
234385
+ });
234386
+
233814
234387
  // features/perchTerminal/runtime/contextMeterDisplay.ts
233815
234388
  function positiveInt3(value) {
233816
234389
  if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return null;
@@ -233870,13 +234443,182 @@ function resolveContextMeterDisplay(snapshot, activeModel) {
233870
234443
  hasWorkers
233871
234444
  };
233872
234445
  }
233873
- var ADMITTED_ROW_STATUSES2;
234446
+ function displayCategoryOrder(key) {
234447
+ if (key.startsWith("mcp_tools")) {
234448
+ const idx2 = DISPLAY_CATEGORY_ORDER.indexOf("mcp_tools");
234449
+ return idx2;
234450
+ }
234451
+ const idx = DISPLAY_CATEGORY_ORDER.indexOf(key);
234452
+ return idx === -1 ? DISPLAY_CATEGORY_ORDER.length : idx;
234453
+ }
234454
+ function displayCategoryForLane(lane) {
234455
+ if (lane.startsWith("mcp_tools")) {
234456
+ return { key: lane, label: sectionLabel(lane) };
234457
+ }
234458
+ switch (lane) {
234459
+ case "system":
234460
+ case "system_prompt":
234461
+ case "selected_model":
234462
+ return { key: "system_prompt", label: "System prompt" };
234463
+ case "tools":
234464
+ case "tool_definitions":
234465
+ case "system_tools":
234466
+ return { key: "system_tools", label: "System tools" };
234467
+ case "mcp_tools":
234468
+ return { key: "mcp_tools", label: "MCP tools" };
234469
+ case "skills":
234470
+ case "agent_skills":
234471
+ return { key: "skills", label: "Skills" };
234472
+ case "output_response":
234473
+ return { key: "output_response", label: "Output response" };
234474
+ case "output_reserve":
234475
+ case "reserved_output":
234476
+ return { key: "reserved_output", label: "Reserved output" };
234477
+ case "deferred":
234478
+ return { key: "deferred", label: "Deferred" };
234479
+ case "messages":
234480
+ case "conversation":
234481
+ case "summarized_conversation":
234482
+ return { key: "conversation", label: "Conversation" };
234483
+ case "tool_transcript":
234484
+ return { key: "tool_transcript", label: "Tool transcript" };
234485
+ case "project_memory":
234486
+ case "permanent_memory":
234487
+ case "rules_project_memory":
234488
+ case "durable_memory":
234489
+ return { key: "memory_rules", label: "Memory & rules" };
234490
+ case "tool_evidence":
234491
+ case "thread_evidence":
234492
+ case "retrieved_evidence":
234493
+ case "files":
234494
+ case "selected_source":
234495
+ return { key: "evidence", label: "Evidence" };
234496
+ case "workers":
234497
+ return { key: "workers", label: "Workers" };
234498
+ case "desktop":
234499
+ case "workspace_context":
234500
+ return { key: "workspace_context", label: "Workspace context" };
234501
+ case "wire_overhead":
234502
+ return { key: "overhead", label: "Overhead" };
234503
+ default:
234504
+ return { key: lane, label: sectionLabel(lane) };
234505
+ }
234506
+ }
234507
+ function isCacheKey(key) {
234508
+ return key.includes("cache");
234509
+ }
234510
+ function segmentsFromCategories(categories) {
234511
+ return categories.filter((category) => category.tokens > 0 && !isCacheKey(category.key)).map((category) => ({
234512
+ key: category.key,
234513
+ label: category.label,
234514
+ tokens: category.tokens
234515
+ }));
234516
+ }
234517
+ function segmentsFromLaneTotals(laneTotals) {
234518
+ return laneTotals.filter((lane) => lane.lane !== "output_reserve" && lane.tokens > 0 && !isCacheKey(lane.lane)).map((lane) => ({ key: lane.lane, label: sectionLabel(lane.lane), tokens: lane.tokens }));
234519
+ }
234520
+ function segmentsFromRows(rows) {
234521
+ const byLane = /* @__PURE__ */ new Map();
234522
+ for (const row of rows) {
234523
+ if (row.lane === "output_reserve") continue;
234524
+ if (isCacheKey(row.lane)) continue;
234525
+ if (!ADMITTED_ROW_STATUSES2.has(row.status)) continue;
234526
+ byLane.set(row.lane, (byLane.get(row.lane) ?? 0) + row.estimatedTokens);
234527
+ }
234528
+ return Array.from(byLane.entries()).filter(([, tokens]) => tokens > 0).map(([key, tokens]) => ({ key, label: sectionLabel(key), tokens }));
234529
+ }
234530
+ function segmentsFromBreakdown(breakdown) {
234531
+ return Object.entries(breakdown).filter(([key, val]) => val.estimatedTokens > 0 && !isCacheKey(key)).map(([key, val]) => ({ key, label: sectionLabel(key), tokens: val.estimatedTokens }));
234532
+ }
234533
+ function groupDisplaySegments(segments) {
234534
+ const grouped = /* @__PURE__ */ new Map();
234535
+ for (const segment of segments) {
234536
+ const display = displayCategoryForLane(segment.key);
234537
+ const existing = grouped.get(display.key);
234538
+ if (existing) {
234539
+ existing.tokens += segment.tokens;
234540
+ } else {
234541
+ grouped.set(display.key, { key: display.key, label: display.label, tokens: segment.tokens });
234542
+ }
234543
+ }
234544
+ return Array.from(grouped.values());
234545
+ }
234546
+ function buildContentSegments(snapshot) {
234547
+ if (!snapshot) return [];
234548
+ if (snapshot.contextCategories?.length) {
234549
+ return segmentsFromCategories(snapshot.contextCategories);
234550
+ }
234551
+ const source = snapshot.laneTotals?.length ? segmentsFromLaneTotals(snapshot.laneTotals) : snapshot.rows ? segmentsFromRows(snapshot.rows) : segmentsFromBreakdown(snapshot.sectionBreakdown ?? {});
234552
+ return groupDisplaySegments(source);
234553
+ }
234554
+ function resolveTruncationState(snapshot) {
234555
+ if (snapshot?.truncated) return "truncated";
234556
+ if (snapshot?.compacted) return "compacted";
234557
+ return "none";
234558
+ }
234559
+ function buildContextComposition(snapshot, activeModel) {
234560
+ const meter = resolveContextMeterDisplay(snapshot, activeModel);
234561
+ const totalTokens = Math.max(1, meter.limitTokens);
234562
+ const reservedOutputTokens = Math.max(0, meter.reservedOutputTokens);
234563
+ const segments = buildContentSegments(snapshot);
234564
+ if (reservedOutputTokens > 0) {
234565
+ segments.push({ key: "reserved_output", label: "Reserved output", tokens: reservedOutputTokens });
234566
+ }
234567
+ const ordered = segments.filter((segment) => segment.tokens > 0).sort((a, b2) => displayCategoryOrder(a.key) - displayCategoryOrder(b2.key));
234568
+ const usedTokens = Math.min(
234569
+ totalTokens,
234570
+ ordered.reduce((sum, segment) => sum + segment.tokens, 0)
234571
+ );
234572
+ const freeSpaceTokens = Math.max(0, totalTokens - usedTokens);
234573
+ const slices = ordered.map((segment) => ({
234574
+ key: segment.key,
234575
+ label: segment.label,
234576
+ tokens: segment.tokens,
234577
+ pct: segment.tokens / totalTokens * 100
234578
+ }));
234579
+ return {
234580
+ slices,
234581
+ freeSpaceTokens,
234582
+ freeSpacePct: freeSpaceTokens / totalTokens * 100,
234583
+ usedTokens,
234584
+ totalTokens,
234585
+ usedPercent: usedTokens / totalTokens * 100,
234586
+ truncationState: resolveTruncationState(snapshot)
234587
+ };
234588
+ }
234589
+ function contextTruncationNotice(state) {
234590
+ switch (state) {
234591
+ case "compacted":
234592
+ return "\u26A0 Context full \u2014 older messages were compacted to fit";
234593
+ case "truncated":
234594
+ return "\u26A0 Context full \u2014 older messages were dropped to fit";
234595
+ default:
234596
+ return "";
234597
+ }
234598
+ }
234599
+ var ADMITTED_ROW_STATUSES2, DISPLAY_CATEGORY_ORDER;
233874
234600
  var init_contextMeterDisplay = __esm({
233875
234601
  "features/perchTerminal/runtime/contextMeterDisplay.ts"() {
233876
234602
  "use strict";
234603
+ init_statusLabels();
233877
234604
  init_contextMeter();
233878
234605
  init_contextThresholds();
233879
234606
  ADMITTED_ROW_STATUSES2 = /* @__PURE__ */ new Set(["sent_raw", "sent_compacted"]);
234607
+ DISPLAY_CATEGORY_ORDER = [
234608
+ "system_prompt",
234609
+ "system_tools",
234610
+ "mcp_tools",
234611
+ "skills",
234612
+ "conversation",
234613
+ "tool_transcript",
234614
+ "memory_rules",
234615
+ "evidence",
234616
+ "workspace_context",
234617
+ "workers",
234618
+ "overhead",
234619
+ "deferred",
234620
+ "reserved_output"
234621
+ ];
233880
234622
  }
233881
234623
  });
233882
234624
 
@@ -290110,6 +290852,27 @@ async function runInteractiveSlashCommand(input) {
290110
290852
  input.state.personaId = parsed.value;
290111
290853
  writeModeLine(input.writer, "persona", input.state.personaId);
290112
290854
  return "continue";
290855
+ case "model": {
290856
+ const labelFor = (choice) => choice === "internal" ? "Internal" : ROOST_TIER_LABELS[choice];
290857
+ if (!parsed.value) {
290858
+ writeModeLine(input.writer, "model", labelFor(input.state.roostChoice));
290859
+ return "continue";
290860
+ }
290861
+ input.state.roostChoice = parsed.value;
290862
+ setRoostUserSelectionForNode({ choice: parsed.value, reasoningEnabled: input.state.roostReasoningEnabled });
290863
+ writeModeLine(input.writer, "model", labelFor(parsed.value));
290864
+ return "continue";
290865
+ }
290866
+ case "thinking": {
290867
+ if (parsed.value === void 0) {
290868
+ writeModeLine(input.writer, "thinking", input.state.roostReasoningEnabled ? "on" : "off");
290869
+ return "continue";
290870
+ }
290871
+ input.state.roostReasoningEnabled = parsed.value;
290872
+ setRoostUserSelectionForNode({ choice: input.state.roostChoice, reasoningEnabled: parsed.value });
290873
+ writeModeLine(input.writer, "thinking", input.state.roostReasoningEnabled ? "on" : "off");
290874
+ return "continue";
290875
+ }
290113
290876
  case "appUrl":
290114
290877
  if (!parsed.value) {
290115
290878
  writeModeLine(input.writer, "app-url", input.state.appUrl ?? "(none)");
@@ -290203,6 +290966,22 @@ function parseInteractiveSlashCommand(input) {
290203
290966
  if (!value) return { ok: true, kind: "persona" };
290204
290967
  if (!isPersonaId(value)) return { ok: false, error: `Unknown persona: ${value}` };
290205
290968
  return { ok: true, kind: "persona", value };
290969
+ case "model":
290970
+ if (!value) return { ok: true, kind: "model" };
290971
+ {
290972
+ const normalized = value.toLowerCase().replace(/[\s-]+/g, "_");
290973
+ const choice = normalizeRoostModelChoice(
290974
+ normalized === "standardmax" ? "standard_max" : normalized === "promax" ? "pro_max" : normalized
290975
+ );
290976
+ if (!choice) {
290977
+ return { ok: false, error: `Unknown model: ${value}. Try standard, standard max, pro, pro max, or internal.` };
290978
+ }
290979
+ return { ok: true, kind: "model", value: choice };
290980
+ }
290981
+ case "thinking":
290982
+ if (!value) return { ok: true, kind: "thinking" };
290983
+ if (value !== "on" && value !== "off") return { ok: false, error: "/thinking expects on or off." };
290984
+ return { ok: true, kind: "thinking", value: value === "on" };
290206
290985
  case "app-url":
290207
290986
  case "app":
290208
290987
  return { ok: true, kind: "appUrl", ...value ? { value } : {} };
@@ -290243,6 +291022,8 @@ function renderInteractiveStatus(state, connection, session, workspaceId) {
290243
291022
  ["permission", state.permissionMode],
290244
291023
  ["mode", state.chatMode],
290245
291024
  ["persona", state.personaId],
291025
+ ["model", state.roostChoice === "internal" ? "Internal" : ROOST_TIER_LABELS[state.roostChoice]],
291026
+ ["thinking", state.roostReasoningEnabled ? "on" : "off"],
290246
291027
  ["thread", state.threadId],
290247
291028
  ["context", renderCliContextMeter(state.contextSnapshot, activeContextModel)],
290248
291029
  ["saved", state.persistedThreadUpdatedAt ? new Date(state.persistedThreadUpdatedAt).toLocaleString() : "(new thread)"],
@@ -290382,11 +291163,13 @@ function renderInkSpeakerLabel(label) {
290382
291163
  return `${label}\u203A`;
290383
291164
  }
290384
291165
  function createInteractiveCliState(options) {
290385
- return {
291166
+ const state = {
290386
291167
  cwd: resolveExistingDirectory(options.cwd ?? process.cwd()),
290387
291168
  chatMode: options.chatMode ?? "agents",
290388
291169
  personaId: options.personaId ?? "saffron",
290389
291170
  permissionMode: options.permissionMode ?? "default",
291171
+ roostChoice: "internal",
291172
+ roostReasoningEnabled: true,
290390
291173
  threadId: options.threadId?.trim() || "cli-default",
290391
291174
  threadScopeKey: null,
290392
291175
  desktopConnected: options.desktopConnected ?? false,
@@ -290397,6 +291180,11 @@ function createInteractiveCliState(options) {
290397
291180
  contextSnapshot: null,
290398
291181
  persistedThreadUpdatedAt: null
290399
291182
  };
291183
+ setRoostUserSelectionForNode({
291184
+ choice: state.roostChoice,
291185
+ reasoningEnabled: state.roostReasoningEnabled
291186
+ });
291187
+ return state;
290400
291188
  }
290401
291189
  async function hydrateInteractiveCliState(state) {
290402
291190
  const persisted = await hydrateCliThreadState(state.threadId, state.threadScopeKey);
@@ -290603,20 +291391,33 @@ function renderCliContextMeter(snapshot, activeModel) {
290603
291391
  if (snapshot.compacted || compacted > 0) parts.push(`compacted ${compacted}`);
290604
291392
  return parts.join(" \xB7 ");
290605
291393
  }
291394
+ function renderCliBlockBar(percent2, width) {
291395
+ const clamped = Math.max(0, Math.min(100, percent2));
291396
+ const filled = Math.round(clamped / 100 * width);
291397
+ return `\u2595${"\u2588".repeat(filled)}${"\u2591".repeat(Math.max(0, width - filled))}\u258F`;
291398
+ }
290606
291399
  function renderCliContextDetails(snapshot, activeModel) {
290607
291400
  if (!snapshot) return "context no meter yet\n";
290608
- const meter = resolveContextMeterDisplay(snapshot, activeModel);
290609
- const percent2 = snapshot.contextPercentage ?? Math.round(meter.committedTokens / Math.max(1, meter.limitTokens) * 100);
290610
- const lines = [
290611
- ["context", renderCliContextMeter(snapshot, activeModel)],
290612
- ["thread", `${formatCliTokenCount(meter.threadTokens)} tokens`],
290613
- ["limit", `${formatCliTokenCount(meter.limitTokens)} tokens`],
290614
- ["fill", `${Math.max(0, Math.min(100, percent2))}%`],
290615
- ["compacted", snapshot.compacted || (snapshot.compactedRowCount ?? 0) > 0 ? `${snapshot.compactedRowCount ?? 0} row(s)` : "no"],
290616
- ["not-found", `${snapshot.notFoundRowCount ?? 0} row(s)`]
290617
- ];
290618
291401
  const color = shouldUseCliColor();
290619
- return lines.map(([key, value]) => `${paint(key.padEnd(11), "muted", color)} ${value}`).join("\n") + "\n";
291402
+ const composition = buildContextComposition(snapshot, activeModel);
291403
+ const percent2 = Math.max(0, Math.min(100, Math.round(composition.usedPercent)));
291404
+ const bar = renderCliBlockBar(composition.usedPercent, 24);
291405
+ const header = `${paint("context".padEnd(11), "muted", color)} ${paint(bar, percent2 >= 90 ? "red" : "accent", color)} ${formatCliTokenCount(composition.usedTokens)} / ${formatCliTokenCount(composition.totalTokens)} (${percent2}%)`;
291406
+ const rows = [
291407
+ ...composition.slices.map((slice2) => ({ label: slice2.label, tokens: slice2.tokens, pct: slice2.pct })),
291408
+ { label: "Free space", tokens: composition.freeSpaceTokens, pct: composition.freeSpacePct }
291409
+ ];
291410
+ const labelWidth = Math.max(...rows.map((row) => row.label.length));
291411
+ const tokenWidth = Math.max(...rows.map((row) => formatCliTokenCount(row.tokens).length));
291412
+ const lines = rows.map((row) => {
291413
+ const label = paint(` ${row.label.padEnd(labelWidth)}`, "muted", color);
291414
+ const tokens = formatCliTokenCount(row.tokens).padStart(tokenWidth);
291415
+ return `${label} ${tokens} \xB7 ${row.pct.toFixed(1).padStart(4)}%`;
291416
+ });
291417
+ const out = [header, ...lines];
291418
+ const notice = contextTruncationNotice(composition.truncationState);
291419
+ if (notice) out.push(paint(notice, "red", color));
291420
+ return out.join("\n") + "\n";
290620
291421
  }
290621
291422
  function formatCliTokenCount(value) {
290622
291423
  if (value < 1e3) return `${Math.max(0, Math.round(value))}`;
@@ -291442,6 +292243,8 @@ var init_perch_cli = __esm({
291442
292243
  init_perchCore();
291443
292244
  init_cliHost();
291444
292245
  init_modelConnection();
292246
+ init_roost();
292247
+ init_roostUserSelectionClient();
291445
292248
  init_cliAuthSession();
291446
292249
  init_cliStandaloneOAuth();
291447
292250
  init_contextMeterDisplay();
@@ -291517,7 +292320,9 @@ Commands:
291517
292320
  /help Show this list.
291518
292321
  /status Show cwd, auth, mode, persona, permission, and thread.
291519
292322
  /skills [name] List Perch core skills, or show one skill body.
291520
- /usage Show tokens and estimated cost for this session.
292323
+ /usage Show Perch Token allowance and session usage.
292324
+ /model [standard|standard max|pro|pro max|internal] Show or set your model.
292325
+ /thinking [on|off] Show or toggle Thinking for the selected model.
291521
292326
  /cwd [dir] Show or change the working directory.
291522
292327
  /permission [mode] Show or set default, auto_review, take_the_wheel, or plan.
291523
292328
  /permissions [mode] Alias for /permission.
@@ -291579,8 +292384,10 @@ Commands:
291579
292384
  ];
291580
292385
  PERCH_SPLASH_COMMANDS = [
291581
292386
  ["/status", "show auth, route, tools, and thread"],
291582
- ["/usage", "show session tokens and estimated cost"],
292387
+ ["/usage", "show Perch Token allowance and session usage"],
291583
292388
  ["/skills", "show reusable operator skills"],
292389
+ ["/model", "choose Standard, Standard Max, Pro, or Pro Max"],
292390
+ ["/thinking", "toggle model thinking"],
291584
292391
  ["/persona", "swap saffron or quill"],
291585
292392
  ["/permission", "change autonomy for the next turns"],
291586
292393
  ["/login", "connect your Perch account"]