@pellux/goodvibes-agent 1.1.4 → 1.1.5

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.
@@ -450372,23 +450372,6 @@ function createSchema2(db) {
450372
450372
  `);
450373
450373
  db.run(`CREATE INDEX IF NOT EXISTS idx_knowledge_schedules_job_id ON knowledge_schedules(job_id)`);
450374
450374
  }
450375
- function getKnowledgeSchemaStatements() {
450376
- const statements = [];
450377
- createSchema2({
450378
- run(sql) {
450379
- const normalized = sql.trim();
450380
- if (normalized.length > 0)
450381
- statements.push(normalized);
450382
- }
450383
- });
450384
- return statements;
450385
- }
450386
- function renderKnowledgeSchemaSql() {
450387
- return `${getKnowledgeSchemaStatements().map((statement) => statement.endsWith(";") ? statement : `${statement};`).join(`
450388
-
450389
- `)}
450390
- `;
450391
- }
450392
450375
  function rowObject(columns, values2) {
450393
450376
  return Object.fromEntries(columns.map((column, index) => [column, values2[index]]));
450394
450377
  }
@@ -763671,9 +763654,6 @@ var init_ingest = __esm(() => {
763671
763654
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/browser-history/index.js
763672
763655
  var init_browser_history = __esm(() => {
763673
763656
  init_ingest();
763674
- init_discover();
763675
- init_readers();
763676
- init_paths2();
763677
763657
  });
763678
763658
 
763679
763659
  // node_modules/graphql/jsutils/devAssert.mjs
@@ -781313,7 +781293,6 @@ var init_semantic = __esm(() => {
781313
781293
  init_llm();
781314
781294
  init_gap_repair();
781315
781295
  init_service4();
781316
- init_self_improvement();
781317
781296
  });
781318
781297
 
781319
781298
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/home-graph/helpers.js
@@ -785282,40 +785261,8 @@ var init_map_view = __esm(() => {
785282
785261
  });
785283
785262
 
785284
785263
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/home-graph/types.js
785285
- var HOME_GRAPH_NODE_KINDS, HOME_GRAPH_RELATIONS, HOME_GRAPH_CAPABILITIES;
785264
+ var HOME_GRAPH_CAPABILITIES;
785286
785265
  var init_types15 = __esm(() => {
785287
- HOME_GRAPH_NODE_KINDS = [
785288
- "ha_home",
785289
- "ha_entity",
785290
- "ha_device",
785291
- "ha_area",
785292
- "ha_automation",
785293
- "ha_script",
785294
- "ha_scene",
785295
- "ha_label",
785296
- "ha_integration",
785297
- "ha_room",
785298
- "ha_device_passport",
785299
- "ha_maintenance_item",
785300
- "ha_troubleshooting_case",
785301
- "ha_purchase",
785302
- "ha_network_node"
785303
- ];
785304
- HOME_GRAPH_RELATIONS = [
785305
- "controls",
785306
- "located_in",
785307
- "belongs_to_device",
785308
- "has_manual",
785309
- "has_receipt",
785310
- "has_warranty",
785311
- "has_issue",
785312
- "fixed_by",
785313
- "uses_battery",
785314
- "connected_via",
785315
- "part_of_network",
785316
- "mentioned_by",
785317
- "source_for"
785318
- ];
785319
785266
  HOME_GRAPH_CAPABILITIES = [
785320
785267
  "knowledge-space-isolation",
785321
785268
  "snapshot-sync",
@@ -786722,7 +786669,6 @@ var init_service5 = __esm(() => {
786722
786669
  var init_home_graph = __esm(() => {
786723
786670
  init_service5();
786724
786671
  init_extension();
786725
- init_types15();
786726
786672
  });
786727
786673
 
786728
786674
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/store-refinement.js
@@ -789050,14 +788996,10 @@ var init_service6 = __esm(() => {
789050
788996
  var init_project_planning = __esm(() => {
789051
788997
  init_service6();
789052
788998
  init_helpers3();
789053
- init_readiness();
789054
788999
  });
789055
789000
 
789056
789001
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/persistence.js
789057
- var init_persistence = __esm(() => {
789058
- init_store_schema();
789059
- init_store_load();
789060
- });
789002
+ var init_persistence = () => {};
789061
789003
 
789062
789004
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/projections.js
789063
789005
  class KnowledgeProjectionService {
@@ -792565,21 +792507,21 @@ var init_service7 = __esm(() => {
792565
792507
  var exports_knowledge = {};
792566
792508
  __export(exports_knowledge, {
792567
792509
  withKnowledgeSpace: () => withKnowledgeSpace,
792568
- uniqKnowledgeValues: () => uniq2,
792569
- stabilizeKnowledgeText: () => stableText,
792570
- runKnowledgeSemanticSelfImprovement: () => runKnowledgeSemanticSelfImprovement,
792510
+ uniqKnowledgeValues: () => uniq3,
792511
+ stabilizeKnowledgeText: () => stableText2,
792512
+ runKnowledgeSemanticSelfImprovement: () => runKnowledgeSemanticSelfImprovement2,
792571
792513
  resolveProjectPlanningSpace: () => resolveProjectPlanningSpace,
792572
- resolveKnowledgeDbPathFromControlPlaneDir: () => resolveKnowledgeDbPathFromControlPlaneDir,
792514
+ resolveKnowledgeDbPathFromControlPlaneDir: () => resolveKnowledgeDbPathFromControlPlaneDir2,
792573
792515
  renderPacket: () => renderPacket,
792574
792516
  renderKnowledgeSchemaSql: () => renderKnowledgeSchemaSql,
792575
792517
  renderKnowledgeMap: () => renderKnowledgeMap,
792576
792518
  readKnowledgeSearchText: () => readKnowledgeSearchText,
792577
- readBrowserKnowledgeProfile: () => readBrowserKnowledgeProfile,
792519
+ readBrowserKnowledgeProfile: () => readBrowserKnowledgeProfile2,
792578
792520
  projectPlanningSourceId: () => projectPlanningSourceId,
792579
792521
  projectPlanningProjectIdFromPath: () => projectPlanningProjectIdFromPath,
792580
792522
  projectPlanningCanonicalUri: () => projectPlanningCanonicalUri,
792581
792523
  projectKnowledgeSpaceId: () => projectKnowledgeSpaceId,
792582
- parseKnowledgeJsonValue: () => parseJsonValue,
792524
+ parseKnowledgeJsonValue: () => parseJsonValue2,
792583
792525
  normalizeProjectId: () => normalizeProjectId,
792584
792526
  normalizeKnowledgeSpaceId: () => normalizeKnowledgeSpaceId,
792585
792527
  normalizeHomeAssistantInstallationId: () => normalizeHomeAssistantInstallationId,
@@ -792587,12 +792529,12 @@ __export(exports_knowledge, {
792587
792529
  materializeGeneratedKnowledgeProjection: () => materializeGeneratedKnowledgeProjection,
792588
792530
  looksLikeRawPdfPayload: () => looksLikeRawPdfPayload,
792589
792531
  looksBinaryLikeText: () => looksBinaryLikeText,
792590
- loadKnowledgeStoreSnapshot: () => loadKnowledgeStoreSnapshot,
792532
+ loadKnowledgeStoreSnapshot: () => loadKnowledgeStoreSnapshot2,
792591
792533
  listGeneratedKnowledgePages: () => listGeneratedKnowledgePages,
792592
- listBrowserKinds: () => listBrowserKinds,
792534
+ listBrowserKinds: () => listBrowserKinds2,
792593
792535
  knowledgeSpaceMetadata: () => knowledgeSpaceMetadata,
792594
792536
  knowledgePageSourceWeight: () => knowledgePageSourceWeight,
792595
- knowledgeNowMs: () => nowMs,
792537
+ knowledgeNowMs: () => nowMs2,
792596
792538
  knowledgeExtractionNeedsRefresh: () => knowledgeExtractionNeedsRefresh,
792597
792539
  isUsefulKnowledgePageSourceCandidate: () => isUsefulKnowledgePageSourceCandidate,
792598
792540
  isUsefulKnowledgePageSource: () => isUsefulKnowledgePageSource,
@@ -792612,12 +792554,12 @@ __export(exports_knowledge, {
792612
792554
  generatedKnowledgeSourceId: () => generatedKnowledgeSourceId,
792613
792555
  generatedKnowledgeCanonicalUri: () => generatedKnowledgeCanonicalUri,
792614
792556
  extractKnowledgeArtifact: () => extractKnowledgeArtifact,
792615
- evaluateProjectPlanningReadiness: () => evaluateProjectPlanningReadiness,
792616
- discoverBrowserKnowledgeProfiles: () => discoverBrowserKnowledgeProfiles,
792557
+ evaluateProjectPlanningReadiness: () => evaluateProjectPlanningReadiness2,
792558
+ discoverBrowserKnowledgeProfiles: () => discoverBrowserKnowledgeProfiles2,
792617
792559
  createWebKnowledgeGapRepairer: () => createWebKnowledgeGapRepairer,
792618
792560
  createProviderBackedKnowledgeSemanticLlm: () => createProviderBackedKnowledgeSemanticLlm,
792619
792561
  createMemoryApi: () => createMemoryApi,
792620
- createKnowledgeSchema: () => createSchema2,
792562
+ createKnowledgeSchema: () => createSchema3,
792621
792563
  createKnowledgeApi: () => createKnowledgeApi,
792622
792564
  createDefaultKnowledgeConnectorRegistry: () => createDefaultKnowledgeConnectorRegistry,
792623
792565
  compareKnowledgePageSources: () => compareKnowledgePageSources,
@@ -795056,7 +794998,7 @@ var init_delivery_manager = __esm(() => {
795056
794998
  });
795057
794999
 
795058
795000
  // node_modules/@pellux/goodvibes-sdk/dist/platform/automation/scheduler-capacity.js
795059
- function computeSchedulerCapacity(slotsTotal, runs, nowMs2 = Date.now()) {
795001
+ function computeSchedulerCapacity(slotsTotal, runs, nowMs3 = Date.now()) {
795060
795002
  let slotsInUse = 0;
795061
795003
  const queuedRuns = [];
795062
795004
  for (const run7 of runs) {
@@ -795066,7 +795008,7 @@ function computeSchedulerCapacity(slotsTotal, runs, nowMs2 = Date.now()) {
795066
795008
  queuedRuns.push(run7);
795067
795009
  }
795068
795010
  const queueDepth = queuedRuns.length;
795069
- const oldestQueuedAgeMs = queueDepth > 0 ? nowMs2 - Math.min(...queuedRuns.map((r6) => r6.queuedAt)) : null;
795011
+ const oldestQueuedAgeMs = queueDepth > 0 ? nowMs3 - Math.min(...queuedRuns.map((r6) => r6.queuedAt)) : null;
795070
795012
  return { slotsTotal, slotsInUse, queueDepth, oldestQueuedAgeMs };
795071
795013
  }
795072
795014
 
@@ -817092,7 +817034,7 @@ var createStyledCell = (char, overrides = {}) => ({
817092
817034
  // src/version.ts
817093
817035
  import { readFileSync } from "fs";
817094
817036
  import { join } from "path";
817095
- var _version = "1.1.4";
817037
+ var _version = "1.1.5";
817096
817038
  try {
817097
817039
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf-8"));
817098
817040
  _version = typeof pkg.version === "string" ? pkg.version : _version;
@@ -839605,7 +839547,7 @@ var WORK_PLAN_STATUSES = [
839605
839547
  "failed",
839606
839548
  "cancelled"
839607
839549
  ];
839608
- function nowMs2() {
839550
+ function nowMs3() {
839609
839551
  return Date.now();
839610
839552
  }
839611
839553
  function isObject4(value) {
@@ -839711,7 +839653,7 @@ class WorkPlanStore {
839711
839653
  if (!normalizedTitle)
839712
839654
  throw new Error("Work plan item title is required.");
839713
839655
  const plan = this.readPlan();
839714
- const time4 = nowMs2();
839656
+ const time4 = nowMs3();
839715
839657
  const item = {
839716
839658
  id: createItemId(),
839717
839659
  title: normalizedTitle,
@@ -839735,7 +839677,7 @@ class WorkPlanStore {
839735
839677
  updateItem(idOrPrefix, patch2) {
839736
839678
  const plan = this.readPlan();
839737
839679
  const item = this.resolveItem(plan, idOrPrefix);
839738
- const time4 = nowMs2();
839680
+ const time4 = nowMs3();
839739
839681
  const nextStatus = patch2.status ?? item.status;
839740
839682
  const next = this.pruneItem({
839741
839683
  ...item,
@@ -839768,7 +839710,7 @@ class WorkPlanStore {
839768
839710
  removeItem(idOrPrefix) {
839769
839711
  const plan = this.readPlan();
839770
839712
  const item = this.resolveItem(plan, idOrPrefix);
839771
- const time4 = nowMs2();
839713
+ const time4 = nowMs3();
839772
839714
  const remaining = plan.items.filter((candidate) => candidate.id !== item.id);
839773
839715
  this.writePlan({
839774
839716
  ...plan,
@@ -839788,7 +839730,7 @@ class WorkPlanStore {
839788
839730
  ...plan,
839789
839731
  items: remaining,
839790
839732
  activeItemId: remaining[0]?.id,
839791
- updatedAt: nowMs2()
839733
+ updatedAt: nowMs3()
839792
839734
  });
839793
839735
  return removed;
839794
839736
  }
@@ -839827,7 +839769,7 @@ class WorkPlanStore {
839827
839769
  const parsed = JSON.parse(raw);
839828
839770
  if (!isObject4(parsed))
839829
839771
  return this.createEmptyPlan();
839830
- const time4 = nowMs2();
839772
+ const time4 = nowMs3();
839831
839773
  const createdAt = typeof parsed.createdAt === "number" ? parsed.createdAt : time4;
839832
839774
  const updatedAt = typeof parsed.updatedAt === "number" ? parsed.updatedAt : createdAt;
839833
839775
  const items = Array.isArray(parsed.items) ? parsed.items.map((item) => normalizeItem(item, createdAt)).filter((item) => item !== null) : [];
@@ -839846,7 +839788,7 @@ class WorkPlanStore {
839846
839788
  };
839847
839789
  }
839848
839790
  createEmptyPlan() {
839849
- const time4 = nowMs2();
839791
+ const time4 = nowMs3();
839850
839792
  return {
839851
839793
  id: createPlanId(this.options.projectId, this.options.projectRoot),
839852
839794
  projectId: this.options.projectId,
@@ -849851,13 +849793,13 @@ init_state3();
849851
849793
 
849852
849794
  // src/input/commands/recall-shared.ts
849853
849795
  var VALID_CLASSES = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
849854
- var VALID_SCOPES2 = ["session", "project", "team"];
849796
+ var VALID_SCOPES = ["session", "project", "team"];
849855
849797
  var VALID_REVIEW_STATES = ["fresh", "reviewed", "stale", "contradicted"];
849856
849798
  function isValidClass(s4) {
849857
849799
  return VALID_CLASSES.includes(s4);
849858
849800
  }
849859
849801
  function isValidScope(s4) {
849860
- return VALID_SCOPES2.includes(s4);
849802
+ return VALID_SCOPES.includes(s4);
849861
849803
  }
849862
849804
  function isValidReviewState(s4) {
849863
849805
  return VALID_REVIEW_STATES.includes(s4);
@@ -849900,7 +849842,7 @@ function handleRecallSearch(args2, context) {
849900
849842
  if (isValidScope(scope))
849901
849843
  filter.scope = scope;
849902
849844
  else {
849903
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
849845
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
849904
849846
  return;
849905
849847
  }
849906
849848
  }
@@ -850075,7 +850017,7 @@ function handleRecallList(args2, context) {
850075
850017
  if (scopeIdx !== -1 && args2[scopeIdx + 1]) {
850076
850018
  const scope = args2[scopeIdx + 1];
850077
850019
  if (!isValidScope(scope)) {
850078
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850020
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
850079
850021
  return;
850080
850022
  }
850081
850023
  filter.scope = scope;
@@ -850125,7 +850067,7 @@ async function handleRecallAdd(args2, context) {
850125
850067
  const tags = tagsRaw ? tagsRaw.split(",").map((token) => token.trim()).filter(Boolean) : [];
850126
850068
  const scope = scopeRaw && isValidScope(scopeRaw) ? scopeRaw : "project";
850127
850069
  if (scopeRaw && !isValidScope(scopeRaw)) {
850128
- context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850070
+ context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES.join(", ")}.`);
850129
850071
  return;
850130
850072
  }
850131
850073
  const provenance = [];
@@ -850259,7 +850201,7 @@ function handleRecallExport(args2, context) {
850259
850201
  if (scopeIdx !== -1 && commandArgs[scopeIdx + 1]) {
850260
850202
  const scope = commandArgs[scopeIdx + 1];
850261
850203
  if (!isValidScope(scope)) {
850262
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850204
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
850263
850205
  return;
850264
850206
  }
850265
850207
  filter.scope = scope;
@@ -850338,7 +850280,7 @@ function handleRecallHandoffExport(args2, context) {
850338
850280
  const scopeIdx = commandArgs.indexOf("--scope");
850339
850281
  const scopeRaw = scopeIdx !== -1 ? commandArgs[scopeIdx + 1] : "team";
850340
850282
  if (!scopeRaw || !isValidScope(scopeRaw)) {
850341
- context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850283
+ context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES.join(", ")}.`);
850342
850284
  return;
850343
850285
  }
850344
850286
  const bundle = memory.exportBundle({ scope: scopeRaw });
@@ -850454,7 +850396,7 @@ function handleRecallPromote(args2, context) {
850454
850396
  const id = parsed.rest[0];
850455
850397
  const scope = parsed.rest[1];
850456
850398
  if (!id || !scope || !isValidScope(scope)) {
850457
- context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES2.join("|")}> --yes`);
850399
+ context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES.join("|")}> --yes`);
850458
850400
  return;
850459
850401
  }
850460
850402
  if (!parsed.yes) {
@@ -858623,7 +858565,7 @@ var AGENT_WORKSPACE_CATEGORY_IDS = [
858623
858565
  "onboarding-channels",
858624
858566
  "onboarding-voice-media",
858625
858567
  "onboarding-context",
858626
- "onboarding-verify",
858568
+ "onboarding-automation",
858627
858569
  "research",
858628
858570
  "artifacts",
858629
858571
  "conversation",
@@ -862058,6 +862000,7 @@ Use /channels list to see available channel ids.`);
862058
862000
  }
862059
862001
 
862060
862002
  // src/input/agent-workspace-snapshot.ts
862003
+ init_config8();
862061
862004
  import { basename as basename6, sep as sep3 } from "path";
862062
862005
 
862063
862006
  // src/agent/behavior-discovery-summary.ts
@@ -862265,6 +862208,13 @@ function buildAgentWorkspaceSetupChecklist(input) {
862265
862208
  detail: providerReady ? `Current chat route is ${input.provider} / ${input.model}.` : "Choose a provider and model before relying on assistant turns.",
862266
862209
  command: "Setup -> Provider and model"
862267
862210
  },
862211
+ {
862212
+ id: "subscriptions",
862213
+ label: "Provider subscriptions",
862214
+ status: input.activeSubscriptionCount > 0 ? "ready" : input.pendingSubscriptionCount > 0 ? "recommended" : input.availableSubscriptionProviderCount > 0 ? "recommended" : "optional",
862215
+ detail: input.activeSubscriptionCount > 0 ? `${input.activeSubscriptionCount} provider subscription session(s) are active.` : input.pendingSubscriptionCount > 0 ? `${input.pendingSubscriptionCount} provider subscription login(s) are pending completion.` : input.availableSubscriptionProviderCount > 0 ? `${input.availableSubscriptionProviderCount} subscription-capable provider(s) are available. Start login if you want subscription routing.` : "No subscription-capable providers are available yet. Use API keys or add an OAuth provider service.",
862216
+ command: "Start -> Start subscription login"
862217
+ },
862268
862218
  {
862269
862219
  id: "agent-knowledge",
862270
862220
  label: "Agent Knowledge",
@@ -862833,6 +862783,41 @@ function buildAgentWorkspaceRuntimeSnapshot(context) {
862833
862783
  const ttsVoice = readConfigString3(context, "tts.voice", "(voice default)");
862834
862784
  const ttsLlmProvider = readConfigString3(context, "tts.llmProvider", "");
862835
862785
  const ttsLlmModel = readConfigString3(context, "tts.llmModel", "");
862786
+ const embeddingProvider = readConfigString3(context, "provider.embeddingProvider", "(provider default)");
862787
+ const reasoningEffort = readConfigString3(context, "provider.reasoningEffort", "(default)");
862788
+ const helperEnabled = readConfigBoolean3(context, "helper.enabled", false);
862789
+ const toolLlmEnabled = readConfigBoolean3(context, "tools.llmEnabled", false);
862790
+ const providerFailureHints = readConfigBoolean3(context, "behavior.suggestAlternativeOnProviderFail", false);
862791
+ const cacheEnabled = readConfigBoolean3(context, "cache.enabled", true);
862792
+ const cacheStableTtl = readConfigString3(context, "cache.stableTtl", "(default)");
862793
+ const cacheMonitorHitRate = readConfigBoolean3(context, "cache.monitorHitRate", true);
862794
+ const cacheHitRateWarningThreshold = readConfigNumber(context, "cache.hitRateWarningThreshold", 0.3);
862795
+ const hitlMode = readConfigString3(context, "behavior.hitlMode", "(default)");
862796
+ const guidanceMode = readConfigString3(context, "behavior.guidanceMode", "(default)");
862797
+ const saveHistory2 = readConfigBoolean3(context, "behavior.saveHistory", true);
862798
+ const autoApprove = readConfigBoolean3(context, "behavior.autoApprove", false);
862799
+ const autoCompactThreshold = readConfigNumber(context, "behavior.autoCompactThreshold", 0);
862800
+ const staleContextWarnings = readConfigBoolean3(context, "behavior.staleContextWarnings", false);
862801
+ const showThinking = readConfigBoolean3(context, "display.showThinking", false);
862802
+ const showReasoningSummary = readConfigBoolean3(context, "display.showReasoningSummary", false);
862803
+ const theme = readConfigString3(context, "display.theme", "(default)");
862804
+ const stream6 = readConfigBoolean3(context, "display.stream", true);
862805
+ const lineNumbers = readConfigString3(context, "display.lineNumbers", "(default)");
862806
+ const operationalMessages = readConfigString3(context, "ui.operationalMessages", "(default)");
862807
+ const systemMessages = readConfigString3(context, "ui.systemMessages", "(default)");
862808
+ const releaseChannel = readConfigString3(context, "release.channel", "(default)");
862809
+ const permissionMode = readConfigString3(context, "permissions.mode", "(default)");
862810
+ const toolAutoHeal = readConfigBoolean3(context, "tools.autoHeal", false);
862811
+ const toolsDefaultTokenBudget = readConfigNumber(context, "tools.defaultTokenBudget", 5000);
862812
+ const artifactMaxBytes = readConfigNumber(context, "storage.artifacts.maxBytes", 512 * 1024 * 1024);
862813
+ const rawPromptTelemetry = readConfigBoolean3(context, "telemetry.includeRawPrompts", false);
862814
+ const automationEnabled = readConfigBoolean3(context, "automation.enabled", false);
862815
+ const automationMaxConcurrentRuns = readConfigNumber(context, "automation.maxConcurrentRuns", 4);
862816
+ const automationRunHistoryLimit = readConfigNumber(context, "automation.runHistoryLimit", 100);
862817
+ const automationDefaultTimeoutMs = readConfigNumber(context, "automation.defaultTimeoutMs", 15 * 60 * 1000);
862818
+ const automationCatchUpWindowMinutes = readConfigNumber(context, "automation.catchUpWindowMinutes", 30);
862819
+ const automationFailureCooldownMs = readConfigNumber(context, "automation.failureCooldownMs", 5 * 60 * 1000);
862820
+ const automationDeleteAfterRun = readConfigBoolean3(context, "automation.deleteAfterRun", false);
862836
862821
  const runtimeBaseUrl = `http://${host}:${port}`;
862837
862822
  const companionAccess = (() => {
862838
862823
  const homeDirectory = context.workspace?.shellPaths?.homeDirectory ?? "";
@@ -862854,6 +862839,18 @@ function buildAgentWorkspaceRuntimeSnapshot(context) {
862854
862839
  nextStep
862855
862840
  };
862856
862841
  })();
862842
+ const subscriptionSnapshot = (() => {
862843
+ try {
862844
+ const manager5 = context.platform?.subscriptionManager;
862845
+ const services = context.platform?.serviceRegistry;
862846
+ const active = manager5?.list?.().length ?? 0;
862847
+ const pending = manager5?.listPending?.().length ?? 0;
862848
+ const available = services ? listAvailableSubscriptionProviders(services.getAll()).length : 0;
862849
+ return { active, pending, available };
862850
+ } catch {
862851
+ return { active: 0, pending: 0, available: 0 };
862852
+ }
862853
+ })();
862857
862854
  const channels = buildAgentWorkspaceChannels(context);
862858
862855
  const voiceMediaReadiness = buildAgentWorkspaceVoiceMediaReadiness({
862859
862856
  context,
@@ -862864,6 +862861,9 @@ function buildAgentWorkspaceRuntimeSnapshot(context) {
862864
862861
  provider: provider5,
862865
862862
  model,
862866
862863
  runtimeBaseUrl,
862864
+ activeSubscriptionCount: subscriptionSnapshot.active,
862865
+ pendingSubscriptionCount: subscriptionSnapshot.pending,
862866
+ availableSubscriptionProviderCount: subscriptionSnapshot.available,
862867
862867
  sessionMemoryCount,
862868
862868
  localMemoryCount: memorySnapshot.count,
862869
862869
  localMemoryReviewQueueCount: memorySnapshot.reviewQueueCount,
@@ -862891,11 +862891,49 @@ function buildAgentWorkspaceRuntimeSnapshot(context) {
862891
862891
  provider: provider5,
862892
862892
  model,
862893
862893
  modelDisplayName: currentModel?.displayName ?? model,
862894
+ embeddingProvider,
862895
+ reasoningEffort,
862896
+ helperEnabled,
862897
+ toolLlmEnabled,
862898
+ providerFailureHints,
862899
+ cacheEnabled,
862900
+ cacheStableTtl,
862901
+ cacheMonitorHitRate,
862902
+ cacheHitRateWarningThreshold,
862903
+ hitlMode,
862904
+ guidanceMode,
862905
+ saveHistory: saveHistory2,
862906
+ autoApprove,
862907
+ autoCompactThreshold,
862908
+ staleContextWarnings,
862909
+ showThinking,
862910
+ showReasoningSummary,
862911
+ theme,
862912
+ stream: stream6,
862913
+ lineNumbers,
862914
+ operationalMessages,
862915
+ systemMessages,
862916
+ releaseChannel,
862917
+ permissionMode,
862918
+ toolAutoHeal,
862919
+ toolsDefaultTokenBudget,
862920
+ artifactMaxBytes,
862921
+ rawPromptTelemetry,
862922
+ automationEnabled,
862923
+ automationMaxConcurrentRuns,
862924
+ automationRunHistoryLimit,
862925
+ automationDefaultTimeoutMs,
862926
+ automationCatchUpWindowMinutes,
862927
+ automationFailureCooldownMs,
862928
+ automationDeleteAfterRun,
862894
862929
  sessionId: context.session?.runtime?.sessionId ?? "unknown",
862895
862930
  workingDirectory: context.workspace?.shellPaths?.workingDirectory ?? "unavailable",
862896
862931
  homeDirectory: context.workspace?.shellPaths?.homeDirectory ?? "unavailable",
862897
862932
  runtimeBaseUrl,
862898
862933
  runtimeOwnership: "external",
862934
+ activeSubscriptionCount: subscriptionSnapshot.active,
862935
+ pendingSubscriptionCount: subscriptionSnapshot.pending,
862936
+ availableSubscriptionProviderCount: subscriptionSnapshot.available,
862899
862937
  sessionMemoryCount,
862900
862938
  localMemoryCount: memorySnapshot.count,
862901
862939
  localMemoryReviewQueueCount: memorySnapshot.reviewQueueCount,
@@ -866599,7 +866637,7 @@ import { mkdirSync as mkdirSync66, readFileSync as readFileSync88, writeFileSync
866599
866637
  import { dirname as dirname64, resolve as resolve39 } from "path";
866600
866638
  init_state3();
866601
866639
  var VALID_CLASSES2 = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
866602
- var VALID_SCOPES4 = ["session", "project", "team"];
866640
+ var VALID_SCOPES3 = ["session", "project", "team"];
866603
866641
  var VALID_REVIEW_STATES3 = ["fresh", "reviewed", "stale", "contradicted"];
866604
866642
  var VALID_PROVENANCE_KINDS = ["session", "turn", "task", "event", "file"];
866605
866643
  var VALUE_OPTIONS = new Set([
@@ -866699,7 +866737,7 @@ function isMemoryClass2(value) {
866699
866737
  return VALID_CLASSES2.includes(value);
866700
866738
  }
866701
866739
  function isMemoryScope2(value) {
866702
- return VALID_SCOPES4.includes(value);
866740
+ return VALID_SCOPES3.includes(value);
866703
866741
  }
866704
866742
  function isReviewState(value) {
866705
866743
  return VALID_REVIEW_STATES3.includes(value);
@@ -866714,7 +866752,7 @@ function requireClass(value) {
866714
866752
  }
866715
866753
  function requireScope(value) {
866716
866754
  if (!value || !isMemoryScope2(value))
866717
- throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES4.join(", ")}`);
866755
+ throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES3.join(", ")}`);
866718
866756
  return value;
866719
866757
  }
866720
866758
  function optionalScope(value) {
@@ -881486,7 +881524,7 @@ function createAgentWorkspaceBasicCommandEditor(kind2) {
881486
881524
  selectedFieldIndex: 0,
881487
881525
  message: "Inspect one provider subscription route without starting login or printing token values.",
881488
881526
  fields: [
881489
- { id: "provider", label: "Provider", value: "openai", required: true, multiline: false, hint: "Subscription provider id from /subscription providers." }
881527
+ { id: "provider", label: "Provider", value: "openai", required: true, multiline: false, hint: "Subscription provider id, such as openai." }
881490
881528
  ]
881491
881529
  };
881492
881530
  }
@@ -881496,12 +881534,11 @@ function createAgentWorkspaceBasicCommandEditor(kind2) {
881496
881534
  mode: "create",
881497
881535
  title: "Start Provider Subscription Login",
881498
881536
  selectedFieldIndex: 0,
881499
- message: "Begin one provider subscription OAuth login. Type yes on the final field to confirm browser and pending-login side effects.",
881537
+ message: "Begin one provider subscription OAuth login, save the pending session, and return here for completion.",
881500
881538
  fields: [
881501
- { id: "provider", label: "Provider", value: "openai", required: true, multiline: false, hint: "Subscription provider id from /subscription providers." },
881539
+ { id: "provider", label: "Provider", value: "openai", required: true, multiline: false, hint: "Subscription provider id, such as openai." },
881502
881540
  { id: "openBrowser", label: "Open browser", value: "yes", required: false, multiline: false, hint: "yes/no. Use no to print the authorization URL only." },
881503
- { id: "manual", label: "Manual completion", value: "yes", required: false, multiline: false, hint: "Agent always finishes subscription login through the explicit finish form." },
881504
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /subscription login <provider> start with --yes." }
881541
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to save pending login state and open or show the authorization URL." }
881505
881542
  ]
881506
881543
  };
881507
881544
  }
@@ -881511,11 +881548,11 @@ function createAgentWorkspaceBasicCommandEditor(kind2) {
881511
881548
  mode: "update",
881512
881549
  title: "Finish Provider Subscription Login",
881513
881550
  selectedFieldIndex: 0,
881514
- message: "Finish a pending provider subscription OAuth login from a code or redirected URL. Type yes on the final field to confirm token storage.",
881551
+ message: "Finish a pending provider subscription OAuth login from a code or redirected URL and save the subscription session.",
881515
881552
  fields: [
881516
881553
  { id: "provider", label: "Provider", value: "openai", required: true, multiline: false, hint: "Provider id used when starting login." },
881517
881554
  { id: "code", label: "Code or redirect URL", value: "", required: true, multiline: false, hint: "OAuth code or full redirect URL containing code=..." },
881518
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /subscription login <provider> finish with --yes." }
881555
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to exchange the code and save the provider subscription session." }
881519
881556
  ]
881520
881557
  };
881521
881558
  }
@@ -881525,10 +881562,10 @@ function createAgentWorkspaceBasicCommandEditor(kind2) {
881525
881562
  mode: "delete",
881526
881563
  title: "Logout Provider Subscription",
881527
881564
  selectedFieldIndex: 0,
881528
- message: "Remove one stored provider subscription session. Ambient API key resolution applies again if configured. Type yes to confirm.",
881565
+ message: "Remove one active or pending provider subscription session. Ambient API key resolution applies again if configured.",
881529
881566
  fields: [
881530
881567
  { id: "provider", label: "Provider", value: "openai", required: true, multiline: false, hint: "Stored subscription provider id." },
881531
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /subscription logout with --yes." }
881568
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to remove active or pending subscription state." }
881532
881569
  ]
881533
881570
  };
881534
881571
  }
@@ -890312,6 +890349,14 @@ function activateAgentWorkspaceSelection(workspace, requestRender) {
890312
890349
  workspace.importTuiSettings(requestRender);
890313
890350
  return;
890314
890351
  }
890352
+ if (action2.kind === "model-picker") {
890353
+ workspace.openModelPickerAction(action2, requestRender);
890354
+ return;
890355
+ }
890356
+ if (action2.kind === "settings-modal") {
890357
+ workspace.openSettingsModalAction(action2, requestRender);
890358
+ return;
890359
+ }
890315
890360
  if (action2.kind === "editor" && action2.editorKind) {
890316
890361
  const editor = createAgentWorkspaceEditor(action2.editorKind, {
890317
890362
  runtimeStarterTemplates: workspace.runtimeSnapshot?.runtimeStarterTemplates ?? [],
@@ -890481,6 +890526,63 @@ function settingAction(options) {
890481
890526
  };
890482
890527
  }
890483
890528
 
890529
+ // src/input/agent-workspace-host-category.ts
890530
+ var AGENT_WORKSPACE_HOST_CATEGORY = {
890531
+ id: "host",
890532
+ group: "OPERATIONS",
890533
+ label: "Connected Host",
890534
+ summary: "Connected-host health, tasks, sessions, channels, and automation.",
890535
+ detail: "Use this workspace to inspect the GoodVibes host surfaces that Agent can see: system health, remote routes, host tasks, sessions, channels, schedules, knowledge, media, MCP, provider auth, support bundles, and telemetry/config posture.",
890536
+ actions: [
890537
+ { id: "host-overview", label: "Host overview", detail: "Review connected-host, provider, settings, continuity, and Agent health without starting or mutating host work.", command: "/health review", kind: "command", safety: "read-only" },
890538
+ { id: "host-services", label: "Host services", detail: "Inspect connected-host service readiness, credentials, and integration issues without changing them.", command: "/health host", kind: "command", safety: "read-only" },
890539
+ { id: "host-setup", label: "Setup review", detail: "Inspect setup issues that affect connected-host and Agent runtime readiness.", command: "/health setup", kind: "command", safety: "read-only" },
890540
+ { id: "host-remote", label: "Remote routes", detail: "Inspect remote build-host route health and recovery signals without starting build work.", command: "/health remote", kind: "command", safety: "read-only" },
890541
+ { id: "host-maintenance", label: "Session maintenance", detail: "Review continuity, compaction, and current-session maintenance posture.", command: "/health maintenance", kind: "command", safety: "read-only" },
890542
+ { id: "host-continuity", label: "Continuity", detail: "Inspect last-session pointer, recovery-file posture, and return-context state.", command: "/health continuity", kind: "command", safety: "read-only" },
890543
+ { id: "host-tasks", label: "Host tasks", detail: "Inspect connected-host task state without creating, retrying, or mutating tasks.", command: "/tasks list", kind: "command", safety: "read-only" },
890544
+ { id: "host-task-filter", label: "Filter host tasks", detail: "Open a status/type form for read-only connected-host task filtering.", editorKind: "task-list-filter", kind: "editor", safety: "read-only" },
890545
+ { id: "host-task-show", label: "Inspect host task", detail: "Open a task-id form for read-only connected-host task metadata.", editorKind: "task-show", kind: "editor", safety: "read-only" },
890546
+ { id: "host-task-output", label: "Show task output", detail: "Open a task-id form for read-only connected-host task output.", editorKind: "task-output", kind: "editor", safety: "read-only" },
890547
+ { id: "host-sessions", label: "Host session routes", detail: "Browse saved Agent sessions and return-context posture exposed through the runtime session surface.", command: "/session list", kind: "command", safety: "read-only" },
890548
+ { id: "host-session-graph", label: "Session graph", detail: "Open a read-only form for cross-session graph inspection; graph mutation remains blocked in Agent.", editorKind: "session-graph", kind: "editor", safety: "read-only" },
890549
+ { id: "host-channels-status", label: "Channel status", detail: "Inspect connected channel runtime status from the host without mutating delivery state.", command: "/channels status", kind: "command", safety: "read-only" },
890550
+ { id: "host-channel-accounts", label: "Channel accounts", detail: "Inspect connected channel accounts without printing secret values or sending messages.", command: "/channels accounts", kind: "command", safety: "read-only" },
890551
+ { id: "host-channel-policies", label: "Channel policies", detail: "Inspect channel delivery policy posture without changing routing.", command: "/channels policies", kind: "command", safety: "read-only" },
890552
+ { id: "host-channels", label: "Open Channels", detail: "Jump to the channel setup and delivery workspace.", targetCategoryId: "channels", kind: "workspace", safety: "safe" },
890553
+ { id: "host-automation", label: "Open Automation", detail: "Jump to connected schedules, reminders, receipts, and explicit run controls.", targetCategoryId: "automation", kind: "workspace", safety: "safe" },
890554
+ { id: "host-schedules", label: "Schedule status", detail: "Inspect schedules and run history without running or mutating them.", command: "/schedule list", kind: "command", safety: "read-only" },
890555
+ { id: "host-schedule-reconcile", label: "Reconcile schedules", detail: "Compare local promotion receipts with live connected schedules.", command: "/schedule reconcile", kind: "command", safety: "read-only" },
890556
+ { id: "host-knowledge", label: "Knowledge route", detail: "Inspect isolated Agent Knowledge route readiness and source counts.", command: "/knowledge status", kind: "command", safety: "read-only" },
890557
+ { id: "host-knowledge-open", label: "Open Knowledge", detail: "Jump to Agent Knowledge source, graph, review, and ingest controls.", targetCategoryId: "knowledge", kind: "workspace", safety: "safe" },
890558
+ { id: "host-media", label: "Media providers", detail: "Inspect configured media providers before generating media with confirmation.", command: "/media providers", kind: "command", safety: "read-only" },
890559
+ { id: "host-media-open", label: "Open Voice and Media", detail: "Jump to voice, TTS, image input, media provider, and browser-tool setup actions.", targetCategoryId: "voice-media", kind: "workspace", safety: "safe" },
890560
+ { id: "host-mcp-health", label: "MCP health", detail: "Inspect MCP lifecycle issues without changing trust posture or approving tool-definition review.", command: "/health mcp", kind: "command", safety: "read-only" },
890561
+ { id: "host-mcp-review", label: "MCP review", detail: "Inspect MCP server connection, trust, role, and review posture.", command: "/mcp review", kind: "command", safety: "read-only" },
890562
+ { id: "host-tools-open", label: "Open Tools and MCP", detail: "Jump to MCP server setup, tool inventory, secrets, and security review.", targetCategoryId: "tools", kind: "workspace", safety: "safe" },
890563
+ { id: "host-provider-accounts", label: "Provider accounts", detail: "Review provider account routes, subscription windows, and billing-path safety.", command: "/accounts review", kind: "command", safety: "read-only" },
890564
+ { id: "host-provider-detail", label: "Provider detail", detail: "Open a provider-id form for account and provider configuration review.", editorKind: "provider-inspect", kind: "editor", safety: "read-only" },
890565
+ { id: "host-provider-routes", label: "Provider routes", detail: "Open a provider-id form for account, subscription, and route inspection.", editorKind: "provider-routes", kind: "editor", safety: "read-only" },
890566
+ { id: "host-provider-repair", label: "Provider repair guidance", detail: "Open a provider-id form for read-only provider repair guidance.", editorKind: "provider-account-repair", kind: "editor", safety: "read-only" },
890567
+ { id: "host-auth-owner", label: "Connected-host auth owner", detail: "Show that connected-host auth administration belongs to the owning GoodVibes host, not Agent.", command: "/auth local", kind: "command", safety: "read-only" },
890568
+ { id: "host-auth-review", label: "Provider auth review", detail: "Review provider auth posture without printing token values.", command: "/auth review", kind: "command", safety: "read-only" },
890569
+ { id: "host-auth-detail", label: "Provider auth detail", detail: "Open a provider-id form for read-only provider auth inspection.", editorKind: "auth-show", kind: "editor", safety: "read-only" },
890570
+ { id: "host-auth-repair", label: "Provider auth repair", detail: "Open a provider-id form for provider auth repair guidance.", editorKind: "auth-repair", kind: "editor", safety: "read-only" },
890571
+ { id: "host-auth-bundle-export", label: "Export auth bundle", detail: "Open a confirmed form that exports a redacted provider auth review bundle.", editorKind: "auth-bundle-export", kind: "editor", safety: "safe" },
890572
+ { id: "host-auth-bundle-inspect", label: "Inspect auth bundle", detail: "Open a form that inspects a provider auth review bundle before sharing or import.", editorKind: "auth-bundle-inspect", kind: "editor", safety: "read-only" },
890573
+ { id: "host-subscription-bundle-export", label: "Export subscription bundle", detail: "Open a confirmed form that exports redacted provider subscription state for review.", editorKind: "subscription-bundle-export", kind: "editor", safety: "safe" },
890574
+ { id: "host-subscription-bundle-inspect", label: "Inspect subscription bundle", detail: "Open a form that inspects provider subscription state before sharing.", editorKind: "subscription-bundle-inspect", kind: "editor", safety: "read-only" },
890575
+ { id: "host-security", label: "Security review", detail: "Inspect token posture, MCP attack paths, policy lint, plugin risk, and incident pressure.", command: "/security review", kind: "command", safety: "read-only" },
890576
+ { id: "host-trust", label: "Trust review", detail: "Review permission, secret, plugin, and MCP trust posture without exporting bundles or changing trust.", command: "/trust review", kind: "command", safety: "read-only" },
890577
+ { id: "host-support-bundle-export", label: "Export support bundle", detail: "Export a redacted Agent support bundle from the Host page.", editorKind: "support-bundle-export", kind: "editor", safety: "safe" },
890578
+ { id: "host-support-bundle-inspect", label: "Inspect support bundle", detail: "Inspect a support bundle before import or sharing.", editorKind: "support-bundle-inspect", kind: "editor", safety: "read-only" },
890579
+ { id: "host-support-bundle-import", label: "Import support bundle", detail: "Import reviewed, non-redacted config values from a support bundle.", editorKind: "support-bundle-import", kind: "editor", safety: "safe" },
890580
+ { id: "host-telemetry", label: "Telemetry settings", detail: "Open telemetry payload policy settings for connected-host and Agent observability review.", command: "/config telemetry", kind: "command", safety: "safe" },
890581
+ { id: "host-config", label: "Control-plane settings", detail: "Open configuration controls for service, channels, tools, automation, provider, and storage posture.", command: "/config", kind: "command", safety: "safe" },
890582
+ { id: "host-safety", label: "Host mutation policy", detail: "Agent may inspect connected-host surfaces and run explicit confirmed actions, but does not silently create tasks, send channel messages, mutate auth, or start automation.", kind: "guidance", safety: "blocked" }
890583
+ ]
890584
+ };
890585
+
890484
890586
  // src/input/agent-workspace-categories.ts
890485
890587
  var AGENT_WORKSPACE_CATEGORIES = [
890486
890588
  {
@@ -890493,6 +890595,7 @@ var AGENT_WORKSPACE_CATEGORIES = [
890493
890595
  { id: "chat", label: "Continue assistant chat", detail: "Return to the main composer and type a normal message. Agent work stays serial in the main conversation.", kind: "guidance", safety: "safe" },
890494
890596
  { id: "brief", label: "Operator briefing", detail: "Show a concise Agent status and next-actions briefing without mutating the connected host.", command: "/brief", kind: "command", safety: "read-only" },
890495
890597
  { id: "model", label: "Choose model", detail: "Open the model/provider workspace for the Agent chat route.", command: "/model", kind: "command", safety: "safe" },
890598
+ { id: "model-refresh", label: "Refresh model catalog", detail: "Refresh locally cached provider model lists without changing the selected route.", command: "/refresh-models", kind: "command", safety: "safe" },
890496
890599
  { id: "setup-home", label: "Onboarding", detail: "Jump to first-run configuration for account, model, tools, channels, voice, local context, and finish.", targetCategoryId: "setup", kind: "workspace", safety: "safe" },
890497
890600
  { id: "channels-home", label: "Channels", detail: "Jump to companion pairing and channel readiness without changing connected-host routing.", targetCategoryId: "channels", kind: "workspace", safety: "read-only" },
890498
890601
  { id: "mode-show", label: "Interaction mode", detail: "Review Agent interaction noise level and per-domain verbosity.", command: "/mode show", kind: "command", safety: "read-only" },
@@ -890519,63 +890622,55 @@ var AGENT_WORKSPACE_CATEGORIES = [
890519
890622
  id: "setup",
890520
890623
  group: "ONBOARDING",
890521
890624
  label: "Start",
890522
- summary: "Import existing GoodVibes preferences, choose a main model, and sign in.",
890523
- detail: "Use this first. Every row either imports existing settings, edits a setting inline, or opens a concrete sign-in/provider form.",
890625
+ summary: "Import preferences, sign in, and choose the main model.",
890626
+ detail: "Start here on a fresh install. Every row either saves state, opens the shared model picker, or opens a confirmed in-modal form.",
890524
890627
  actions: [
890525
- { id: "import-goodvibes-tui-settings", label: "Import GoodVibes settings", detail: "Copy existing GoodVibes TUI display, provider, behavior, permission, TTS, channel, helper, tool, release, and automation values into Agent-owned settings.", kind: "settings-import", safety: "safe" },
890526
- settingAction({ id: "setup-provider-model", label: "Main model", detail: "Set the provider-qualified model used for normal assistant turns.", key: "provider.model" }),
890527
- settingAction({ id: "setup-reasoning-effort", label: "Reasoning effort", detail: "Cycle the reasoning level used when the selected model supports it.", key: "provider.reasoningEffort" }),
890528
- { id: "subscription-login-start", label: "Start subscription login", detail: "Open a confirmed form for one provider OAuth login start, with browser/manual completion controls.", editorKind: "subscription-login-start", kind: "editor", safety: "safe" },
890529
- { id: "subscription-login-finish", label: "Finish subscription login", detail: "Open a confirmed form that stores one completed provider subscription session from a code or redirect URL.", editorKind: "subscription-login-finish", kind: "editor", safety: "safe" },
890530
- { id: "subscription-logout", label: "Logout subscription", detail: "Open a confirmed form that removes one stored provider subscription session.", editorKind: "subscription-logout", kind: "editor", safety: "safe" },
890531
- { id: "subscription-inspect", label: "Inspect subscription route", detail: "Inspect one provider subscription OAuth route before starting or finishing login.", editorKind: "subscription-inspect", kind: "editor", safety: "read-only" },
890532
- { id: "subscription-bundle-export", label: "Export subscription bundle", detail: "Export a redacted provider subscription bundle for setup review.", editorKind: "subscription-bundle-export", kind: "editor", safety: "safe" },
890533
- { id: "subscription-bundle-inspect", label: "Inspect subscription bundle", detail: "Inspect a provider subscription bundle before setup review.", editorKind: "subscription-bundle-inspect", kind: "editor", safety: "read-only" },
890628
+ { id: "import-goodvibes-tui-settings", label: "Import GoodVibes settings", detail: "Copy existing display, provider, behavior, permission, TTS, channel, helper, tool, release, and automation values into Agent-owned settings.", kind: "settings-import", safety: "safe" },
890629
+ { id: "subscription-login-start", label: "Start subscription login", detail: "Start one provider sign-in flow, save pending state, and return here.", editorKind: "subscription-login-start", kind: "editor", safety: "safe" },
890630
+ { id: "subscription-login-finish", label: "Finish subscription login", detail: "Exchange a code or redirect URL and save the provider subscription session.", editorKind: "subscription-login-finish", kind: "editor", safety: "safe" },
890631
+ { id: "setup-provider-model", label: "Choose main model", detail: "Open the shared provider/model picker for normal assistant turns.", kind: "model-picker", modelPickerFlow: "providerModel", modelPickerTarget: "main", safety: "safe" },
890632
+ settingAction({ id: "setup-reasoning-effort", label: "Reasoning effort", detail: "Cycle reasoning level when the selected model supports it.", key: "provider.reasoningEffort" }),
890633
+ { id: "subscription-logout", label: "Logout subscription", detail: "Remove one stored or pending provider subscription session after confirmation.", editorKind: "subscription-logout", kind: "editor", safety: "safe" },
890534
890634
  { id: "provider-add", label: "Add custom provider", detail: "Add one OpenAI-compatible provider for Agent model routing.", editorKind: "provider-add", kind: "editor", safety: "safe" },
890535
- { id: "secret-set-provider", label: "Store API secret", detail: "Store a provider or channel credential through the Agent secret manager.", editorKind: "secret-set", kind: "editor", safety: "safe" },
890536
- settingAction({ id: "setup-secret-policy", label: "Secret storage policy", detail: "Choose whether secret persistence prefers or requires secure storage.", key: "storage.secretPolicy" }),
890537
- settingAction({ id: "setup-save-history", label: "Save conversation history", detail: "Toggle local conversation history persistence.", key: "behavior.saveHistory" })
890635
+ { id: "secret-set-provider", label: "Store secret", detail: "Store a provider or channel credential through the Agent secret manager.", editorKind: "secret-set", kind: "editor", safety: "safe" },
890636
+ settingAction({ id: "setup-secret-policy", label: "Secret storage", detail: "Choose how strongly Agent prefers secure secret storage.", key: "storage.secretPolicy" }),
890637
+ settingAction({ id: "setup-save-history", label: "Save history", detail: "Toggle local conversation history persistence.", key: "behavior.saveHistory" })
890538
890638
  ]
890539
890639
  },
890540
890640
  {
890541
890641
  id: "account-model",
890542
890642
  group: "ONBOARDING",
890543
- label: "Account & Model",
890544
- summary: "Model routing for chat, helpers, tools, embeddings, and spoken turns.",
890545
- detail: "Use this after sign-in to make model routing explicit for each workload.",
890643
+ label: "Model Routing",
890644
+ summary: "Set chat, embedding, helper, tool, and spoken-turn routes.",
890645
+ detail: "Use this after sign-in. Routes are saved settings, so selections persist across launches.",
890546
890646
  actions: [
890547
- { id: "provider-use", label: "Switch provider", detail: "Open a provider-id form that switches the Agent chat provider.", editorKind: "provider-use", kind: "editor", safety: "safe" },
890548
- { id: "provider-inspect", label: "Inspect provider auth", detail: "Inspect one provider auth/setup route without storing tokens or starting login.", editorKind: "provider-inspect", kind: "editor", safety: "read-only" },
890549
- { id: "provider-routes", label: "Inspect provider routes", detail: "Inspect provider route and fallback posture for one provider.", editorKind: "provider-routes", kind: "editor", safety: "read-only" },
890550
- { id: "provider-account-repair", label: "Provider repair guidance", detail: "Show provider account repair guidance without mutating credentials.", editorKind: "provider-account-repair", kind: "editor", safety: "read-only" },
890551
- { id: "provider-remove", label: "Remove custom provider", detail: "Remove one Agent custom provider config after confirmation.", editorKind: "provider-remove", kind: "editor", safety: "safe" },
890552
- { id: "model-refresh", label: "Refresh model catalog", detail: "Refresh model catalog, benchmark, and token-limit metadata.", command: "/refresh-models", kind: "command", safety: "safe" },
890553
- { id: "model-pin", label: "Pin model", detail: "Pin one model registry key for quick reuse.", editorKind: "model-pin", kind: "editor", safety: "safe" },
890554
- { id: "model-unpin", label: "Unpin model", detail: "Remove one pinned model registry key.", editorKind: "model-unpin", kind: "editor", safety: "safe" },
890555
- { id: "auth-show", label: "Show provider auth", detail: "Inspect provider auth state without printing token values.", editorKind: "auth-show", kind: "editor", safety: "read-only" },
890556
- { id: "auth-repair", label: "Auth repair guidance", detail: "Show auth repair guidance without storing tokens or starting login.", editorKind: "auth-repair", kind: "editor", safety: "read-only" },
890557
- { id: "auth-bundle-export", label: "Export auth bundle", detail: "Export a redacted auth review bundle after confirmation.", editorKind: "auth-bundle-export", kind: "editor", safety: "safe" },
890558
- { id: "auth-bundle-inspect", label: "Inspect auth bundle", detail: "Inspect an auth review bundle before setup review.", editorKind: "auth-bundle-inspect", kind: "editor", safety: "read-only" },
890559
- settingAction({ id: "account-main-model", label: "Main model", detail: "Edit the provider-qualified model registry key for normal assistant turns.", key: "provider.model" }),
890560
- settingAction({ id: "account-reasoning", label: "Reasoning effort", detail: "Cycle instant, low, medium, or high reasoning effort.", key: "provider.reasoningEffort" }),
890561
- settingAction({ id: "account-embedding", label: "Embedding provider", detail: "Set the embedding provider used by local memory and retrieval.", key: "provider.embeddingProvider" }),
890647
+ { id: "provider-use", label: "Choose provider and model", detail: "Open the shared provider/model picker for the main chat route.", kind: "model-picker", modelPickerFlow: "providerModel", modelPickerTarget: "main", safety: "safe" },
890648
+ { id: "provider-remove", label: "Remove custom provider", detail: "Remove one custom provider config after confirmation.", editorKind: "provider-remove", kind: "editor", safety: "safe" },
890649
+ { id: "account-main-model", label: "Choose main model", detail: "Open the shared model picker for normal assistant turns.", kind: "model-picker", modelPickerFlow: "model", modelPickerTarget: "main", safety: "safe" },
890650
+ settingAction({ id: "account-reasoning", label: "Reasoning effort", detail: "Cycle the reasoning effort used when supported.", key: "provider.reasoningEffort" }),
890651
+ settingAction({ id: "account-embedding", label: "Embedding provider", detail: "Set the embedding provider for memory and retrieval.", key: "provider.embeddingProvider" }),
890562
890652
  settingAction({ id: "account-system-prompt", label: "System prompt file", detail: "Set an optional local system prompt file path.", key: "provider.systemPromptFile" }),
890563
890653
  settingAction({ id: "account-helper-enabled", label: "Enable helper model", detail: "Toggle dedicated helper routing for background utility work.", key: "helper.enabled" }),
890564
- settingAction({ id: "account-helper-provider", label: "Helper provider", detail: "Set the helper provider id.", key: "helper.globalProvider", visibleWhenKey: "helper.enabled", visibleWhenValue: true }),
890565
- settingAction({ id: "account-helper-model", label: "Helper model", detail: "Set the helper model registry key.", key: "helper.globalModel", visibleWhenKey: "helper.enabled", visibleWhenValue: true }),
890654
+ { id: "account-helper-provider", label: "Choose helper provider/model", detail: "Open the shared provider/model picker for helper routing.", kind: "model-picker", modelPickerFlow: "providerModel", modelPickerTarget: "helper", visibleWhenSettingKey: "helper.enabled", visibleWhenSettingValue: true, safety: "safe" },
890655
+ { id: "account-helper-model", label: "Choose helper model", detail: "Open the shared model picker for helper routing.", kind: "model-picker", modelPickerFlow: "model", modelPickerTarget: "helper", visibleWhenSettingKey: "helper.enabled", visibleWhenSettingValue: true, safety: "safe" },
890566
890656
  settingAction({ id: "account-tool-llm-enabled", label: "Enable tool LLM", detail: "Toggle a dedicated tool LLM for internal operations.", key: "tools.llmEnabled" }),
890567
- settingAction({ id: "account-tool-provider", label: "Tool LLM provider", detail: "Set the provider for dedicated tool LLM calls.", key: "tools.llmProvider", visibleWhenKey: "tools.llmEnabled", visibleWhenValue: true }),
890568
- settingAction({ id: "account-tool-model", label: "Tool LLM model", detail: "Set the model for dedicated tool LLM calls.", key: "tools.llmModel", visibleWhenKey: "tools.llmEnabled", visibleWhenValue: true }),
890569
- settingAction({ id: "account-tts-llm-provider", label: "Spoken-turn provider", detail: "Set an optional provider override for spoken-response turns.", key: "tts.llmProvider" }),
890570
- settingAction({ id: "account-tts-llm-model", label: "Spoken-turn model", detail: "Set an optional model override for spoken-response turns.", key: "tts.llmModel" })
890657
+ { id: "account-tool-provider", label: "Choose tool provider/model", detail: "Open the shared provider/model picker for dedicated tool LLM calls.", kind: "model-picker", modelPickerFlow: "providerModel", modelPickerTarget: "tool", visibleWhenSettingKey: "tools.llmEnabled", visibleWhenSettingValue: true, safety: "safe" },
890658
+ { id: "account-tool-model", label: "Choose tool model", detail: "Open the shared model picker for dedicated tool LLM calls.", kind: "model-picker", modelPickerFlow: "model", modelPickerTarget: "tool", visibleWhenSettingKey: "tools.llmEnabled", visibleWhenSettingValue: true, safety: "safe" },
890659
+ { id: "account-tts-llm-provider", label: "Choose spoken-turn provider/model", detail: "Open the shared provider/model picker for spoken-response turns.", kind: "model-picker", modelPickerFlow: "providerModel", modelPickerTarget: "tts", safety: "safe" },
890660
+ { id: "account-tts-llm-model", label: "Choose spoken-turn model", detail: "Open the shared model picker for spoken-response turns.", kind: "model-picker", modelPickerFlow: "model", modelPickerTarget: "tts", safety: "safe" },
890661
+ settingAction({ id: "account-provider-fallback-hint", label: "Provider failure hints", detail: "Toggle alternative model suggestions when the current provider fails non-transiently.", key: "behavior.suggestAlternativeOnProviderFail" }),
890662
+ settingAction({ id: "account-cache-enabled", label: "Prompt cache", detail: "Toggle prompt caching for eligible providers.", key: "cache.enabled" }),
890663
+ settingAction({ id: "account-cache-ttl", label: "Cache TTL", detail: "Cycle ephemeral or persistent cache TTL for stable content.", key: "cache.stableTtl", visibleWhenKey: "cache.enabled", visibleWhenValue: true }),
890664
+ settingAction({ id: "account-cache-monitor", label: "Cache hit-rate monitor", detail: "Toggle cache hit-rate monitoring.", key: "cache.monitorHitRate", visibleWhenKey: "cache.enabled", visibleWhenValue: true }),
890665
+ settingAction({ id: "account-cache-threshold", label: "Cache warning threshold", detail: "Set the cache hit-rate warning threshold.", key: "cache.hitRateWarningThreshold", visibleWhenKey: "cache.monitorHitRate", visibleWhenValue: true })
890571
890666
  ]
890572
890667
  },
890573
890668
  {
890574
890669
  id: "assistant-behavior",
890575
890670
  group: "ONBOARDING",
890576
- label: "Assistant Behavior",
890577
- summary: "Interaction, context, notifications, and reasoning display.",
890578
- detail: "Use this page to decide how much the assistant talks while it works and how it handles context pressure.",
890671
+ label: "Behavior",
890672
+ summary: "Set interaction style, context pressure behavior, and visible reasoning.",
890673
+ detail: "Use this to choose how chat feels during normal work and long-running tasks.",
890579
890674
  actions: [
890580
890675
  settingAction({ id: "behavior-hitl-mode", label: "Interaction mode", detail: "Cycle quiet, balanced, or operator interaction mode.", key: "behavior.hitlMode" }),
890581
890676
  settingAction({ id: "behavior-guidance-mode", label: "Guidance mode", detail: "Cycle off, minimal, or guided operational guidance.", key: "behavior.guidanceMode" }),
@@ -890591,28 +890686,41 @@ var AGENT_WORKSPACE_CATEGORIES = [
890591
890686
  id: "tools-permissions",
890592
890687
  group: "ONBOARDING",
890593
890688
  label: "Tools & Permissions",
890594
- summary: "Tool approval policy, MCP trust entry points, and secret handling.",
890595
- detail: "Use this page to set how Agent asks before file, shell, network, MCP, workflow, and delegation operations.",
890689
+ summary: "Set approval policy, MCP entry points, and secret references.",
890690
+ detail: "Use this before enabling tool-heavy work. Permission rows write policy; MCP and secret rows open setup forms.",
890596
890691
  actions: [
890597
890692
  settingAction({ id: "permissions-mode", label: "Permission mode", detail: "Cycle prompt, allow-all, or custom permission mode.", key: "permissions.mode" }),
890693
+ settingAction({ id: "permissions-auto-approve", label: "Auto-approve tools", detail: "Toggle automatic approval for all tool permission requests.", key: "behavior.autoApprove" }),
890694
+ settingAction({ id: "permissions-read", label: "File reads", detail: "Cycle allow, prompt, or deny for file read operations.", key: "permissions.tools.read" }),
890695
+ settingAction({ id: "permissions-find", label: "File search", detail: "Cycle allow, prompt, or deny for file and directory search operations.", key: "permissions.tools.find" }),
890598
890696
  settingAction({ id: "permissions-write", label: "File writes", detail: "Cycle allow, prompt, or deny for file write operations.", key: "permissions.tools.write" }),
890599
890697
  settingAction({ id: "permissions-edit", label: "File edits", detail: "Cycle allow, prompt, or deny for edit and patch operations.", key: "permissions.tools.edit" }),
890600
890698
  settingAction({ id: "permissions-exec", label: "Shell commands", detail: "Cycle allow, prompt, or deny for shell execution.", key: "permissions.tools.exec" }),
890601
890699
  settingAction({ id: "permissions-fetch", label: "Network fetches", detail: "Cycle allow, prompt, or deny for outbound fetch requests.", key: "permissions.tools.fetch" }),
890700
+ settingAction({ id: "permissions-analyze", label: "Code analysis", detail: "Cycle allow, prompt, or deny for code and project analysis operations.", key: "permissions.tools.analyze" }),
890701
+ settingAction({ id: "permissions-inspect", label: "Runtime inspect", detail: "Cycle allow, prompt, or deny for runtime state inspection.", key: "permissions.tools.inspect" }),
890702
+ settingAction({ id: "permissions-state", label: "State reads", detail: "Cycle allow, prompt, or deny for reading runtime and session state.", key: "permissions.tools.state" }),
890703
+ settingAction({ id: "permissions-registry", label: "Registry reads", detail: "Cycle allow, prompt, or deny for tool and skill registry queries.", key: "permissions.tools.registry" }),
890602
890704
  settingAction({ id: "permissions-mcp", label: "MCP tools", detail: "Cycle allow, prompt, or deny for external MCP tool calls.", key: "permissions.tools.mcp" }),
890603
890705
  settingAction({ id: "permissions-agent", label: "Agent delegation", detail: "Cycle allow, prompt, or deny for subagent and delegation operations.", key: "permissions.tools.agent" }),
890604
890706
  settingAction({ id: "permissions-workflow", label: "Workflow automation", detail: "Cycle allow, prompt, or deny for multi-step workflow automation.", key: "permissions.tools.workflow" }),
890707
+ settingAction({ id: "permissions-delegate", label: "Unknown tools", detail: "Cycle allow, prompt, or deny for unknown or unregistered tools.", key: "permissions.tools.delegate" }),
890605
890708
  { id: "onboarding-mcp-server", label: "Add MCP server", detail: "Add or update one MCP server with command, args, role, trust, env refs, paths, and hosts.", editorKind: "mcp-server", kind: "editor", safety: "safe" },
890606
890709
  { id: "onboarding-secret-link", label: "Link secret reference", detail: "Link one config key to a goodvibes secret reference.", editorKind: "secret-link", kind: "editor", safety: "safe" },
890607
- { id: "onboarding-secret-test", label: "Test secret reference", detail: "Check one stored secret reference without printing the value.", editorKind: "secret-test", kind: "editor", safety: "safe" }
890710
+ { id: "onboarding-secret-test", label: "Test secret reference", detail: "Check one stored secret reference without printing the value.", editorKind: "secret-test", kind: "editor", safety: "safe" },
890711
+ settingAction({ id: "tools-auto-heal", label: "Tool auto-heal", detail: "Toggle automatic syntax repair for precision write and edit operations.", key: "tools.autoHeal" }),
890712
+ settingAction({ id: "tools-token-budget", label: "Tool token budget", detail: "Set the default token budget for precision read operations.", key: "tools.defaultTokenBudget" }),
890713
+ settingAction({ id: "tools-hooks-file", label: "Hooks file", detail: "Set the hook configuration file name relative to host data.", key: "tools.hooksFile" }),
890714
+ settingAction({ id: "storage-artifact-limit", label: "Artifact storage limit", detail: "Set the maximum artifact size for file, URL, multipart, and raw upload ingest.", key: "storage.artifacts.maxBytes" }),
890715
+ settingAction({ id: "telemetry-raw-prompts", label: "Raw prompt telemetry", detail: "Toggle raw prompt and response telemetry; leave off unless debugging locally.", key: "telemetry.includeRawPrompts" })
890608
890716
  ]
890609
890717
  },
890610
890718
  {
890611
890719
  id: "onboarding-display",
890612
890720
  group: "ONBOARDING",
890613
890721
  label: "Interface",
890614
- summary: "Display, streaming, operational messages, and release channel.",
890615
- detail: "Use this page to make the terminal readable for normal daily work.",
890722
+ summary: "Display, streaming, message placement, and release channel.",
890723
+ detail: "Use this page to make the terminal readable for daily operation.",
890616
890724
  actions: [
890617
890725
  settingAction({ id: "display-stream", label: "Stream tokens", detail: "Toggle streaming assistant tokens as they arrive.", key: "display.stream" }),
890618
890726
  settingAction({ id: "display-theme", label: "Theme", detail: "Set the color theme name.", key: "display.theme" }),
@@ -890629,18 +890737,20 @@ var AGENT_WORKSPACE_CATEGORIES = [
890629
890737
  id: "onboarding-channels",
890630
890738
  group: "ONBOARDING",
890631
890739
  label: "Messaging",
890632
- summary: "Messaging surfaces and settings for enabled channels.",
890633
- detail: "Start by enabling the channels you want. Channel-specific fields appear below each enabled channel.",
890740
+ summary: "Choose remote channels, then fill only the fields for enabled channels.",
890741
+ detail: "Enable the channels you actually want. Channel credentials and default targets are saved as Agent settings or secret refs.",
890634
890742
  actions: [
890635
- { id: "onboarding-pair-companion", label: "Pair companion app", detail: "Open the QR pairing view for companion access.", command: "/pair", kind: "command", safety: "safe" },
890636
890743
  settingAction({ id: "channel-ntfy-enabled", label: "Use ntfy", detail: "Toggle ntfy notifications and chat routing.", key: "surfaces.ntfy.enabled" }),
890637
890744
  settingAction({ id: "channel-ntfy-base-url", label: "ntfy base URL", detail: "Set the ntfy server URL.", key: "surfaces.ntfy.baseUrl", visibleWhenKey: "surfaces.ntfy.enabled", visibleWhenValue: true }),
890638
890745
  settingAction({ id: "channel-ntfy-chat-topic", label: "ntfy chat topic", detail: "Set the topic routed into active terminal chat.", key: "surfaces.ntfy.chatTopic", visibleWhenKey: "surfaces.ntfy.enabled", visibleWhenValue: true }),
890639
890746
  settingAction({ id: "channel-ntfy-agent-topic", label: "ntfy agent topic", detail: "Set the topic routed to Agent work.", key: "surfaces.ntfy.agentTopic", visibleWhenKey: "surfaces.ntfy.enabled", visibleWhenValue: true }),
890747
+ settingAction({ id: "channel-ntfy-default-topic", label: "ntfy default topic", detail: "Set the default outbound notification topic.", key: "surfaces.ntfy.topic", visibleWhenKey: "surfaces.ntfy.enabled", visibleWhenValue: true }),
890748
+ settingAction({ id: "channel-ntfy-remote-topic", label: "ntfy remote topic", detail: "Set the daemon-owned remote chat topic.", key: "surfaces.ntfy.remoteTopic", visibleWhenKey: "surfaces.ntfy.enabled", visibleWhenValue: true }),
890640
890749
  settingAction({ id: "channel-ntfy-token", label: "ntfy token", detail: "Store the ntfy access token or secret reference.", key: "surfaces.ntfy.token", visibleWhenKey: "surfaces.ntfy.enabled", visibleWhenValue: true }),
890641
890750
  settingAction({ id: "channel-ntfy-priority", label: "ntfy priority", detail: "Set default ntfy priority from 1 to 5.", key: "surfaces.ntfy.defaultPriority", visibleWhenKey: "surfaces.ntfy.enabled", visibleWhenValue: true }),
890642
890751
  settingAction({ id: "channel-slack-enabled", label: "Use Slack", detail: "Toggle Slack adapter configuration.", key: "surfaces.slack.enabled" }),
890643
890752
  settingAction({ id: "channel-slack-bot-token", label: "Slack bot token", detail: "Store the Slack bot token or secret reference.", key: "surfaces.slack.botToken", visibleWhenKey: "surfaces.slack.enabled", visibleWhenValue: true }),
890753
+ settingAction({ id: "channel-slack-app-token", label: "Slack app token", detail: "Store the Slack app token or secret reference.", key: "surfaces.slack.appToken", visibleWhenKey: "surfaces.slack.enabled", visibleWhenValue: true }),
890644
890754
  settingAction({ id: "channel-slack-signing-secret", label: "Slack signing secret", detail: "Store the Slack signing secret or secret reference.", key: "surfaces.slack.signingSecret", visibleWhenKey: "surfaces.slack.enabled", visibleWhenValue: true }),
890645
890755
  settingAction({ id: "channel-slack-default-channel", label: "Slack default channel", detail: "Set the default Slack channel for notifications and replies.", key: "surfaces.slack.defaultChannel", visibleWhenKey: "surfaces.slack.enabled", visibleWhenValue: true }),
890646
890756
  settingAction({ id: "channel-slack-workspace", label: "Slack workspace ID", detail: "Set the Slack workspace id for route binding.", key: "surfaces.slack.workspaceId", visibleWhenKey: "surfaces.slack.enabled", visibleWhenValue: true }),
@@ -890648,49 +890758,67 @@ var AGENT_WORKSPACE_CATEGORIES = [
890648
890758
  settingAction({ id: "channel-discord-bot-token", label: "Discord bot token", detail: "Store the Discord bot token or secret reference.", key: "surfaces.discord.botToken", visibleWhenKey: "surfaces.discord.enabled", visibleWhenValue: true }),
890649
890759
  settingAction({ id: "channel-discord-application", label: "Discord application ID", detail: "Set the Discord application id.", key: "surfaces.discord.applicationId", visibleWhenKey: "surfaces.discord.enabled", visibleWhenValue: true }),
890650
890760
  settingAction({ id: "channel-discord-public-key", label: "Discord public key", detail: "Set the Discord application public key.", key: "surfaces.discord.publicKey", visibleWhenKey: "surfaces.discord.enabled", visibleWhenValue: true }),
890761
+ settingAction({ id: "channel-discord-guild", label: "Discord guild ID", detail: "Set the default Discord guild id.", key: "surfaces.discord.guildId", visibleWhenKey: "surfaces.discord.enabled", visibleWhenValue: true }),
890651
890762
  settingAction({ id: "channel-discord-default-channel", label: "Discord default channel", detail: "Set the default Discord channel id.", key: "surfaces.discord.defaultChannelId", visibleWhenKey: "surfaces.discord.enabled", visibleWhenValue: true }),
890652
890763
  settingAction({ id: "channel-webhook-enabled", label: "Use webhooks", detail: "Toggle generic webhook delivery.", key: "surfaces.webhook.enabled" }),
890653
890764
  settingAction({ id: "channel-webhook-target", label: "Webhook target URL", detail: "Set the default outbound webhook target URL.", key: "surfaces.webhook.defaultTarget", visibleWhenKey: "surfaces.webhook.enabled", visibleWhenValue: true }),
890654
890765
  settingAction({ id: "channel-webhook-secret", label: "Webhook secret", detail: "Store the shared webhook secret or secret reference.", key: "surfaces.webhook.secret", visibleWhenKey: "surfaces.webhook.enabled", visibleWhenValue: true }),
890766
+ settingAction({ id: "channel-webhook-timeout", label: "Webhook timeout", detail: "Set outbound webhook timeout in milliseconds.", key: "surfaces.webhook.timeoutMs", visibleWhenKey: "surfaces.webhook.enabled", visibleWhenValue: true }),
890655
890767
  settingAction({ id: "channel-telegram-enabled", label: "Use Telegram", detail: "Toggle Telegram bot delivery.", key: "surfaces.telegram.enabled" }),
890656
890768
  settingAction({ id: "channel-telegram-bot-token", label: "Telegram bot token", detail: "Store the Telegram bot token or secret reference.", key: "surfaces.telegram.botToken", visibleWhenKey: "surfaces.telegram.enabled", visibleWhenValue: true }),
890769
+ settingAction({ id: "channel-telegram-bot-username", label: "Telegram bot username", detail: "Set the Telegram bot username.", key: "surfaces.telegram.botUsername", visibleWhenKey: "surfaces.telegram.enabled", visibleWhenValue: true }),
890657
890770
  settingAction({ id: "channel-telegram-chat", label: "Telegram chat ID", detail: "Set the default Telegram chat, group, or channel id.", key: "surfaces.telegram.defaultChatId", visibleWhenKey: "surfaces.telegram.enabled", visibleWhenValue: true }),
890658
890771
  settingAction({ id: "channel-telegram-mode", label: "Telegram mode", detail: "Cycle webhook or polling ingress mode.", key: "surfaces.telegram.mode", visibleWhenKey: "surfaces.telegram.enabled", visibleWhenValue: true }),
890772
+ settingAction({ id: "channel-telegram-webhook-secret", label: "Telegram webhook secret", detail: "Store the Telegram webhook secret or secret reference.", key: "surfaces.telegram.webhookSecret", visibleWhenKey: "surfaces.telegram.enabled", visibleWhenValue: true }),
890659
890773
  settingAction({ id: "channel-googlechat-enabled", label: "Use Google Chat", detail: "Toggle Google Chat delivery.", key: "surfaces.googleChat.enabled" }),
890660
890774
  settingAction({ id: "channel-googlechat-webhook", label: "Google Chat webhook", detail: "Set the Google Chat webhook or app callback URL.", key: "surfaces.googleChat.webhookUrl", visibleWhenKey: "surfaces.googleChat.enabled", visibleWhenValue: true }),
890775
+ settingAction({ id: "channel-googlechat-space", label: "Google Chat space", detail: "Set the default Google Chat space id.", key: "surfaces.googleChat.spaceId", visibleWhenKey: "surfaces.googleChat.enabled", visibleWhenValue: true }),
890776
+ settingAction({ id: "channel-googlechat-app-id", label: "Google Chat app ID", detail: "Set the Google Chat app id.", key: "surfaces.googleChat.appId", visibleWhenKey: "surfaces.googleChat.enabled", visibleWhenValue: true }),
890777
+ settingAction({ id: "channel-googlechat-verification", label: "Google Chat verification", detail: "Store the Google Chat verification token or secret reference.", key: "surfaces.googleChat.verificationToken", visibleWhenKey: "surfaces.googleChat.enabled", visibleWhenValue: true }),
890661
890778
  settingAction({ id: "channel-homeassistant-enabled", label: "Use home automation", detail: "Toggle home automation conversation and event delivery.", key: "surfaces.homeassistant.enabled" }),
890662
890779
  settingAction({ id: "channel-homeassistant-url", label: "Home automation URL", detail: "Set the home automation instance URL.", key: "surfaces.homeassistant.instanceUrl", visibleWhenKey: "surfaces.homeassistant.enabled", visibleWhenValue: true }),
890663
890780
  settingAction({ id: "channel-homeassistant-token", label: "Home automation token", detail: "Store the home automation access token or secret reference.", key: "surfaces.homeassistant.accessToken", visibleWhenKey: "surfaces.homeassistant.enabled", visibleWhenValue: true }),
890781
+ settingAction({ id: "channel-homeassistant-webhook-secret", label: "Home automation webhook secret", detail: "Store the shared secret used to verify inbound callbacks.", key: "surfaces.homeassistant.webhookSecret", visibleWhenKey: "surfaces.homeassistant.enabled", visibleWhenValue: true }),
890782
+ settingAction({ id: "channel-homeassistant-conversation", label: "Home automation conversation", detail: "Set the default conversation id.", key: "surfaces.homeassistant.defaultConversationId", visibleWhenKey: "surfaces.homeassistant.enabled", visibleWhenValue: true }),
890783
+ settingAction({ id: "channel-homeassistant-device-id", label: "Home automation device ID", detail: "Set the stable device id exposed to the home automation surface.", key: "surfaces.homeassistant.deviceId", visibleWhenKey: "surfaces.homeassistant.enabled", visibleWhenValue: true }),
890784
+ settingAction({ id: "channel-homeassistant-device-name", label: "Home automation device name", detail: "Set the device display name exposed to the home automation surface.", key: "surfaces.homeassistant.deviceName", visibleWhenKey: "surfaces.homeassistant.enabled", visibleWhenValue: true }),
890785
+ settingAction({ id: "channel-homeassistant-event-type", label: "Home automation event type", detail: "Set the event type used for daemon-to-home automation delivery.", key: "surfaces.homeassistant.eventType", visibleWhenKey: "surfaces.homeassistant.enabled", visibleWhenValue: true }),
890786
+ settingAction({ id: "channel-homeassistant-session-ttl", label: "Home automation session TTL", detail: "Set the idle TTL for remote home automation conversation sessions.", key: "surfaces.homeassistant.remoteSessionTtlMs", visibleWhenKey: "surfaces.homeassistant.enabled", visibleWhenValue: true }),
890664
890787
  settingAction({ id: "channel-signal-enabled", label: "Use Signal", detail: "Toggle Signal bridge delivery.", key: "surfaces.signal.enabled" }),
890665
890788
  settingAction({ id: "channel-signal-bridge", label: "Signal bridge URL", detail: "Set the Signal bridge base URL.", key: "surfaces.signal.bridgeUrl", visibleWhenKey: "surfaces.signal.enabled", visibleWhenValue: true }),
890789
+ settingAction({ id: "channel-signal-account", label: "Signal account", detail: "Set the Signal account id or phone number.", key: "surfaces.signal.account", visibleWhenKey: "surfaces.signal.enabled", visibleWhenValue: true }),
890790
+ settingAction({ id: "channel-signal-token", label: "Signal token", detail: "Store the Signal bridge token or secret reference.", key: "surfaces.signal.token", visibleWhenKey: "surfaces.signal.enabled", visibleWhenValue: true }),
890666
890791
  settingAction({ id: "channel-signal-recipient", label: "Signal recipient", detail: "Set the default Signal recipient or group.", key: "surfaces.signal.defaultRecipient", visibleWhenKey: "surfaces.signal.enabled", visibleWhenValue: true }),
890667
890792
  settingAction({ id: "channel-whatsapp-enabled", label: "Use WhatsApp", detail: "Toggle WhatsApp delivery.", key: "surfaces.whatsapp.enabled" }),
890668
890793
  settingAction({ id: "channel-whatsapp-provider", label: "WhatsApp provider", detail: "Cycle Meta Cloud API or bridge provider mode.", key: "surfaces.whatsapp.provider", visibleWhenKey: "surfaces.whatsapp.enabled", visibleWhenValue: true }),
890669
890794
  settingAction({ id: "channel-whatsapp-token", label: "WhatsApp access token", detail: "Store the WhatsApp provider access token or secret reference.", key: "surfaces.whatsapp.accessToken", visibleWhenKey: "surfaces.whatsapp.enabled", visibleWhenValue: true }),
890795
+ settingAction({ id: "channel-whatsapp-phone-id", label: "WhatsApp phone number ID", detail: "Set the WhatsApp phone number id.", key: "surfaces.whatsapp.phoneNumberId", visibleWhenKey: "surfaces.whatsapp.enabled", visibleWhenValue: true }),
890796
+ settingAction({ id: "channel-whatsapp-business-id", label: "WhatsApp business ID", detail: "Set the WhatsApp business account id.", key: "surfaces.whatsapp.businessAccountId", visibleWhenKey: "surfaces.whatsapp.enabled", visibleWhenValue: true }),
890797
+ settingAction({ id: "channel-whatsapp-verify", label: "WhatsApp verify token", detail: "Store the WhatsApp verify token or secret reference.", key: "surfaces.whatsapp.verifyToken", visibleWhenKey: "surfaces.whatsapp.enabled", visibleWhenValue: true }),
890798
+ settingAction({ id: "channel-whatsapp-signing", label: "WhatsApp signing secret", detail: "Store the WhatsApp signing secret or secret reference.", key: "surfaces.whatsapp.signingSecret", visibleWhenKey: "surfaces.whatsapp.enabled", visibleWhenValue: true }),
890670
890799
  settingAction({ id: "channel-whatsapp-recipient", label: "WhatsApp recipient", detail: "Set the default WhatsApp recipient or chat id.", key: "surfaces.whatsapp.defaultRecipient", visibleWhenKey: "surfaces.whatsapp.enabled", visibleWhenValue: true }),
890671
890800
  settingAction({ id: "channel-imessage-enabled", label: "Use iMessage", detail: "Toggle iMessage bridge delivery.", key: "surfaces.imessage.enabled" }),
890672
890801
  settingAction({ id: "channel-imessage-bridge", label: "iMessage bridge URL", detail: "Set the iMessage bridge base URL.", key: "surfaces.imessage.bridgeUrl", visibleWhenKey: "surfaces.imessage.enabled", visibleWhenValue: true }),
890673
- settingAction({ id: "channel-imessage-chat", label: "iMessage chat ID", detail: "Set the default iMessage chat id.", key: "surfaces.imessage.defaultChatId", visibleWhenKey: "surfaces.imessage.enabled", visibleWhenValue: true }),
890674
- { id: "onboarding-notify-webhook", label: "Add notification webhook", detail: "Add one webhook target for explicit reminder and routine delivery.", editorKind: "notify-webhook", kind: "editor", safety: "safe" },
890675
- { id: "onboarding-test-webhook", label: "Test notification webhooks", detail: "Send one confirmed test notification to configured webhook targets.", editorKind: "notify-webhook-test", kind: "editor", safety: "safe" }
890802
+ settingAction({ id: "channel-imessage-account", label: "iMessage account", detail: "Set the iMessage account id.", key: "surfaces.imessage.account", visibleWhenKey: "surfaces.imessage.enabled", visibleWhenValue: true }),
890803
+ settingAction({ id: "channel-imessage-token", label: "iMessage token", detail: "Store the iMessage bridge token or secret reference.", key: "surfaces.imessage.token", visibleWhenKey: "surfaces.imessage.enabled", visibleWhenValue: true }),
890804
+ settingAction({ id: "channel-imessage-chat", label: "iMessage chat ID", detail: "Set the default iMessage chat id.", key: "surfaces.imessage.defaultChatId", visibleWhenKey: "surfaces.imessage.enabled", visibleWhenValue: true })
890676
890805
  ]
890677
890806
  },
890678
890807
  {
890679
890808
  id: "onboarding-voice-media",
890680
890809
  group: "ONBOARDING",
890681
890810
  label: "Voice & Phone",
890682
- summary: "Configure spoken replies, TTS routing, media prompts, and telephony.",
890683
- detail: "Use this page for local voice, spoken-output defaults, image/media prompts, and SMS or phone-call delivery.",
890811
+ summary: "Configure voice controls, spoken output, and SMS or phone-call delivery.",
890812
+ detail: "Use this page for saved voice/TTS settings and telephony credentials. Generating media is available later from Voice & Media.",
890684
890813
  actions: [
890685
890814
  settingAction({ id: "voice-enabled", label: "Use voice controls", detail: "Toggle the optional local voice control surface.", key: "ui.voiceEnabled" }),
890686
890815
  settingAction({ id: "voice-tts-provider", label: "TTS provider", detail: "Set the default text-to-speech provider id.", key: "tts.provider" }),
890687
890816
  settingAction({ id: "voice-tts-voice", label: "TTS voice", detail: "Set the default text-to-speech voice id.", key: "tts.voice" }),
890688
- { id: "voice-speak-prompt", label: "Try spoken prompt", detail: "Open a prompt form for a spoken assistant reply through configured TTS.", editorKind: "tts-prompt", kind: "editor", safety: "safe" },
890689
- { id: "media-attach-image", label: "Attach image", detail: "Attach a local image path and optional prompt to the next assistant turn.", editorKind: "image-input", kind: "editor", safety: "safe" },
890690
- { id: "onboarding-media-generate", label: "Generate media", detail: "Generate image or video artifacts through a configured media provider after confirmation.", editorKind: "media-generate", kind: "editor", safety: "safe" },
890691
890817
  settingAction({ id: "telephony-enabled", label: "Use telephony", detail: "Toggle SMS, voice call, or telephony bridge delivery.", key: "surfaces.telephony.enabled" }),
890692
890818
  settingAction({ id: "telephony-provider", label: "Telephony provider", detail: "Cycle direct provider or bridge mode.", key: "surfaces.telephony.provider", visibleWhenKey: "surfaces.telephony.enabled", visibleWhenValue: true }),
890693
890819
  settingAction({ id: "telephony-mode", label: "Telephony mode", detail: "Cycle SMS, voice call, or bridge delivery mode.", key: "surfaces.telephony.mode", visibleWhenKey: "surfaces.telephony.enabled", visibleWhenValue: true }),
890820
+ settingAction({ id: "telephony-bridge-url", label: "Telephony bridge URL", detail: "Set the telephony bridge base URL.", key: "surfaces.telephony.bridgeUrl", visibleWhenKey: "surfaces.telephony.enabled", visibleWhenValue: true }),
890821
+ settingAction({ id: "telephony-token", label: "Telephony bridge token", detail: "Store the telephony bridge token or secret reference.", key: "surfaces.telephony.token", visibleWhenKey: "surfaces.telephony.enabled", visibleWhenValue: true }),
890694
890822
  settingAction({ id: "telephony-account-sid", label: "Twilio account SID", detail: "Set the Twilio account SID for provider-direct delivery.", key: "surfaces.telephony.accountSid", visibleWhenKey: "surfaces.telephony.enabled", visibleWhenValue: true }),
890695
890823
  settingAction({ id: "telephony-auth-token", label: "Twilio auth token", detail: "Store the Twilio auth token or secret reference.", key: "surfaces.telephony.authToken", visibleWhenKey: "surfaces.telephony.enabled", visibleWhenValue: true }),
890696
890824
  settingAction({ id: "telephony-from", label: "Sender phone number", detail: "Set the default caller or sender phone number.", key: "surfaces.telephony.fromNumber", visibleWhenKey: "surfaces.telephony.enabled", visibleWhenValue: true }),
@@ -890702,9 +890830,9 @@ var AGENT_WORKSPACE_CATEGORIES = [
890702
890830
  {
890703
890831
  id: "onboarding-context",
890704
890832
  group: "ONBOARDING",
890705
- label: "Context",
890706
- summary: "Local persona, memory, skills, routines, notes, and Agent Knowledge.",
890707
- detail: "Use this page to make the assistant useful with durable local context and source-backed knowledge.",
890833
+ label: "Local Context",
890834
+ summary: "Create/import memory, personas, skills, routines, notes, and Knowledge.",
890835
+ detail: "Use this page to seed the assistant with durable local context. These forms create Agent-owned records or ingest reviewed sources.",
890708
890836
  actions: [
890709
890837
  { id: "context-profile-from-discovered", label: "Profile from discovered files", detail: "Create an isolated Agent profile from reviewed local persona, skill, and routine files.", editorKind: "profile-from-discovered", kind: "editor", safety: "safe" },
890710
890838
  { id: "context-persona-discovery", label: "Import persona files", detail: "Import discovered persona files into the Agent persona registry.", editorKind: "persona-discovery-import", kind: "editor", safety: "safe" },
@@ -890722,20 +890850,19 @@ var AGENT_WORKSPACE_CATEGORIES = [
890722
890850
  ]
890723
890851
  },
890724
890852
  {
890725
- id: "onboarding-verify",
890853
+ id: "onboarding-automation",
890726
890854
  group: "ONBOARDING",
890727
- label: "Verify",
890728
- summary: "Review the configured runtime before finishing onboarding.",
890729
- detail: "Use this page to inspect health, model/provider state, channels, MCP, and knowledge before applying the completion marker.",
890855
+ label: "Automation Setup",
890856
+ summary: "Set scheduled work limits for reminders and routines.",
890857
+ detail: "Use this page to enable automation and set bounded run limits. Creating actual reminders and routines remains a separate confirmed action.",
890730
890858
  actions: [
890731
- { id: "verify-brief", label: "Operator briefing", detail: "Show a concise status and next-action briefing.", command: "/brief", kind: "command", safety: "read-only" },
890732
- { id: "verify-health", label: "Health review", detail: "Review local runtime and connected-host status.", command: "/health review", kind: "command", safety: "read-only" },
890733
- { id: "verify-compat", label: "Compatibility", detail: "Inspect connected-host compatibility and Agent Knowledge route readiness.", command: "/compat", kind: "command", safety: "read-only" },
890734
- { id: "verify-provider", label: "Provider status", detail: "Inspect provider/model routing state.", command: "/provider", kind: "command", safety: "read-only" },
890735
- { id: "verify-subscription", label: "Subscription status", detail: "Inspect active and pending provider subscription sessions.", command: "/subscription review", kind: "command", safety: "read-only" },
890736
- { id: "verify-channels", label: "Channel readiness", detail: "Inspect channel readiness and enabled-channel attention items.", command: "/channels attention", kind: "command", safety: "read-only" },
890737
- { id: "verify-mcp", label: "MCP review", detail: "Inspect MCP server connection, role, trust, and quarantine posture.", command: "/mcp review", kind: "command", safety: "read-only" },
890738
- { id: "verify-knowledge", label: "Knowledge status", detail: "Inspect isolated Agent Knowledge readiness and counts.", command: "/knowledge status", kind: "command", safety: "read-only" }
890859
+ settingAction({ id: "automation-enabled", label: "Use automation", detail: "Toggle the automation subsystem for reminders and scheduled routines.", key: "automation.enabled" }),
890860
+ settingAction({ id: "automation-max-concurrent", label: "Concurrent runs", detail: "Set the maximum automation runs that can execute concurrently.", key: "automation.maxConcurrentRuns", visibleWhenKey: "automation.enabled", visibleWhenValue: true }),
890861
+ settingAction({ id: "automation-history-limit", label: "Run history limit", detail: "Set the number of run history entries retained per automation job.", key: "automation.runHistoryLimit", visibleWhenKey: "automation.enabled", visibleWhenValue: true }),
890862
+ settingAction({ id: "automation-default-timeout", label: "Default timeout", detail: "Set the default automation run timeout in milliseconds.", key: "automation.defaultTimeoutMs", visibleWhenKey: "automation.enabled", visibleWhenValue: true }),
890863
+ settingAction({ id: "automation-catch-up", label: "Catch-up window", detail: "Set how long startup should catch up missed automation runs.", key: "automation.catchUpWindowMinutes", visibleWhenKey: "automation.enabled", visibleWhenValue: true }),
890864
+ settingAction({ id: "automation-failure-cooldown", label: "Failure cooldown", detail: "Set the cooldown after a failed automation run.", key: "automation.failureCooldownMs", visibleWhenKey: "automation.enabled", visibleWhenValue: true }),
890865
+ settingAction({ id: "automation-delete-after-run", label: "Delete one-shot jobs", detail: "Toggle deleting one-shot automation jobs after their first successful run.", key: "automation.deleteAfterRun", visibleWhenKey: "automation.enabled", visibleWhenValue: true })
890739
890866
  ]
890740
890867
  },
890741
890868
  {
@@ -891171,52 +891298,7 @@ var AGENT_WORKSPACE_CATEGORIES = [
891171
891298
  { id: "approval-cancel", label: "Cancel request", detail: "Open a confirmed form for cancelling one pending connected-host approval request by id.", editorKind: "approval-cancel", kind: "editor", safety: "safe" }
891172
891299
  ]
891173
891300
  },
891174
- {
891175
- id: "host",
891176
- group: "OPERATIONS",
891177
- label: "Connected Host",
891178
- summary: "Connected-host health, tasks, sessions, channels, and automation.",
891179
- detail: "Use this workspace to inspect the GoodVibes host surfaces that Agent can see: system health, remote routes, host tasks, sessions, channels, schedules, knowledge, media, MCP, provider auth, support bundles, and telemetry/config posture.",
891180
- actions: [
891181
- { id: "host-overview", label: "Host overview", detail: "Review connected-host, provider, settings, continuity, and Agent health without starting or mutating host work.", command: "/health review", kind: "command", safety: "read-only" },
891182
- { id: "host-services", label: "Host services", detail: "Inspect connected-host service readiness, credentials, and integration issues without changing them.", command: "/health host", kind: "command", safety: "read-only" },
891183
- { id: "host-setup", label: "Setup review", detail: "Inspect setup issues that affect connected-host and Agent runtime readiness.", command: "/health setup", kind: "command", safety: "read-only" },
891184
- { id: "host-remote", label: "Remote routes", detail: "Inspect remote build-host route health and recovery signals without starting build work.", command: "/health remote", kind: "command", safety: "read-only" },
891185
- { id: "host-maintenance", label: "Session maintenance", detail: "Review continuity, compaction, and current-session maintenance posture.", command: "/health maintenance", kind: "command", safety: "read-only" },
891186
- { id: "host-continuity", label: "Continuity", detail: "Inspect last-session pointer, recovery-file posture, and return-context state.", command: "/health continuity", kind: "command", safety: "read-only" },
891187
- { id: "host-tasks", label: "Host tasks", detail: "Inspect connected-host task state without creating, retrying, or mutating tasks.", command: "/tasks list", kind: "command", safety: "read-only" },
891188
- { id: "host-task-filter", label: "Filter host tasks", detail: "Open a status/type form for read-only connected-host task filtering.", editorKind: "task-list-filter", kind: "editor", safety: "read-only" },
891189
- { id: "host-task-show", label: "Inspect host task", detail: "Open a task-id form for read-only connected-host task metadata.", editorKind: "task-show", kind: "editor", safety: "read-only" },
891190
- { id: "host-task-output", label: "Show task output", detail: "Open a task-id form for read-only connected-host task output.", editorKind: "task-output", kind: "editor", safety: "read-only" },
891191
- { id: "host-sessions", label: "Host session routes", detail: "Browse saved Agent sessions and return-context posture exposed through the runtime session surface.", command: "/session list", kind: "command", safety: "read-only" },
891192
- { id: "host-session-graph", label: "Session graph", detail: "Open a read-only form for cross-session graph inspection; graph mutation remains blocked in Agent.", editorKind: "session-graph", kind: "editor", safety: "read-only" },
891193
- { id: "host-channels-status", label: "Channel status", detail: "Inspect connected channel runtime status from the host without mutating delivery state.", command: "/channels status", kind: "command", safety: "read-only" },
891194
- { id: "host-channel-accounts", label: "Channel accounts", detail: "Inspect connected channel accounts without printing secret values or sending messages.", command: "/channels accounts", kind: "command", safety: "read-only" },
891195
- { id: "host-channel-policies", label: "Channel policies", detail: "Inspect channel delivery policy posture without changing routing.", command: "/channels policies", kind: "command", safety: "read-only" },
891196
- { id: "host-channels", label: "Open Channels", detail: "Jump to the channel setup and delivery workspace.", targetCategoryId: "channels", kind: "workspace", safety: "safe" },
891197
- { id: "host-automation", label: "Open Automation", detail: "Jump to connected schedules, reminders, receipts, and explicit run controls.", targetCategoryId: "automation", kind: "workspace", safety: "safe" },
891198
- { id: "host-schedules", label: "Schedule status", detail: "Inspect schedules and run history without running or mutating them.", command: "/schedule list", kind: "command", safety: "read-only" },
891199
- { id: "host-schedule-reconcile", label: "Reconcile schedules", detail: "Compare local promotion receipts with live connected schedules.", command: "/schedule reconcile", kind: "command", safety: "read-only" },
891200
- { id: "host-knowledge", label: "Knowledge route", detail: "Inspect isolated Agent Knowledge route readiness and source counts.", command: "/knowledge status", kind: "command", safety: "read-only" },
891201
- { id: "host-knowledge-open", label: "Open Knowledge", detail: "Jump to Agent Knowledge source, graph, review, and ingest controls.", targetCategoryId: "knowledge", kind: "workspace", safety: "safe" },
891202
- { id: "host-media", label: "Media providers", detail: "Inspect configured media providers before generating media with confirmation.", command: "/media providers", kind: "command", safety: "read-only" },
891203
- { id: "host-media-open", label: "Open Voice and Media", detail: "Jump to voice, TTS, image input, media provider, and browser-tool setup actions.", targetCategoryId: "voice-media", kind: "workspace", safety: "safe" },
891204
- { id: "host-mcp-health", label: "MCP health", detail: "Inspect MCP lifecycle issues without changing trust posture or approving tool-definition review.", command: "/health mcp", kind: "command", safety: "read-only" },
891205
- { id: "host-mcp-review", label: "MCP review", detail: "Inspect MCP server connection, trust, role, and review posture.", command: "/mcp review", kind: "command", safety: "read-only" },
891206
- { id: "host-tools-open", label: "Open Tools and MCP", detail: "Jump to MCP server setup, tool inventory, secrets, and security review.", targetCategoryId: "tools", kind: "workspace", safety: "safe" },
891207
- { id: "host-provider-accounts", label: "Provider accounts", detail: "Review provider account routes, subscription windows, and billing-path safety.", command: "/accounts review", kind: "command", safety: "read-only" },
891208
- { id: "host-auth-owner", label: "Connected-host auth owner", detail: "Show that connected-host auth administration belongs to the owning GoodVibes host, not Agent.", command: "/auth local", kind: "command", safety: "read-only" },
891209
- { id: "host-auth-review", label: "Provider auth review", detail: "Review provider auth posture without printing token values.", command: "/auth review", kind: "command", safety: "read-only" },
891210
- { id: "host-security", label: "Security review", detail: "Inspect token posture, MCP attack paths, policy lint, plugin risk, and incident pressure.", command: "/security review", kind: "command", safety: "read-only" },
891211
- { id: "host-trust", label: "Trust review", detail: "Review permission, secret, plugin, and MCP trust posture without exporting bundles or changing trust.", command: "/trust review", kind: "command", safety: "read-only" },
891212
- { id: "host-support-bundle-export", label: "Export support bundle", detail: "Export a redacted Agent support bundle from the Host page.", editorKind: "support-bundle-export", kind: "editor", safety: "safe" },
891213
- { id: "host-support-bundle-inspect", label: "Inspect support bundle", detail: "Inspect a support bundle before import or sharing.", editorKind: "support-bundle-inspect", kind: "editor", safety: "read-only" },
891214
- { id: "host-support-bundle-import", label: "Import support bundle", detail: "Import reviewed, non-redacted config values from a support bundle.", editorKind: "support-bundle-import", kind: "editor", safety: "safe" },
891215
- { id: "host-telemetry", label: "Telemetry settings", detail: "Open telemetry payload policy settings for connected-host and Agent observability review.", command: "/config telemetry", kind: "command", safety: "safe" },
891216
- { id: "host-config", label: "Control-plane settings", detail: "Open configuration controls for service, channels, tools, automation, provider, and storage posture.", command: "/config", kind: "command", safety: "safe" },
891217
- { id: "host-safety", label: "Host mutation policy", detail: "Agent may inspect connected-host surfaces and run explicit confirmed actions, but does not silently create tasks, send channel messages, mutate auth, or start automation.", kind: "guidance", safety: "blocked" }
891218
- ]
891219
- },
891301
+ AGENT_WORKSPACE_HOST_CATEGORY,
891220
891302
  {
891221
891303
  id: "automation",
891222
891304
  group: "OPERATIONS",
@@ -891287,6 +891369,9 @@ function searchAgentWorkspaceActions(categories, query2) {
891287
891369
  action2.command ?? "",
891288
891370
  action2.editorKind ?? "",
891289
891371
  action2.targetCategoryId ?? "",
891372
+ action2.modelPickerFlow ?? "",
891373
+ action2.modelPickerTarget ?? "",
891374
+ action2.settingsTarget ?? "",
891290
891375
  action2.localOperation ?? "",
891291
891376
  action2.safety
891292
891377
  ].join(" ").toLowerCase();
@@ -891317,6 +891402,9 @@ function scoreActionSearchResult(result2, exactQuery, terms) {
891317
891402
  score += scoreField(action2.editorKind, terms, exactQuery, 85, 26);
891318
891403
  score += scoreField(action2.command, terms, exactQuery, 75, 22);
891319
891404
  score += scoreField(action2.label, terms, exactQuery, 65, 18);
891405
+ score += scoreField(action2.modelPickerTarget, terms, exactQuery, 58, 18);
891406
+ score += scoreField(action2.settingsTarget, terms, exactQuery, 58, 18);
891407
+ score += scoreField(action2.modelPickerFlow, terms, exactQuery, 54, 16);
891320
891408
  score += scoreField(action2.localOperation, terms, exactQuery, 50, 16);
891321
891409
  score += scoreField(action2.targetCategoryId, terms, exactQuery, 40, 12);
891322
891410
  score += scoreField(action2.detail, terms, exactQuery, 24, 6);
@@ -895422,6 +895510,163 @@ function handleMcpWorkspaceToken(workspace, token, handleEscape2, requestRender)
895422
895510
  return true;
895423
895511
  }
895424
895512
 
895513
+ // src/input/agent-workspace-requirements.ts
895514
+ function buildAgentWorkspaceRequirements(readField) {
895515
+ return buildAgentSkillRequirements({
895516
+ env: splitList5(readField("requiresEnv")),
895517
+ commands: splitList5(readField("requiresCommands"))
895518
+ });
895519
+ }
895520
+
895521
+ // src/input/agent-workspace-local-editor-submission.ts
895522
+ function submitAgentWorkspaceLocalRegistryEditor(shellPaths3, editor, callbacks) {
895523
+ const field = callbacks.readField;
895524
+ if (editor.mode === "delete") {
895525
+ callbacks.submitDeleteEditor();
895526
+ return;
895527
+ }
895528
+ if (editor.kind === "learned-behavior") {
895529
+ const created = createAgentWorkspaceLearnedBehavior(shellPaths3, {
895530
+ target: callbacks.learnedBehaviorTarget(),
895531
+ name: field("name"),
895532
+ description: field("description"),
895533
+ notes: field("notes"),
895534
+ tags: splitList5(field("tags")),
895535
+ triggers: splitList5(field("triggers")),
895536
+ enable: isAffirmative15(field("enable"))
895537
+ });
895538
+ callbacks.finishLocalEditor(created.kind, created.id, created.name, "Created");
895539
+ } else if (editor.kind === "profile") {
895540
+ const template = field("template");
895541
+ const templateId = template && template.toLowerCase() !== "none" ? template : undefined;
895542
+ const profile5 = createAgentRuntimeProfile(shellPaths3.homeDirectory, field("name"), {
895543
+ ...templateId ? { templateId } : {}
895544
+ });
895545
+ callbacks.finishProfileEditor(profile5);
895546
+ } else if (editor.kind === "note") {
895547
+ submitNoteEditor(shellPaths3, editor, field, callbacks.finishLocalEditor);
895548
+ } else if (editor.kind === "persona") {
895549
+ submitPersonaEditor(shellPaths3, editor, field, callbacks.finishLocalEditor);
895550
+ } else if (editor.kind === "skill") {
895551
+ submitSkillEditor(shellPaths3, editor, field, callbacks.finishLocalEditor);
895552
+ } else {
895553
+ submitRoutineEditor(shellPaths3, editor, field, callbacks.finishLocalEditor);
895554
+ }
895555
+ }
895556
+ function submitNoteEditor(shellPaths3, editor, field, finish) {
895557
+ const registry5 = AgentNoteRegistry.fromShellPaths(shellPaths3);
895558
+ if (editor.mode === "update" && editor.recordId) {
895559
+ const updated = registry5.update(editor.recordId, {
895560
+ title: field("title"),
895561
+ body: field("body"),
895562
+ sourceUrl: field("sourceUrl"),
895563
+ tags: splitList5(field("tags")),
895564
+ provenance: "Workspace"
895565
+ });
895566
+ finish("note", updated.id, updated.title, "Updated");
895567
+ return;
895568
+ }
895569
+ const created = registry5.create({
895570
+ title: field("title"),
895571
+ body: field("body"),
895572
+ sourceUrl: field("sourceUrl"),
895573
+ tags: splitList5(field("tags")),
895574
+ source: "user",
895575
+ provenance: "Workspace"
895576
+ });
895577
+ finish("note", created.id, created.title, "Created");
895578
+ }
895579
+ function submitPersonaEditor(shellPaths3, editor, field, finish) {
895580
+ const registry5 = AgentPersonaRegistry.fromShellPaths(shellPaths3);
895581
+ if (editor.mode === "update" && editor.recordId) {
895582
+ const wasActive = registry5.snapshot().activePersonaId === editor.recordId;
895583
+ const updated = registry5.update(editor.recordId, {
895584
+ name: field("name"),
895585
+ description: field("description"),
895586
+ body: field("body"),
895587
+ tags: splitList5(field("tags")),
895588
+ triggers: splitList5(field("triggers")),
895589
+ provenance: "Workspace"
895590
+ });
895591
+ if (isAffirmative15(field("activate")))
895592
+ registry5.setActive(updated.id);
895593
+ else if (wasActive)
895594
+ registry5.clearActive();
895595
+ finish("persona", updated.id, updated.name, "Updated");
895596
+ return;
895597
+ }
895598
+ const created = registry5.create({
895599
+ name: field("name"),
895600
+ description: field("description"),
895601
+ body: field("body"),
895602
+ tags: splitList5(field("tags")),
895603
+ triggers: splitList5(field("triggers")),
895604
+ source: "user",
895605
+ provenance: "Workspace"
895606
+ });
895607
+ if (isAffirmative15(field("activate")))
895608
+ registry5.setActive(created.id);
895609
+ finish("persona", created.id, created.name, "Created");
895610
+ }
895611
+ function submitSkillEditor(shellPaths3, editor, field, finish) {
895612
+ const registry5 = AgentSkillRegistry.fromShellPaths(shellPaths3);
895613
+ if (editor.mode === "update" && editor.recordId) {
895614
+ const updated = registry5.update(editor.recordId, {
895615
+ name: field("name"),
895616
+ description: field("description"),
895617
+ procedure: field("procedure"),
895618
+ triggers: splitList5(field("triggers")),
895619
+ tags: splitList5(field("tags")),
895620
+ requirements: buildAgentWorkspaceRequirements(field),
895621
+ provenance: "Workspace"
895622
+ });
895623
+ registry5.setEnabled(updated.id, isAffirmative15(field("enabled")));
895624
+ finish("skill", updated.id, updated.name, "Updated");
895625
+ return;
895626
+ }
895627
+ const created = registry5.create({
895628
+ name: field("name"),
895629
+ description: field("description"),
895630
+ procedure: field("procedure"),
895631
+ triggers: splitList5(field("triggers")),
895632
+ tags: splitList5(field("tags")),
895633
+ requirements: buildAgentWorkspaceRequirements(field),
895634
+ enabled: isAffirmative15(field("enabled")),
895635
+ source: "user",
895636
+ provenance: "Workspace"
895637
+ });
895638
+ finish("skill", created.id, created.name, "Created");
895639
+ }
895640
+ function submitRoutineEditor(shellPaths3, editor, field, finish) {
895641
+ const registry5 = AgentRoutineRegistry.fromShellPaths(shellPaths3);
895642
+ if (editor.mode === "update" && editor.recordId) {
895643
+ const updated = registry5.update(editor.recordId, {
895644
+ name: field("name"),
895645
+ description: field("description"),
895646
+ steps: field("steps"),
895647
+ triggers: splitList5(field("triggers")),
895648
+ tags: splitList5(field("tags")),
895649
+ requirements: buildAgentWorkspaceRequirements(field),
895650
+ provenance: "Workspace"
895651
+ });
895652
+ registry5.setEnabled(updated.id, isAffirmative15(field("enabled")));
895653
+ finish("routine", updated.id, updated.name, "Updated");
895654
+ return;
895655
+ }
895656
+ const created = registry5.create({
895657
+ name: field("name"),
895658
+ description: field("description"),
895659
+ steps: field("steps"),
895660
+ triggers: splitList5(field("triggers")),
895661
+ tags: splitList5(field("tags")),
895662
+ requirements: buildAgentWorkspaceRequirements(field),
895663
+ enabled: isAffirmative15(field("enabled")),
895664
+ source: "user",
895665
+ provenance: "Workspace"
895666
+ });
895667
+ finish("routine", created.id, created.name, "Created");
895668
+ }
895669
+
895425
895670
  // src/input/agent-workspace-local-selection.ts
895426
895671
  function agentWorkspaceLocalLibraryItems(snapshot2, kind2) {
895427
895672
  if (kind2 === "memory")
@@ -895782,14 +896027,6 @@ function selectAgentWorkspaceCategory(host, categoryIdOrLabel) {
895782
896027
  return true;
895783
896028
  }
895784
896029
 
895785
- // src/input/agent-workspace-requirements.ts
895786
- function buildAgentWorkspaceRequirements(readField) {
895787
- return buildAgentSkillRequirements({
895788
- env: splitList5(readField("requiresEnv")),
895789
- commands: splitList5(readField("requiresCommands"))
895790
- });
895791
- }
895792
-
895793
896030
  // src/input/agent-workspace-settings.ts
895794
896031
  import { existsSync as existsSync87, readFileSync as readFileSync94 } from "fs";
895795
896032
  var GOODVIBES_TUI_SURFACE_ROOT = "tui";
@@ -896037,6 +896274,166 @@ function createSettingEditor(setting, currentValue, action2) {
896037
896274
  ]
896038
896275
  };
896039
896276
  }
896277
+
896278
+ // src/input/agent-workspace-subscription-editor.ts
896279
+ init_config8();
896280
+ async function submitAgentWorkspaceSubscriptionLoginStartEditor(host, editor, context, readField) {
896281
+ if (!isAffirmative15(readField("confirm"))) {
896282
+ host.localEditor = { ...editor, message: "Subscription login start not confirmed. Type yes, then press Enter." };
896283
+ host.status = "Subscription login start not confirmed.";
896284
+ return;
896285
+ }
896286
+ try {
896287
+ const provider5 = readField("provider") || "openai";
896288
+ const openBrowser2 = isAffirmative15(readField("openBrowser"));
896289
+ const { manager: manager5, services } = subscriptionServices(context);
896290
+ const resolved = getSubscriptionProviderConfig(provider5, services.get(provider5));
896291
+ if (!resolved) {
896292
+ throw new Error(`OAuth is not configured for ${provider5}. Add an OAuth provider service or choose a built-in subscription provider.`);
896293
+ }
896294
+ const started = provider5 === "openai" && resolved.source === "builtin" ? await beginOpenAICodexLogin() : null;
896295
+ const authorizationUrl = started ? started.authorizationUrl : (await manager5.beginOAuthLogin(provider5, resolveManualLoginConfig2(resolved.oauth))).authorizationUrl;
896296
+ if (started) {
896297
+ manager5.savePending({
896298
+ provider: provider5,
896299
+ state: started.state,
896300
+ verifier: started.verifier,
896301
+ redirectUri: started.redirectUri,
896302
+ createdAt: Date.now()
896303
+ });
896304
+ }
896305
+ const browserOpened = openBrowser2 ? await openExternalUrl(authorizationUrl) : false;
896306
+ host.localEditor = null;
896307
+ host.runtimeSnapshot = context ? buildAgentWorkspaceRuntimeSnapshot(context) : host.runtimeSnapshot;
896308
+ host.status = `Subscription login started for ${provider5}.`;
896309
+ host.lastActionResult = {
896310
+ kind: "refreshed",
896311
+ title: "Subscription login started",
896312
+ detail: [
896313
+ `Provider: ${provider5}.`,
896314
+ `Browser: ${openBrowser2 ? browserOpened ? "opened" : "open failed" : "skipped"}.`,
896315
+ "Use Finish subscription login with the callback code or redirect URL.",
896316
+ `Authorization URL: ${authorizationUrl}`
896317
+ ].join(" "),
896318
+ safety: "safe"
896319
+ };
896320
+ host.clampSelection();
896321
+ } catch (error53) {
896322
+ const detail = error53 instanceof Error ? error53.message : String(error53);
896323
+ host.localEditor = { ...editor, message: detail };
896324
+ host.status = detail;
896325
+ host.lastActionResult = { kind: "error", title: "Subscription login start failed", detail, safety: "safe" };
896326
+ }
896327
+ }
896328
+ async function submitAgentWorkspaceSubscriptionLoginFinishEditor(host, editor, context, readField) {
896329
+ if (!isAffirmative15(readField("confirm"))) {
896330
+ host.localEditor = { ...editor, message: "Subscription login finish not confirmed. Type yes, then press Enter." };
896331
+ host.status = "Subscription login finish not confirmed.";
896332
+ return;
896333
+ }
896334
+ try {
896335
+ const provider5 = readField("provider") || "openai";
896336
+ const codeInput = readField("code");
896337
+ const code2 = extractAuthorizationCode3(codeInput) ?? codeInput;
896338
+ const { manager: manager5, services } = subscriptionServices(context);
896339
+ const resolved = getSubscriptionProviderConfig(provider5, services.get(provider5));
896340
+ if (!resolved) {
896341
+ throw new Error(`OAuth is not configured for ${provider5}. Start with a configured or built-in subscription provider.`);
896342
+ }
896343
+ const record2 = provider5 === "openai" && resolved.source === "builtin" ? (() => {
896344
+ const pending = manager5.getPending(provider5);
896345
+ if (!pending)
896346
+ throw new Error(`No pending OAuth login for ${provider5}. Start subscription login first.`);
896347
+ return exchangeOpenAICodexCode(code2, pending.verifier).then((token) => {
896348
+ const now5 = Date.now();
896349
+ return manager5.saveSubscription({
896350
+ provider: provider5,
896351
+ accessToken: token.accessToken,
896352
+ tokenType: token.tokenType,
896353
+ ...typeof token.refreshToken === "string" && token.refreshToken.length > 0 ? { refreshToken: token.refreshToken } : {},
896354
+ ...typeof token.expiresAt === "number" && Number.isFinite(token.expiresAt) ? { expiresAt: token.expiresAt } : {},
896355
+ ...token.scopes ? { scopes: token.scopes } : {},
896356
+ authMode: "oauth",
896357
+ overrideAmbientApiKeys: false,
896358
+ createdAt: manager5.get(provider5)?.createdAt ?? now5,
896359
+ updatedAt: now5
896360
+ });
896361
+ });
896362
+ })() : manager5.completeOAuthLogin(provider5, resolveManualLoginConfig2(resolved.oauth), code2);
896363
+ const saved = await record2;
896364
+ host.localEditor = null;
896365
+ host.runtimeSnapshot = context ? buildAgentWorkspaceRuntimeSnapshot(context) : host.runtimeSnapshot;
896366
+ host.status = `Subscription session saved for ${provider5}.`;
896367
+ host.lastActionResult = {
896368
+ kind: "refreshed",
896369
+ title: "Subscription session saved",
896370
+ detail: [
896371
+ `Provider: ${provider5}.`,
896372
+ `Token type: ${saved.tokenType}.`,
896373
+ `Expires: ${saved.expiresAt ? new Date(saved.expiresAt).toISOString() : "n/a"}.`,
896374
+ describeSubscriptionPrecedence(saved)
896375
+ ].join(" "),
896376
+ safety: "safe"
896377
+ };
896378
+ host.clampSelection();
896379
+ } catch (error53) {
896380
+ const detail = error53 instanceof Error ? error53.message : String(error53);
896381
+ host.localEditor = { ...editor, message: detail };
896382
+ host.status = detail;
896383
+ host.lastActionResult = { kind: "error", title: "Subscription login finish failed", detail, safety: "safe" };
896384
+ }
896385
+ }
896386
+ function submitAgentWorkspaceSubscriptionLogoutEditor(host, editor, context, readField) {
896387
+ if (!isAffirmative15(readField("confirm"))) {
896388
+ host.localEditor = { ...editor, message: "Subscription logout not confirmed. Type yes, then press Enter." };
896389
+ host.status = "Subscription logout not confirmed.";
896390
+ return;
896391
+ }
896392
+ try {
896393
+ const provider5 = readField("provider") || "openai";
896394
+ const { manager: manager5 } = subscriptionServices(context);
896395
+ const removed = manager5.logout(provider5);
896396
+ host.localEditor = null;
896397
+ host.runtimeSnapshot = context ? buildAgentWorkspaceRuntimeSnapshot(context) : host.runtimeSnapshot;
896398
+ host.status = removed ? `Logged out of ${provider5}.` : `No subscription session existed for ${provider5}.`;
896399
+ host.lastActionResult = {
896400
+ kind: removed ? "refreshed" : "guidance",
896401
+ title: removed ? "Subscription session removed" : "No subscription session found",
896402
+ detail: removed ? `Removed active or pending subscription state for ${provider5}. Ambient API key resolution applies if configured.` : `No active or pending subscription state existed for ${provider5}.`,
896403
+ safety: "safe"
896404
+ };
896405
+ host.clampSelection();
896406
+ } catch (error53) {
896407
+ const detail = error53 instanceof Error ? error53.message : String(error53);
896408
+ host.localEditor = { ...editor, message: detail };
896409
+ host.status = detail;
896410
+ host.lastActionResult = { kind: "error", title: "Subscription logout failed", detail, safety: "safe" };
896411
+ }
896412
+ }
896413
+ function subscriptionServices(context) {
896414
+ const manager5 = context?.platform.subscriptionManager;
896415
+ const services = context?.platform.serviceRegistry;
896416
+ if (!manager5 || !services)
896417
+ throw new Error("Subscription services are unavailable in this runtime.");
896418
+ return { manager: manager5, services };
896419
+ }
896420
+ function extractAuthorizationCode3(input) {
896421
+ const trimmed2 = input.trim();
896422
+ if (!trimmed2)
896423
+ return null;
896424
+ try {
896425
+ const url2 = new URL(trimmed2);
896426
+ return url2.searchParams.get("code");
896427
+ } catch {
896428
+ return null;
896429
+ }
896430
+ }
896431
+ function resolveManualLoginConfig2(config6) {
896432
+ return config6.manualRedirectUri ? { ...config6, redirectUri: config6.manualRedirectUri } : config6;
896433
+ }
896434
+ function describeSubscriptionPrecedence(record2) {
896435
+ return record2.overrideAmbientApiKeys ? "Subscription routing now overrides ambient API keys for this provider." : "Subscription session is stored for subscription-backed flows; ambient API keys are unchanged.";
896436
+ }
896040
896437
  // src/input/agent-workspace-token.ts
896041
896438
  function handleAgentWorkspaceToken(workspace, token, handleEscape2, requestRender) {
896042
896439
  if (!workspace.active)
@@ -896405,6 +896802,51 @@ class AgentWorkspace {
896405
896802
  this.lastActionResult = { kind: "error", title: "Onboarding completion failed", detail, safety: "safe" };
896406
896803
  }
896407
896804
  }
896805
+ openModelPickerAction(action2, requestRender) {
896806
+ const target = action2.modelPickerTarget ?? "main";
896807
+ const opened2 = action2.modelPickerFlow === "model" ? this.context?.openModelPickerWithTarget?.(target) : this.context?.openProviderModelPickerWithTarget?.(target);
896808
+ if (!opened2) {
896809
+ this.status = "Model picker is unavailable.";
896810
+ this.lastActionResult = {
896811
+ kind: "error",
896812
+ title: "Model picker unavailable",
896813
+ detail: "This runtime cannot open the model picker from Agent workspace.",
896814
+ safety: action2.safety
896815
+ };
896816
+ requestRender?.();
896817
+ return;
896818
+ }
896819
+ this.status = `Opening ${action2.label}.`;
896820
+ this.lastActionResult = {
896821
+ kind: "dispatched",
896822
+ title: `Opening ${action2.label}`,
896823
+ detail: "Opened the shared provider/model picker for this setup target.",
896824
+ safety: action2.safety
896825
+ };
896826
+ requestRender?.();
896827
+ }
896828
+ openSettingsModalAction(action2, requestRender) {
896829
+ if (!this.context?.openSettingsModal) {
896830
+ this.status = "Settings are unavailable.";
896831
+ this.lastActionResult = {
896832
+ kind: "error",
896833
+ title: "Settings unavailable",
896834
+ detail: "This runtime cannot open settings from Agent workspace.",
896835
+ safety: action2.safety
896836
+ };
896837
+ requestRender?.();
896838
+ return;
896839
+ }
896840
+ this.context.openSettingsModal(action2.settingsTarget);
896841
+ this.status = `Opening ${action2.label}.`;
896842
+ this.lastActionResult = {
896843
+ kind: "dispatched",
896844
+ title: `Opening ${action2.label}`,
896845
+ detail: "Opened the shared settings surface for this setup area.",
896846
+ safety: action2.safety
896847
+ };
896848
+ requestRender?.();
896849
+ }
896408
896850
  applySettingAction(action2, requestRender) {
896409
896851
  const effect = buildAgentWorkspaceSettingActionEffect(this.context, action2);
896410
896852
  if (effect.kind === "result") {
@@ -896515,6 +896957,19 @@ class AgentWorkspace {
896515
896957
  this.status = `${missing.label} is required.`;
896516
896958
  return;
896517
896959
  }
896960
+ if (editor.kind === "subscription-login-start") {
896961
+ submitAgentWorkspaceSubscriptionLoginStartEditor(this, editor, this.context, (id) => this.editorField(id)).finally(() => requestRender?.());
896962
+ return;
896963
+ }
896964
+ if (editor.kind === "subscription-login-finish") {
896965
+ submitAgentWorkspaceSubscriptionLoginFinishEditor(this, editor, this.context, (id) => this.editorField(id)).finally(() => requestRender?.());
896966
+ return;
896967
+ }
896968
+ if (editor.kind === "subscription-logout") {
896969
+ submitAgentWorkspaceSubscriptionLogoutEditor(this, editor, this.context, (id) => this.editorField(id));
896970
+ requestRender?.();
896971
+ return;
896972
+ }
896518
896973
  if (isAgentWorkspaceCommandEditorKind(editor.kind)) {
896519
896974
  this.submitCommandEditor(editor);
896520
896975
  requestRender?.();
@@ -896565,138 +897020,13 @@ class AgentWorkspace {
896565
897020
  return;
896566
897021
  }
896567
897022
  try {
896568
- if (editor.mode === "delete") {
896569
- this.submitLocalDeleteEditor(shellPaths3, editor);
896570
- return;
896571
- }
896572
- if (editor.kind === "learned-behavior") {
896573
- const created = createAgentWorkspaceLearnedBehavior(shellPaths3, {
896574
- target: this.learnedBehaviorTarget(),
896575
- name: this.editorField("name"),
896576
- description: this.editorField("description"),
896577
- notes: this.editorField("notes"),
896578
- tags: splitList5(this.editorField("tags")),
896579
- triggers: splitList5(this.editorField("triggers")),
896580
- enable: isAffirmative15(this.editorField("enable"))
896581
- });
896582
- this.finishLocalEditor(created.kind, created.id, created.name, "Created");
896583
- } else if (editor.kind === "profile") {
896584
- const template = this.editorField("template");
896585
- const templateId = template && template.toLowerCase() !== "none" ? template : undefined;
896586
- const profile5 = createAgentRuntimeProfile(shellPaths3.homeDirectory, this.editorField("name"), {
896587
- ...templateId ? { templateId } : {}
896588
- });
896589
- this.finishProfileEditor(profile5);
896590
- } else if (editor.kind === "note") {
896591
- const registry5 = AgentNoteRegistry.fromShellPaths(shellPaths3);
896592
- if (editor.mode === "update" && editor.recordId) {
896593
- const updated = registry5.update(editor.recordId, {
896594
- title: this.editorField("title"),
896595
- body: this.editorField("body"),
896596
- sourceUrl: this.editorField("sourceUrl"),
896597
- tags: splitList5(this.editorField("tags")),
896598
- provenance: "Workspace"
896599
- });
896600
- this.finishLocalEditor(editor.kind, updated.id, updated.title, "Updated");
896601
- return;
896602
- }
896603
- const created = registry5.create({
896604
- title: this.editorField("title"),
896605
- body: this.editorField("body"),
896606
- sourceUrl: this.editorField("sourceUrl"),
896607
- tags: splitList5(this.editorField("tags")),
896608
- source: "user",
896609
- provenance: "Workspace"
896610
- });
896611
- this.finishLocalEditor(editor.kind, created.id, created.title, "Created");
896612
- } else if (editor.kind === "persona") {
896613
- const registry5 = AgentPersonaRegistry.fromShellPaths(shellPaths3);
896614
- if (editor.mode === "update" && editor.recordId) {
896615
- const wasActive = registry5.snapshot().activePersonaId === editor.recordId;
896616
- const updated = registry5.update(editor.recordId, {
896617
- name: this.editorField("name"),
896618
- description: this.editorField("description"),
896619
- body: this.editorField("body"),
896620
- tags: splitList5(this.editorField("tags")),
896621
- triggers: splitList5(this.editorField("triggers")),
896622
- provenance: "Workspace"
896623
- });
896624
- if (isAffirmative15(this.editorField("activate")))
896625
- registry5.setActive(updated.id);
896626
- else if (wasActive)
896627
- registry5.clearActive();
896628
- this.finishLocalEditor(editor.kind, updated.id, updated.name, "Updated");
896629
- return;
896630
- }
896631
- const created = registry5.create({
896632
- name: this.editorField("name"),
896633
- description: this.editorField("description"),
896634
- body: this.editorField("body"),
896635
- tags: splitList5(this.editorField("tags")),
896636
- triggers: splitList5(this.editorField("triggers")),
896637
- source: "user",
896638
- provenance: "Workspace"
896639
- });
896640
- if (isAffirmative15(this.editorField("activate")))
896641
- registry5.setActive(created.id);
896642
- this.finishLocalEditor(editor.kind, created.id, created.name, "Created");
896643
- } else if (editor.kind === "skill") {
896644
- const registry5 = AgentSkillRegistry.fromShellPaths(shellPaths3);
896645
- if (editor.mode === "update" && editor.recordId) {
896646
- const updated = registry5.update(editor.recordId, {
896647
- name: this.editorField("name"),
896648
- description: this.editorField("description"),
896649
- procedure: this.editorField("procedure"),
896650
- triggers: splitList5(this.editorField("triggers")),
896651
- tags: splitList5(this.editorField("tags")),
896652
- requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
896653
- provenance: "Workspace"
896654
- });
896655
- registry5.setEnabled(updated.id, isAffirmative15(this.editorField("enabled")));
896656
- this.finishLocalEditor(editor.kind, updated.id, updated.name, "Updated");
896657
- return;
896658
- }
896659
- const created = registry5.create({
896660
- name: this.editorField("name"),
896661
- description: this.editorField("description"),
896662
- procedure: this.editorField("procedure"),
896663
- triggers: splitList5(this.editorField("triggers")),
896664
- tags: splitList5(this.editorField("tags")),
896665
- requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
896666
- enabled: isAffirmative15(this.editorField("enabled")),
896667
- source: "user",
896668
- provenance: "Workspace"
896669
- });
896670
- this.finishLocalEditor(editor.kind, created.id, created.name, "Created");
896671
- } else {
896672
- const registry5 = AgentRoutineRegistry.fromShellPaths(shellPaths3);
896673
- if (editor.mode === "update" && editor.recordId) {
896674
- const updated = registry5.update(editor.recordId, {
896675
- name: this.editorField("name"),
896676
- description: this.editorField("description"),
896677
- steps: this.editorField("steps"),
896678
- triggers: splitList5(this.editorField("triggers")),
896679
- tags: splitList5(this.editorField("tags")),
896680
- requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
896681
- provenance: "Workspace"
896682
- });
896683
- registry5.setEnabled(updated.id, isAffirmative15(this.editorField("enabled")));
896684
- this.finishLocalEditor(editor.kind, updated.id, updated.name, "Updated");
896685
- return;
896686
- }
896687
- const created = registry5.create({
896688
- name: this.editorField("name"),
896689
- description: this.editorField("description"),
896690
- steps: this.editorField("steps"),
896691
- triggers: splitList5(this.editorField("triggers")),
896692
- tags: splitList5(this.editorField("tags")),
896693
- requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
896694
- enabled: isAffirmative15(this.editorField("enabled")),
896695
- source: "user",
896696
- provenance: "Workspace"
896697
- });
896698
- this.finishLocalEditor(editor.kind, created.id, created.name, "Created");
896699
- }
897023
+ submitAgentWorkspaceLocalRegistryEditor(shellPaths3, editor, {
897024
+ readField: (id) => this.editorField(id),
897025
+ learnedBehaviorTarget: () => this.learnedBehaviorTarget(),
897026
+ submitDeleteEditor: () => this.submitLocalDeleteEditor(shellPaths3, editor),
897027
+ finishLocalEditor: (kind2, id, name51, verb) => this.finishLocalEditor(kind2, id, name51, verb),
897028
+ finishProfileEditor: (profile5) => this.finishProfileEditor(profile5)
897029
+ });
896700
897030
  } catch (error53) {
896701
897031
  const detail = error53 instanceof Error ? error53.message : String(error53);
896702
897032
  this.localEditor = { ...editor, message: detail };
@@ -898540,6 +898870,17 @@ function handleModalTokenRoutes(state4, token) {
898540
898870
  }, token)) {
898541
898871
  return withState(state4, true);
898542
898872
  }
898873
+ if (handleModelPickerToken({
898874
+ modelPicker: state4.modelPicker,
898875
+ modalStack: state4.modalStack,
898876
+ commandContext: state4.commandContext,
898877
+ getViewportHeight: state4.getViewportHeight,
898878
+ requestRender: state4.requestRender,
898879
+ handleEscape: state4.handleEscape,
898880
+ onModelPickerCommit: state4.onModelPickerCommit
898881
+ }, token)) {
898882
+ return withState(state4, true);
898883
+ }
898543
898884
  if (handleSettingsModalToken({
898544
898885
  settingsModal: state4.settingsModal,
898545
898886
  commandContext: state4.commandContext,
@@ -898592,17 +898933,6 @@ function handleModalTokenRoutes(state4, token) {
898592
898933
  if (handleHistorySearchToken(historyState, token)) {
898593
898934
  return withState(state4, true, historyState);
898594
898935
  }
898595
- if (handleModelPickerToken({
898596
- modelPicker: state4.modelPicker,
898597
- modalStack: state4.modalStack,
898598
- commandContext: state4.commandContext,
898599
- getViewportHeight: state4.getViewportHeight,
898600
- requestRender: state4.requestRender,
898601
- handleEscape: state4.handleEscape,
898602
- onModelPickerCommit: state4.onModelPickerCommit
898603
- }, token)) {
898604
- return withState(state4, true);
898605
- }
898606
898936
  if (handleLiveTailToken({
898607
898937
  liveTailModal: state4.liveTailModal,
898608
898938
  processModal: state4.processModal,
@@ -899541,7 +899871,8 @@ class InputHandler {
899541
899871
  handleCtrlCForHandler(this);
899542
899872
  }
899543
899873
  modalOpened(name51) {
899544
- if (name51 !== "agentWorkspace" && this.agentWorkspace.active) {
899874
+ const keepAgentWorkspaceUnderlay = name51 === "modelPicker" || name51 === "settings";
899875
+ if (name51 !== "agentWorkspace" && !keepAgentWorkspaceUnderlay && this.agentWorkspace.active) {
899545
899876
  this.closeAgentWorkspaceModal();
899546
899877
  }
899547
899878
  modalOpenedForHandler(this, name51);
@@ -899904,232 +900235,6 @@ class PermissionPromptUI {
899904
900235
  }
899905
900236
  }
899906
900237
 
899907
- // src/renderer/layout-engine.ts
899908
- function clamp4(value, min2, max2) {
899909
- return Math.max(min2, Math.min(max2, value));
899910
- }
899911
- function createShellLayout(request2) {
899912
- const width = Math.max(1, request2.width);
899913
- const height = Math.max(1, request2.height);
899914
- const headerHeight = clamp4(request2.headerHeight, 0, height);
899915
- const footerHeight = clamp4(request2.footerHeight, 0, Math.max(0, height - headerHeight));
899916
- const bodyHeight = Math.max(0, height - headerHeight - footerHeight);
899917
- const hasPanel = typeof request2.panelWidth === "number" && request2.panelWidth > 0;
899918
- const safePanelWidth = hasPanel ? clamp4(request2.panelWidth, 1, Math.max(1, width - 2)) : 0;
899919
- const separatorWidth = hasPanel ? 1 : 0;
899920
- const conversationWidth = hasPanel ? Math.max(1, width - safePanelWidth - separatorWidth) : width;
899921
- return {
899922
- screen: { x: 0, y: 0, width, height },
899923
- header: { x: 0, y: 0, width, height: headerHeight },
899924
- body: { x: 0, y: headerHeight, width, height: bodyHeight },
899925
- footer: { x: 0, y: headerHeight + bodyHeight, width, height: footerHeight },
899926
- conversation: { x: 0, y: headerHeight, width: conversationWidth, height: bodyHeight },
899927
- panel: hasPanel ? {
899928
- x: conversationWidth + separatorWidth,
899929
- y: headerHeight,
899930
- width: safePanelWidth,
899931
- height: bodyHeight
899932
- } : undefined,
899933
- separatorX: hasPanel ? conversationWidth : undefined
899934
- };
899935
- }
899936
- function createSplitPaneLayout(totalRows, ratio, options = {}) {
899937
- const topTabRows = options.topTabRows ?? 1;
899938
- const bottomTabRows = options.bottomTabRows ?? 1;
899939
- const separatorRows = options.separatorRows ?? 1;
899940
- const chromeRows = topTabRows + bottomTabRows + separatorRows;
899941
- const contentRows = Math.max(0, totalRows - chromeRows);
899942
- const normalizedRatio = clamp4(ratio, 0.2, 0.8);
899943
- const topContentRows = contentRows <= 1 ? contentRows : Math.max(1, Math.floor(contentRows * normalizedRatio));
899944
- const bottomContentRows = contentRows <= 1 ? 0 : Math.max(1, contentRows - topContentRows);
899945
- return {
899946
- totalRows,
899947
- topTabRows,
899948
- bottomTabRows,
899949
- separatorRows,
899950
- topContentRows,
899951
- bottomContentRows
899952
- };
899953
- }
899954
-
899955
- // src/renderer/process-indicator.ts
899956
- function truncateToWidth2(text, maxWidth) {
899957
- let width = 0;
899958
- let i5 = 0;
899959
- for (const char of text) {
899960
- const cw = getDisplayWidth(char);
899961
- if (width + cw > maxWidth)
899962
- break;
899963
- width += cw;
899964
- i5 += char.length;
899965
- }
899966
- return text.slice(0, i5);
899967
- }
899968
- function renderProcessIndicator(width, agentCount, toolCount, focused = false, agentProgress) {
899969
- const total = agentCount + toolCount;
899970
- const delegationLabel = (count) => `${count} delegation${count !== 1 ? "s" : ""}`;
899971
- const renderPlainStatus = (text, style) => [UIFactory.stringToLine(` ${text}`, width, style)];
899972
- const renderFocusedStatus = (text) => {
899973
- const bg = "#31506f";
899974
- const fg = "#eefaff";
899975
- const markerFg = "#7dd3fc";
899976
- const line2 = UIFactory.stringToLine(" ".repeat(width), width, { fg: "238" });
899977
- const prefix = `${GLYPHS.navigation.selected} `;
899978
- const body2 = truncateToWidth2(text, Math.max(0, width - 8));
899979
- const highlighted = ` ${prefix}${body2} `;
899980
- const startX = 2;
899981
- for (let i5 = 0;i5 < highlighted.length && startX + i5 < width - 2; i5++) {
899982
- const ch = highlighted[i5];
899983
- const isMarker = i5 < prefix.length + 1;
899984
- line2[startX + i5].char = ch;
899985
- line2[startX + i5].fg = isMarker ? markerFg : fg;
899986
- line2[startX + i5].bg = bg;
899987
- line2[startX + i5].bold = true;
899988
- line2[startX + i5].dim = false;
899989
- }
899990
- return [line2];
899991
- };
899992
- if (focused) {
899993
- const parts3 = [];
899994
- if (agentCount > 0)
899995
- parts3.push(delegationLabel(agentCount));
899996
- if (toolCount > 0)
899997
- parts3.push(`${toolCount} tool${toolCount !== 1 ? "s" : ""} running`);
899998
- const label2 = total === 0 ? `No runtime activity ${GLYPHS.status.pending} back to input` : `${parts3.join(` ${GLYPHS.navigation.pipeSeparator} `)} ${GLYPHS.status.pending} Enter to open ${GLYPHS.status.pending} back to input`;
899999
- return renderFocusedStatus(label2);
900000
- }
900001
- if (total === 0) {
900002
- return renderPlainStatus("No runtime activity", { fg: "238", dim: true });
900003
- }
900004
- const parts2 = [];
900005
- if (agentCount > 0) {
900006
- parts2.push(delegationLabel(agentCount));
900007
- }
900008
- if (toolCount > 0) {
900009
- parts2.push(`${toolCount} tool${toolCount !== 1 ? "s" : ""} running`);
900010
- }
900011
- const PROGRESS_RESERVED_CHARS = 43;
900012
- const progressMaxLen = Math.max(0, width - PROGRESS_RESERVED_CHARS);
900013
- const progressSuffix = agentProgress && progressMaxLen > 10 ? ` | ${agentProgress.length > progressMaxLen ? agentProgress.slice(0, Math.max(0, progressMaxLen - 3)) + "..." : agentProgress}` : "";
900014
- const label = `${parts2.join(` ${GLYPHS.navigation.pipeSeparator} `)}${progressSuffix}`;
900015
- const hint = ` ${GLYPHS.status.pending} Enter to view`;
900016
- return renderPlainStatus(`${label}${hint}`, { fg: "#00ffff", bold: true });
900017
- }
900018
-
900019
- // src/renderer/shell-surface.ts
900020
- var FOOTER_BASE_ROWS = 9;
900021
- var CONTEXT_PROGRESS_ROWS = 2;
900022
- var PROCESS_INDICATOR_ROWS = 1;
900023
- function estimateShellFooterHeight(promptLineCount, contextWindow) {
900024
- const safePromptLines = Math.max(1, promptLineCount);
900025
- const progressRows = contextWindow && contextWindow > 0 ? CONTEXT_PROGRESS_ROWS : 0;
900026
- return FOOTER_BASE_ROWS + safePromptLines + progressRows + PROCESS_INDICATOR_ROWS;
900027
- }
900028
- function buildShellFooter(options) {
900029
- const lines = UIFactory.createFooter(options.width, options.promptText, options.usage, options.showExitNotice, options.lastCopyTime, options.model, options.toolCount, options.promptCursorPos, options.workingDir, options.provider, options.contextWindow, options.compactThreshold, options.dangerMode, options.lastInputTokens, options.commandArgsHint, options.hitlMode, options.promptFocused ?? !options.indicatorFocused, options.composerMode, options.composerStatus, options.composerFlags, options.composerPendingRisk);
900030
- const processIndicator = renderProcessIndicator(options.width, options.runningAgentCount, options.runningProcessCount, options.indicatorFocused, options.runningAgentProgress);
900031
- const inputBoxRows = Math.max(1, options.promptLineCount) + 2;
900032
- lines.splice(inputBoxRows, 0, ...processIndicator);
900033
- return { lines, height: lines.length };
900034
- }
900035
-
900036
- // src/renderer/conversation-layout.ts
900037
- function buildConversationViewport(request2) {
900038
- const overlayRows = request2.overlayRows ?? 0;
900039
- const effectiveHeight = Math.max(0, request2.viewportHeight - overlayRows);
900040
- const lineCount = request2.conversation.history.getLineCount();
900041
- const maxScroll = Math.max(0, lineCount - effectiveHeight);
900042
- const nextScrollTop = request2.scrollLocked ? maxScroll : Math.max(0, Math.min(request2.scrollTop, maxScroll));
900043
- const viewport = request2.conversation.history.getSnapshot(nextScrollTop, effectiveHeight, request2.width);
900044
- return {
900045
- effectiveHeight,
900046
- maxScroll,
900047
- nextScrollTop,
900048
- viewport
900049
- };
900050
- }
900051
- function overlayViewportBottom(viewport, overlay, width, viewportHeight, bottomInset = 0) {
900052
- if (overlay.length === 0)
900053
- return [...viewport];
900054
- const next = [...viewport];
900055
- const targetStart = Math.max(0, viewportHeight - bottomInset - overlay.length);
900056
- next.length = Math.min(next.length, targetStart);
900057
- while (next.length < targetStart)
900058
- next.push(createEmptyLine(width));
900059
- next.push(...overlay);
900060
- return next;
900061
- }
900062
- function replaceViewportWithOverlay(overlay, width, viewportHeight) {
900063
- const next = [];
900064
- const pad = Math.max(0, viewportHeight - overlay.length);
900065
- for (let i5 = 0;i5 < pad; i5++)
900066
- next.push(createEmptyLine(width));
900067
- next.push(...overlay);
900068
- return next;
900069
- }
900070
-
900071
- // src/renderer/file-picker-overlay.ts
900072
- var FILE_PICKER_TITLE = "Select File";
900073
- var FILE_PICKER_SEARCH_PREFIX = "@ ";
900074
- var FILE_PICKER_EMPTY_MESSAGE = "No matching files";
900075
- var FILE_PICKER_HINTS = "[Up/Down] Navigate [/] Search [Enter] Select [Esc] Cancel";
900076
- function renderFilePickerOverlay(picker, width, viewportHeight = 24) {
900077
- const lines = [];
900078
- const metrics = getOverlaySurfaceMetrics(width, viewportHeight, {
900079
- chromeRows: 4,
900080
- maxWidth: 70,
900081
- minContentRows: 6,
900082
- maxContentRows: 10
900083
- });
900084
- const layout = createOverlayBoxLayout(width, metrics.margin, metrics.boxWidth);
900085
- const contentW = layout.innerWidth;
900086
- const borderFg = DEFAULT_OVERLAY_PALETTE.borderFg;
900087
- const titleFg = DEFAULT_OVERLAY_PALETTE.titleFg;
900088
- const bodyFg = DEFAULT_OVERLAY_PALETTE.bodyFg;
900089
- const mutedFg = DEFAULT_OVERLAY_PALETTE.mutedFg;
900090
- const selectedBg = DEFAULT_OVERLAY_PALETTE.selectedBg;
900091
- const titleLine = createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.topLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.topRight, borderFg, DEFAULT_OVERLAY_PALETTE.titleBg);
900092
- putOverlayText(titleLine, layout.margin + 2, layout.width - 4, FILE_PICKER_TITLE, { fg: titleFg, bold: true });
900093
- lines.push(titleLine);
900094
- const queryDisplay = picker.query || "";
900095
- const searchLine = createOverlayContentLine(width, layout, borderFg, DEFAULT_OVERLAY_PALETTE.inputBg);
900096
- const searchPrefix = FILE_PICKER_SEARCH_PREFIX;
900097
- const queryText = fitDisplay(`${queryDisplay}${picker.searchFocused ? OVERLAY_GLYPHS.cursor : ""}`, Math.max(0, contentW - getDisplayWidth(searchPrefix)));
900098
- putOverlayText(searchLine, layout.margin + 2, getDisplayWidth(searchPrefix), searchPrefix, { fg: picker.searchFocused ? bodyFg : mutedFg });
900099
- putOverlayText(searchLine, layout.margin + 2 + getDisplayWidth(searchPrefix), contentW - getDisplayWidth(searchPrefix), queryText, { fg: picker.query.length > 0 || picker.searchFocused ? bodyFg : mutedFg });
900100
- lines.push(searchLine);
900101
- lines.push(createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.teeLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.teeRight, borderFg, DEFAULT_OVERLAY_PALETTE.sectionBg));
900102
- if (picker.results.length === 0) {
900103
- const noResults = createOverlayContentLine(width, layout, borderFg, DEFAULT_OVERLAY_PALETTE.bodyBg);
900104
- putOverlayText(noResults, layout.margin + 2, contentW, fitDisplay(FILE_PICKER_EMPTY_MESSAGE, contentW), { fg: "244", dim: true });
900105
- lines.push(noResults);
900106
- } else {
900107
- const maxVisible = metrics.contentRows;
900108
- let startIdx = 0;
900109
- if (picker.results.length > maxVisible) {
900110
- startIdx = Math.max(0, Math.min(picker.selectedIndex - Math.floor(maxVisible / 2), picker.results.length - maxVisible));
900111
- }
900112
- const endIdx = Math.min(startIdx + maxVisible, picker.results.length);
900113
- for (let i5 = startIdx;i5 < endIdx; i5++) {
900114
- const file2 = picker.results[i5];
900115
- const isSelected = i5 === picker.selectedIndex;
900116
- const indicator = isSelected ? `${OVERLAY_GLYPHS.selected} ` : " ";
900117
- const displayFile = getDisplayWidth(file2) > contentW - 2 ? truncateDisplay(file2, contentW - 2) : file2;
900118
- const line2 = createOverlayContentLine(width, layout, borderFg, isSelected ? selectedBg : DEFAULT_OVERLAY_PALETTE.bodyBg);
900119
- putOverlayText(line2, layout.margin + 2, contentW, fitDisplay(indicator + fitDisplay(displayFile, contentW - 2), contentW), {
900120
- fg: isSelected ? titleFg : file2.endsWith("/") ? titleFg : bodyFg,
900121
- bg: isSelected ? selectedBg : DEFAULT_OVERLAY_PALETTE.bodyBg,
900122
- bold: isSelected
900123
- });
900124
- lines.push(line2);
900125
- }
900126
- }
900127
- const bottomLine = createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.bottomLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.bottomRight, borderFg, DEFAULT_OVERLAY_PALETTE.sectionBg);
900128
- putOverlayText(bottomLine, layout.margin + 2, layout.width - 4, truncateDisplay(FILE_PICKER_HINTS, layout.width - 4), { fg: mutedFg, dim: true });
900129
- lines.push(bottomLine);
900130
- return lines;
900131
- }
900132
-
900133
900238
  // src/renderer/model-workspace.ts
900134
900239
  var PALETTE = {
900135
900240
  border: "#64748b",
@@ -900175,7 +900280,7 @@ var MODEL_WORKSPACE_CONTEXT_CAP_INPUT_HELP = "Type digits to set a cap. Enter co
900175
900280
  var MODEL_WORKSPACE_FOOTER_SEARCH_ACTIVE = "Typing filters search; Esc clears search";
900176
900281
  var MODEL_WORKSPACE_FOOTER_SEARCH_INACTIVE = "/ search";
900177
900282
  var MODEL_WORKSPACE_FOOTER_CONTROLS = "Up/Down navigate \u2022 Left/Right pane \u2022 Enter select \u2022 <search> \u2022 Tab price \u2022 C caps \u2022 A available \u2022 B benchmark \u2022 G group \u2022 Esc close";
900178
- function clamp5(value, min2, max2) {
900283
+ function clamp4(value, min2, max2) {
900179
900284
  return Math.max(min2, Math.min(max2, value));
900180
900285
  }
900181
900286
  function fillRange2(line2, startX, endX, bg) {
@@ -900264,10 +900369,10 @@ function padDisplay2(text, width) {
900264
900369
  function stableWindow2(total, selected, visible) {
900265
900370
  if (total <= 0 || visible <= 0)
900266
900371
  return { start: 0, end: 0 };
900267
- const clamped = clamp5(selected, 0, total - 1);
900372
+ const clamped = clamp4(selected, 0, total - 1);
900268
900373
  const half = Math.floor(visible / 2);
900269
900374
  const maxStart = Math.max(0, total - visible);
900270
- const start2 = clamp5(clamped - half, 0, maxStart);
900375
+ const start2 = clamp4(clamped - half, 0, maxStart);
900271
900376
  return { start: start2, end: Math.min(total, start2 + visible) };
900272
900377
  }
900273
900378
  function formatContext(value) {
@@ -900405,11 +900510,11 @@ function renderProviderRows(picker, lines, rows, startX, width) {
900405
900510
  function renderModelRows(picker, lines, rows, startX, width) {
900406
900511
  const models = picker.getFilteredModels();
900407
900512
  const { start: start2, end } = stableWindow2(models.length, picker.selectedIndex, rows);
900408
- const providerW = clamp5(Math.floor(width * 0.14), 10, 18);
900513
+ const providerW = clamp4(Math.floor(width * 0.14), 10, 18);
900409
900514
  const ctxW = 8;
900410
900515
  const tierW = 8;
900411
900516
  const capsW = 14;
900412
- const nameW = clamp5(Math.floor(width * 0.28), 16, 36);
900517
+ const nameW = clamp4(Math.floor(width * 0.28), 16, 36);
900413
900518
  const keyW = Math.max(10, width - providerW - ctxW - tierW - capsW - nameW - 10);
900414
900519
  for (let visibleRow = 0;visibleRow < rows; visibleRow += 1) {
900415
900520
  const absolute = start2 + visibleRow;
@@ -900489,11 +900594,11 @@ function writeTableHeader(line2, picker, startX, width) {
900489
900594
  writeText3(line2, startX + 1, width - 2, MODEL_WORKSPACE_TABLE_HEADERS.contextCap, style);
900490
900595
  return;
900491
900596
  }
900492
- const providerW = clamp5(Math.floor(width * 0.14), 10, 18);
900597
+ const providerW = clamp4(Math.floor(width * 0.14), 10, 18);
900493
900598
  const ctxW = 8;
900494
900599
  const tierW = 8;
900495
900600
  const capsW = 14;
900496
- const nameW = clamp5(Math.floor(width * 0.28), 16, 36);
900601
+ const nameW = clamp4(Math.floor(width * 0.28), 16, 36);
900497
900602
  const keyW = Math.max(10, width - providerW - ctxW - tierW - capsW - nameW - 10);
900498
900603
  let x2 = startX + 3;
900499
900604
  writeText3(line2, x2, keyW, padDisplay2(MODEL_WORKSPACE_TABLE_HEADERS.modelKey, keyW), style);
@@ -900516,7 +900621,7 @@ function renderModelWorkspace(picker, width, viewportHeight) {
900516
900621
  const safeWidth = Math.max(20, width);
900517
900622
  const safeHeight = Math.max(12, viewportHeight);
900518
900623
  const lines = [];
900519
- const targetW = clamp5(Math.round(safeWidth * 0.18), 24, 34);
900624
+ const targetW = clamp4(Math.round(safeWidth * 0.18), 24, 34);
900520
900625
  const contentX = targetW + 1;
900521
900626
  const contentW = Math.max(1, safeWidth - contentX - 1);
900522
900627
  const top = borderLine2(safeWidth, GLYPHS.frame.topLeft, GLYPHS.frame.horizontal, GLYPHS.frame.topRight);
@@ -900536,7 +900641,7 @@ function renderModelWorkspace(picker, width, viewportHeight) {
900536
900641
  const bodyRows = safeHeight - 3 - footerRows;
900537
900642
  const maxDetailRows = Math.max(3, bodyRows - 2);
900538
900643
  const minDetailRows = Math.min(6, maxDetailRows);
900539
- const detailRows = clamp5(Math.round(bodyRows * 0.32), minDetailRows, maxDetailRows);
900644
+ const detailRows = clamp4(Math.round(bodyRows * 0.32), minDetailRows, maxDetailRows);
900540
900645
  const listRows = Math.max(1, bodyRows - detailRows - 1);
900541
900646
  const details = detailLines(picker, contentW - 2).slice(0, detailRows);
900542
900647
  for (let row = 0;row < bodyRows; row += 1) {
@@ -900644,292 +900749,6 @@ function keyForTargets(values2) {
900644
900749
  ].join("\x1D")).join("\x1F");
900645
900750
  }
900646
900751
 
900647
- // src/renderer/selection-modal-overlay.ts
900648
- var BORDER_FG = DEFAULT_OVERLAY_PALETTE.borderFg;
900649
- var TITLE_FG = DEFAULT_OVERLAY_PALETTE.titleFg;
900650
- var BODY_FG = DEFAULT_OVERLAY_PALETTE.bodyFg;
900651
- var MUTED_FG = DEFAULT_OVERLAY_PALETTE.mutedFg;
900652
- var CATEGORY_FG = "#4488cc";
900653
- var SELECTED_BG = DEFAULT_OVERLAY_PALETTE.selectedBg;
900654
- var SELECTION_MODAL_SEARCH_LABEL = " Search";
900655
- var SELECTION_MODAL_RESULTS_LABEL = " Results";
900656
- var SELECTION_MODAL_NO_MATCHING_ITEMS = "No matching items";
900657
- var SELECTION_MODAL_NO_ITEMS = "No items";
900658
- var SELECTION_MODAL_NAVIGATION_HINT = "[Up/Down] Navigate";
900659
- var SELECTION_MODAL_CLOSE_HINT = "[Esc] Close";
900660
- var SELECTION_MODAL_SEARCH_HINT = "[/] Search";
900661
- var SELECTION_MODAL_SPACE_TOGGLE_HINT = "[Space] Toggle";
900662
- function putText(line2, startX, maxWidth, text, style) {
900663
- putOverlayText(line2, startX, maxWidth, text, style);
900664
- }
900665
- function primaryVerbForAction(primaryAction) {
900666
- return primaryAction === "toggle" ? "[Enter] Toggle" : primaryAction === "edit" ? "[Enter] Edit" : primaryAction === "delete" ? "[Enter] Delete" : "[Enter] Select";
900667
- }
900668
- function renderSelectionModalOverlay(modal, width, viewportHeight = 24) {
900669
- const lines = [];
900670
- const metrics = getOverlaySurfaceMetrics(width, viewportHeight, {
900671
- margin: 4,
900672
- maxWidth: 72,
900673
- chromeRows: modal.allowSearch ? 5 : 4,
900674
- minContentRows: 6,
900675
- maxContentRows: 10
900676
- });
900677
- const layout = createOverlayBoxLayout(width, metrics.margin, metrics.boxWidth);
900678
- lines.push(createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.topLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.topRight, BORDER_FG, DEFAULT_OVERLAY_PALETTE.titleBg));
900679
- const titleLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.titleBg);
900680
- putText(titleLine, layout.margin + 2, layout.innerWidth, fitDisplay(truncateDisplay(modal.title, layout.innerWidth), layout.innerWidth), { fg: TITLE_FG, bold: true });
900681
- lines.push(titleLine);
900682
- if (modal.allowSearch) {
900683
- const labelLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
900684
- putText(labelLine, layout.margin + 2, layout.innerWidth, fitDisplay(SELECTION_MODAL_SEARCH_LABEL, layout.innerWidth), {
900685
- fg: CATEGORY_FG,
900686
- dim: true
900687
- });
900688
- lines.push(labelLine);
900689
- const searchLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.inputBg);
900690
- const prefix = "/ ";
900691
- const queryAreaWidth = layout.innerWidth - getDisplayWidth(prefix);
900692
- const queryValue = modal.query + (modal.searchFocused ? OVERLAY_GLYPHS.cursor : "");
900693
- const queryText = fitDisplay(truncateDisplay(queryValue, queryAreaWidth), queryAreaWidth);
900694
- putText(searchLine, layout.margin + 2, getDisplayWidth(prefix), prefix, { fg: modal.searchFocused ? BODY_FG : MUTED_FG });
900695
- putText(searchLine, layout.margin + 2 + getDisplayWidth(prefix), queryAreaWidth, queryText, {
900696
- fg: modal.query.length > 0 || modal.searchFocused ? BODY_FG : MUTED_FG
900697
- });
900698
- lines.push(searchLine);
900699
- lines.push(createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.teeLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.teeRight, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg));
900700
- } else {
900701
- lines.push(createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg));
900702
- }
900703
- const listTitle = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
900704
- putText(listTitle, layout.margin + 2, layout.innerWidth, fitDisplay(SELECTION_MODAL_RESULTS_LABEL, layout.innerWidth), {
900705
- fg: CATEGORY_FG,
900706
- dim: true
900707
- });
900708
- lines.push(listTitle);
900709
- const items = modal.filteredItems;
900710
- if (items.length === 0) {
900711
- const line2 = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.bodyBg);
900712
- const message = modal.query ? SELECTION_MODAL_NO_MATCHING_ITEMS : SELECTION_MODAL_NO_ITEMS;
900713
- putText(line2, layout.margin + 2, layout.innerWidth, fitDisplay(message, layout.innerWidth), { fg: MUTED_FG, dim: true });
900714
- lines.push(line2);
900715
- } else {
900716
- const maxVisible = metrics.contentRows;
900717
- let startIdx = 0;
900718
- if (items.length > maxVisible) {
900719
- startIdx = Math.max(0, Math.min(modal.selectedIndex - Math.floor(maxVisible / 2), items.length - maxVisible));
900720
- }
900721
- const endIdx = Math.min(startIdx + maxVisible, items.length);
900722
- let lastCategory;
900723
- for (let i5 = startIdx;i5 < endIdx; i5++) {
900724
- const item = items[i5];
900725
- const isSelected = i5 === modal.selectedIndex;
900726
- if (item.category && item.category !== lastCategory) {
900727
- lastCategory = item.category;
900728
- const categoryLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
900729
- putText(categoryLine, layout.margin + 2, layout.innerWidth, fitDisplay(` ${item.category}`, layout.innerWidth), {
900730
- fg: CATEGORY_FG,
900731
- dim: true
900732
- });
900733
- lines.push(categoryLine);
900734
- }
900735
- const indicator = isSelected ? `${OVERLAY_GLYPHS.selected} ` : " ";
900736
- const indicatorWidth = 2;
900737
- const remaining = layout.innerWidth - indicatorWidth;
900738
- const labelColor = isSelected ? TITLE_FG : item.fg ?? BODY_FG;
900739
- const detailColor = isSelected ? BODY_FG : MUTED_FG;
900740
- const labelWidth = item.detail ? fitLabelDetailColumns(item.label, item.detail, remaining).labelWidth : remaining;
900741
- const labelLine = createOverlayContentLine(width, layout, BORDER_FG, isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg);
900742
- putText(labelLine, layout.margin + 2, indicatorWidth, indicator, {
900743
- fg: isSelected ? TITLE_FG : MUTED_FG,
900744
- bg: isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg,
900745
- bold: isSelected
900746
- });
900747
- putText(labelLine, layout.margin + 2 + indicatorWidth, labelWidth, fitDisplay(truncateDisplay(item.label, labelWidth), labelWidth), {
900748
- fg: labelColor,
900749
- bg: isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg,
900750
- bold: isSelected
900751
- });
900752
- if (item.detail) {
900753
- const detailWidth = fitLabelDetailColumns(item.label, item.detail, remaining).detailWidth;
900754
- if (detailWidth >= 12) {
900755
- putText(labelLine, layout.margin + 2 + indicatorWidth + labelWidth, 2, " ", {
900756
- fg: BODY_FG,
900757
- bg: isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg
900758
- });
900759
- putText(labelLine, layout.margin + 2 + indicatorWidth + labelWidth + 2, detailWidth, fitDisplay(truncateDisplay(item.detail, detailWidth), detailWidth), {
900760
- fg: detailColor,
900761
- bg: isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg
900762
- });
900763
- lines.push(labelLine);
900764
- } else {
900765
- lines.push(labelLine);
900766
- const wrappedDetails = wrapWithHangingIndent(item.detail, Math.max(8, remaining), "", 2);
900767
- for (const detailLineText of wrappedDetails) {
900768
- const detailLine = createOverlayContentLine(width, layout, BORDER_FG, isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg);
900769
- putText(detailLine, layout.margin + 2 + indicatorWidth, remaining, fitDisplay(truncateDisplay(detailLineText, remaining), remaining), {
900770
- fg: detailColor,
900771
- bg: isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg,
900772
- dim: !isSelected
900773
- });
900774
- lines.push(detailLine);
900775
- }
900776
- }
900777
- } else {
900778
- lines.push(labelLine);
900779
- }
900780
- }
900781
- if (items.length > maxVisible) {
900782
- const above = startIdx;
900783
- const below = items.length - endIdx;
900784
- const scrollHint = above > 0 && below > 0 ? `(${above} above, ${below} below)` : below > 0 ? `(${below} below)` : `(${above} above)`;
900785
- const hintLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
900786
- putText(hintLine, layout.margin + 2, layout.innerWidth, fitDisplay(scrollHint, layout.innerWidth), { fg: MUTED_FG, dim: true });
900787
- lines.push(hintLine);
900788
- }
900789
- }
900790
- const footerLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
900791
- const selectedItem = modal.getSelected();
900792
- const primaryVerb = primaryVerbForAction(selectedItem?.primaryAction);
900793
- let hints = `${SELECTION_MODAL_NAVIGATION_HINT} ${primaryVerb} ${SELECTION_MODAL_CLOSE_HINT}`;
900794
- if (modal.allowSearch)
900795
- hints += ` ${SELECTION_MODAL_SEARCH_HINT}`;
900796
- if (selectedItem?.primaryAction === "toggle" && !selectedItem.actions)
900797
- hints += ` ${SELECTION_MODAL_SPACE_TOGGLE_HINT}`;
900798
- if (selectedItem?.actions)
900799
- hints += ` ${selectedItem.actions}`;
900800
- putText(footerLine, layout.margin + 2, layout.innerWidth, fitDisplay(truncateDisplay(hints, layout.innerWidth), layout.innerWidth), { fg: MUTED_FG, dim: true });
900801
- lines.push(footerLine);
900802
- lines.push(createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.bottomLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.bottomRight, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg));
900803
- return lines;
900804
- }
900805
-
900806
- // src/renderer/bottom-bar.ts
900807
- function createBottomBarLine(width, style) {
900808
- const line2 = createEmptyLine(width);
900809
- for (let col = 0;col < width; col++) {
900810
- line2[col] = createStyledCell(" ", {
900811
- fg: style.fg,
900812
- bg: style.bg,
900813
- bold: style.bold ?? false,
900814
- dim: style.dim ?? false,
900815
- underline: style.underline ?? false
900816
- });
900817
- }
900818
- return line2;
900819
- }
900820
- function writeBottomBarText(line2, startX, maxWidth, text, style) {
900821
- let x2 = startX;
900822
- let used = 0;
900823
- for (const ch of text) {
900824
- const cellWidth = getDisplayWidth(ch);
900825
- if (cellWidth <= 0)
900826
- continue;
900827
- if (used + cellWidth > maxWidth || x2 >= line2.length)
900828
- break;
900829
- line2[x2] = createStyledCell(ch, {
900830
- fg: style.fg,
900831
- bg: style.bg,
900832
- bold: style.bold ?? false,
900833
- dim: style.dim ?? false,
900834
- underline: style.underline ?? false
900835
- });
900836
- if (cellWidth > 1 && x2 + 1 < line2.length) {
900837
- line2[x2 + 1] = createStyledCell(" ", {
900838
- fg: style.fg,
900839
- bg: style.bg,
900840
- bold: style.bold ?? false,
900841
- dim: style.dim ?? false,
900842
- underline: style.underline ?? false
900843
- });
900844
- }
900845
- x2 += cellWidth;
900846
- used += cellWidth;
900847
- }
900848
- }
900849
-
900850
- // src/renderer/search-overlay.ts
900851
- var SEARCH_OVERLAY_LABEL = " Find: ";
900852
- var SEARCH_OVERLAY_NO_MATCHES = "No matches";
900853
- var SEARCH_OVERLAY_COUNT_SUFFIX = "up/down";
900854
- var SEARCH_OVERLAY_LOCKED_HINTS = " [Up/Down] or [jk] navigate [Bksp] edit [Esc] close";
900855
- var SEARCH_OVERLAY_UNLOCKED_HINTS = " [Enter/Tab] lock [Esc] close";
900856
- function searchOverlayMatchCount(current, total) {
900857
- return `${current}/${total} ${SEARCH_OVERLAY_COUNT_SUFFIX}`;
900858
- }
900859
- function renderSearchOverlay(manager5, width) {
900860
- const matchCount = manager5.matches?.length > 0 ? searchOverlayMatchCount(manager5.currentMatch + 1, manager5.matches.length) : manager5.query.length > 0 ? SEARCH_OVERLAY_NO_MATCHES : "";
900861
- const locked = manager5.locked;
900862
- const cursor = locked ? "" : "\u2588";
900863
- const queryDisplay = manager5.query + cursor;
900864
- const hints = locked ? SEARCH_OVERLAY_LOCKED_HINTS : SEARCH_OVERLAY_UNLOCKED_HINTS;
900865
- const label = SEARCH_OVERLAY_LABEL;
900866
- const matchStr = matchCount ? ` ${matchCount}` : "";
900867
- const leftPart = label + queryDisplay;
900868
- const hintsW = getDisplayWidth(hints);
900869
- const matchStrW = getDisplayWidth(matchStr);
900870
- const leftWidth = width - hintsW - matchStrW - 2;
900871
- const truncatedLeft = fitDisplay(getDisplayWidth(leftPart) > leftWidth ? truncateDisplay(leftPart, leftWidth) : leftPart, leftWidth);
900872
- const fullLine = truncatedLeft + matchStr + hints + " ";
900873
- const line2 = createBottomBarLine(width, { fg: "#000000", bg: "#00ffcc" });
900874
- writeBottomBarText(line2, 0, width, fitDisplay(truncateDisplay(fullLine, width), width), { fg: "#000000", bg: "#00ffcc" });
900875
- if (matchStr.length > 0) {
900876
- const matchStart = getDisplayWidth(truncatedLeft);
900877
- writeBottomBarText(line2, matchStart, matchStrW, matchStr, { fg: "#888888", bg: "#00ffcc", dim: true });
900878
- }
900879
- return [line2];
900880
- }
900881
-
900882
- // src/renderer/history-search-overlay.ts
900883
- var HISTORY_SEARCH_PREFIX = "(reverse-i-search)`";
900884
- var HISTORY_SEARCH_FAILED_PREFIX = "(failed reverse-i-search)`";
900885
- var HISTORY_SEARCH_QUERY_SUFFIX = "': ";
900886
- function historySearchLabel(prefix, query2) {
900887
- return prefix + query2 + HISTORY_SEARCH_QUERY_SUFFIX;
900888
- }
900889
- function truncateToWidth3(text, maxWidth) {
900890
- let usedWidth = 0;
900891
- let result2 = "";
900892
- let i5 = 0;
900893
- while (i5 < text.length) {
900894
- const code2 = text.codePointAt(i5);
900895
- const charLen = code2 > 65535 ? 2 : 1;
900896
- const charWidth = getDisplayWidth(text.slice(i5, i5 + charLen));
900897
- if (usedWidth + charWidth > maxWidth)
900898
- break;
900899
- result2 += text.slice(i5, i5 + charLen);
900900
- usedWidth += charWidth;
900901
- i5 += charLen;
900902
- }
900903
- return result2 + " ".repeat(maxWidth - usedWidth);
900904
- }
900905
- function renderHistorySearchOverlay(historySearch, width) {
900906
- if (width <= 0)
900907
- return [];
900908
- const match = historySearch.currentMatch;
900909
- const hasMatch = match !== null && historySearch.query.length > 0;
900910
- const noMatch = historySearch.query.length > 0 && !hasMatch;
900911
- const prefix = noMatch ? HISTORY_SEARCH_FAILED_PREFIX : HISTORY_SEARCH_PREFIX;
900912
- const matchText = hasMatch ? match?.entry ?? "" : "";
900913
- const label = historySearchLabel(prefix, historySearch.query);
900914
- const full = truncateToWidth3(label + matchText, width);
900915
- const line2 = createBottomBarLine(width, { fg: "#000000", bg: "#00ffcc" });
900916
- writeBottomBarText(line2, 0, width, full, { fg: "#000000", bg: "#00ffcc" });
900917
- if (hasMatch && match) {
900918
- const labelW = getDisplayWidth(label);
900919
- const matchStartCol = labelW + match.matchStart;
900920
- const matchEndCol = matchStartCol + match.matchLength;
900921
- const highlightWidth = Math.max(0, matchEndCol - matchStartCol);
900922
- const matchedSlice = truncateToWidth3(match.entry.slice(match.matchStart, match.matchStart + match.matchLength), highlightWidth);
900923
- writeBottomBarText(line2, matchStartCol, highlightWidth, matchedSlice, {
900924
- fg: "#000000",
900925
- bg: "#00ffcc",
900926
- bold: true,
900927
- underline: true
900928
- });
900929
- }
900930
- return [line2];
900931
- }
900932
-
900933
900752
  // src/renderer/settings-modal-helpers.ts
900934
900753
  function maskSecretValue(value) {
900935
900754
  if (value.length === 0)
@@ -901604,6 +901423,518 @@ function renderSettingsModal(modal, width, viewportHeight = 24) {
901604
901423
  });
901605
901424
  }
901606
901425
 
901426
+ // src/renderer/layout-engine.ts
901427
+ function clamp5(value, min2, max2) {
901428
+ return Math.max(min2, Math.min(max2, value));
901429
+ }
901430
+ function createShellLayout(request2) {
901431
+ const width = Math.max(1, request2.width);
901432
+ const height = Math.max(1, request2.height);
901433
+ const headerHeight = clamp5(request2.headerHeight, 0, height);
901434
+ const footerHeight = clamp5(request2.footerHeight, 0, Math.max(0, height - headerHeight));
901435
+ const bodyHeight = Math.max(0, height - headerHeight - footerHeight);
901436
+ const hasPanel = typeof request2.panelWidth === "number" && request2.panelWidth > 0;
901437
+ const safePanelWidth = hasPanel ? clamp5(request2.panelWidth, 1, Math.max(1, width - 2)) : 0;
901438
+ const separatorWidth = hasPanel ? 1 : 0;
901439
+ const conversationWidth = hasPanel ? Math.max(1, width - safePanelWidth - separatorWidth) : width;
901440
+ return {
901441
+ screen: { x: 0, y: 0, width, height },
901442
+ header: { x: 0, y: 0, width, height: headerHeight },
901443
+ body: { x: 0, y: headerHeight, width, height: bodyHeight },
901444
+ footer: { x: 0, y: headerHeight + bodyHeight, width, height: footerHeight },
901445
+ conversation: { x: 0, y: headerHeight, width: conversationWidth, height: bodyHeight },
901446
+ panel: hasPanel ? {
901447
+ x: conversationWidth + separatorWidth,
901448
+ y: headerHeight,
901449
+ width: safePanelWidth,
901450
+ height: bodyHeight
901451
+ } : undefined,
901452
+ separatorX: hasPanel ? conversationWidth : undefined
901453
+ };
901454
+ }
901455
+ function createSplitPaneLayout(totalRows, ratio, options = {}) {
901456
+ const topTabRows = options.topTabRows ?? 1;
901457
+ const bottomTabRows = options.bottomTabRows ?? 1;
901458
+ const separatorRows = options.separatorRows ?? 1;
901459
+ const chromeRows = topTabRows + bottomTabRows + separatorRows;
901460
+ const contentRows = Math.max(0, totalRows - chromeRows);
901461
+ const normalizedRatio = clamp5(ratio, 0.2, 0.8);
901462
+ const topContentRows = contentRows <= 1 ? contentRows : Math.max(1, Math.floor(contentRows * normalizedRatio));
901463
+ const bottomContentRows = contentRows <= 1 ? 0 : Math.max(1, contentRows - topContentRows);
901464
+ return {
901465
+ totalRows,
901466
+ topTabRows,
901467
+ bottomTabRows,
901468
+ separatorRows,
901469
+ topContentRows,
901470
+ bottomContentRows
901471
+ };
901472
+ }
901473
+
901474
+ // src/renderer/process-indicator.ts
901475
+ function truncateToWidth2(text, maxWidth) {
901476
+ let width = 0;
901477
+ let i5 = 0;
901478
+ for (const char of text) {
901479
+ const cw = getDisplayWidth(char);
901480
+ if (width + cw > maxWidth)
901481
+ break;
901482
+ width += cw;
901483
+ i5 += char.length;
901484
+ }
901485
+ return text.slice(0, i5);
901486
+ }
901487
+ function renderProcessIndicator(width, agentCount, toolCount, focused = false, agentProgress) {
901488
+ const total = agentCount + toolCount;
901489
+ const delegationLabel = (count) => `${count} delegation${count !== 1 ? "s" : ""}`;
901490
+ const renderPlainStatus = (text, style) => [UIFactory.stringToLine(` ${text}`, width, style)];
901491
+ const renderFocusedStatus = (text) => {
901492
+ const bg = "#31506f";
901493
+ const fg = "#eefaff";
901494
+ const markerFg = "#7dd3fc";
901495
+ const line2 = UIFactory.stringToLine(" ".repeat(width), width, { fg: "238" });
901496
+ const prefix = `${GLYPHS.navigation.selected} `;
901497
+ const body2 = truncateToWidth2(text, Math.max(0, width - 8));
901498
+ const highlighted = ` ${prefix}${body2} `;
901499
+ const startX = 2;
901500
+ for (let i5 = 0;i5 < highlighted.length && startX + i5 < width - 2; i5++) {
901501
+ const ch = highlighted[i5];
901502
+ const isMarker = i5 < prefix.length + 1;
901503
+ line2[startX + i5].char = ch;
901504
+ line2[startX + i5].fg = isMarker ? markerFg : fg;
901505
+ line2[startX + i5].bg = bg;
901506
+ line2[startX + i5].bold = true;
901507
+ line2[startX + i5].dim = false;
901508
+ }
901509
+ return [line2];
901510
+ };
901511
+ if (focused) {
901512
+ const parts3 = [];
901513
+ if (agentCount > 0)
901514
+ parts3.push(delegationLabel(agentCount));
901515
+ if (toolCount > 0)
901516
+ parts3.push(`${toolCount} tool${toolCount !== 1 ? "s" : ""} running`);
901517
+ const label2 = total === 0 ? `No runtime activity ${GLYPHS.status.pending} back to input` : `${parts3.join(` ${GLYPHS.navigation.pipeSeparator} `)} ${GLYPHS.status.pending} Enter to open ${GLYPHS.status.pending} back to input`;
901518
+ return renderFocusedStatus(label2);
901519
+ }
901520
+ if (total === 0) {
901521
+ return renderPlainStatus("No runtime activity", { fg: "238", dim: true });
901522
+ }
901523
+ const parts2 = [];
901524
+ if (agentCount > 0) {
901525
+ parts2.push(delegationLabel(agentCount));
901526
+ }
901527
+ if (toolCount > 0) {
901528
+ parts2.push(`${toolCount} tool${toolCount !== 1 ? "s" : ""} running`);
901529
+ }
901530
+ const PROGRESS_RESERVED_CHARS = 43;
901531
+ const progressMaxLen = Math.max(0, width - PROGRESS_RESERVED_CHARS);
901532
+ const progressSuffix = agentProgress && progressMaxLen > 10 ? ` | ${agentProgress.length > progressMaxLen ? agentProgress.slice(0, Math.max(0, progressMaxLen - 3)) + "..." : agentProgress}` : "";
901533
+ const label = `${parts2.join(` ${GLYPHS.navigation.pipeSeparator} `)}${progressSuffix}`;
901534
+ const hint = ` ${GLYPHS.status.pending} Enter to view`;
901535
+ return renderPlainStatus(`${label}${hint}`, { fg: "#00ffff", bold: true });
901536
+ }
901537
+
901538
+ // src/renderer/shell-surface.ts
901539
+ var FOOTER_BASE_ROWS = 9;
901540
+ var CONTEXT_PROGRESS_ROWS = 2;
901541
+ var PROCESS_INDICATOR_ROWS = 1;
901542
+ function estimateShellFooterHeight(promptLineCount, contextWindow) {
901543
+ const safePromptLines = Math.max(1, promptLineCount);
901544
+ const progressRows = contextWindow && contextWindow > 0 ? CONTEXT_PROGRESS_ROWS : 0;
901545
+ return FOOTER_BASE_ROWS + safePromptLines + progressRows + PROCESS_INDICATOR_ROWS;
901546
+ }
901547
+ function buildShellFooter(options) {
901548
+ const lines = UIFactory.createFooter(options.width, options.promptText, options.usage, options.showExitNotice, options.lastCopyTime, options.model, options.toolCount, options.promptCursorPos, options.workingDir, options.provider, options.contextWindow, options.compactThreshold, options.dangerMode, options.lastInputTokens, options.commandArgsHint, options.hitlMode, options.promptFocused ?? !options.indicatorFocused, options.composerMode, options.composerStatus, options.composerFlags, options.composerPendingRisk);
901549
+ const processIndicator = renderProcessIndicator(options.width, options.runningAgentCount, options.runningProcessCount, options.indicatorFocused, options.runningAgentProgress);
901550
+ const inputBoxRows = Math.max(1, options.promptLineCount) + 2;
901551
+ lines.splice(inputBoxRows, 0, ...processIndicator);
901552
+ return { lines, height: lines.length };
901553
+ }
901554
+
901555
+ // src/renderer/conversation-layout.ts
901556
+ function buildConversationViewport(request2) {
901557
+ const overlayRows = request2.overlayRows ?? 0;
901558
+ const effectiveHeight = Math.max(0, request2.viewportHeight - overlayRows);
901559
+ const lineCount = request2.conversation.history.getLineCount();
901560
+ const maxScroll = Math.max(0, lineCount - effectiveHeight);
901561
+ const nextScrollTop = request2.scrollLocked ? maxScroll : Math.max(0, Math.min(request2.scrollTop, maxScroll));
901562
+ const viewport = request2.conversation.history.getSnapshot(nextScrollTop, effectiveHeight, request2.width);
901563
+ return {
901564
+ effectiveHeight,
901565
+ maxScroll,
901566
+ nextScrollTop,
901567
+ viewport
901568
+ };
901569
+ }
901570
+ function overlayViewportBottom(viewport, overlay, width, viewportHeight, bottomInset = 0) {
901571
+ if (overlay.length === 0)
901572
+ return [...viewport];
901573
+ const next = [...viewport];
901574
+ const targetStart = Math.max(0, viewportHeight - bottomInset - overlay.length);
901575
+ next.length = Math.min(next.length, targetStart);
901576
+ while (next.length < targetStart)
901577
+ next.push(createEmptyLine(width));
901578
+ next.push(...overlay);
901579
+ return next;
901580
+ }
901581
+ function replaceViewportWithOverlay(overlay, width, viewportHeight) {
901582
+ const next = [];
901583
+ const pad = Math.max(0, viewportHeight - overlay.length);
901584
+ for (let i5 = 0;i5 < pad; i5++)
901585
+ next.push(createEmptyLine(width));
901586
+ next.push(...overlay);
901587
+ return next;
901588
+ }
901589
+
901590
+ // src/renderer/file-picker-overlay.ts
901591
+ var FILE_PICKER_TITLE = "Select File";
901592
+ var FILE_PICKER_SEARCH_PREFIX = "@ ";
901593
+ var FILE_PICKER_EMPTY_MESSAGE = "No matching files";
901594
+ var FILE_PICKER_HINTS = "[Up/Down] Navigate [/] Search [Enter] Select [Esc] Cancel";
901595
+ function renderFilePickerOverlay(picker, width, viewportHeight = 24) {
901596
+ const lines = [];
901597
+ const metrics = getOverlaySurfaceMetrics(width, viewportHeight, {
901598
+ chromeRows: 4,
901599
+ maxWidth: 70,
901600
+ minContentRows: 6,
901601
+ maxContentRows: 10
901602
+ });
901603
+ const layout = createOverlayBoxLayout(width, metrics.margin, metrics.boxWidth);
901604
+ const contentW = layout.innerWidth;
901605
+ const borderFg = DEFAULT_OVERLAY_PALETTE.borderFg;
901606
+ const titleFg = DEFAULT_OVERLAY_PALETTE.titleFg;
901607
+ const bodyFg = DEFAULT_OVERLAY_PALETTE.bodyFg;
901608
+ const mutedFg = DEFAULT_OVERLAY_PALETTE.mutedFg;
901609
+ const selectedBg = DEFAULT_OVERLAY_PALETTE.selectedBg;
901610
+ const titleLine = createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.topLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.topRight, borderFg, DEFAULT_OVERLAY_PALETTE.titleBg);
901611
+ putOverlayText(titleLine, layout.margin + 2, layout.width - 4, FILE_PICKER_TITLE, { fg: titleFg, bold: true });
901612
+ lines.push(titleLine);
901613
+ const queryDisplay = picker.query || "";
901614
+ const searchLine = createOverlayContentLine(width, layout, borderFg, DEFAULT_OVERLAY_PALETTE.inputBg);
901615
+ const searchPrefix = FILE_PICKER_SEARCH_PREFIX;
901616
+ const queryText = fitDisplay(`${queryDisplay}${picker.searchFocused ? OVERLAY_GLYPHS.cursor : ""}`, Math.max(0, contentW - getDisplayWidth(searchPrefix)));
901617
+ putOverlayText(searchLine, layout.margin + 2, getDisplayWidth(searchPrefix), searchPrefix, { fg: picker.searchFocused ? bodyFg : mutedFg });
901618
+ putOverlayText(searchLine, layout.margin + 2 + getDisplayWidth(searchPrefix), contentW - getDisplayWidth(searchPrefix), queryText, { fg: picker.query.length > 0 || picker.searchFocused ? bodyFg : mutedFg });
901619
+ lines.push(searchLine);
901620
+ lines.push(createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.teeLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.teeRight, borderFg, DEFAULT_OVERLAY_PALETTE.sectionBg));
901621
+ if (picker.results.length === 0) {
901622
+ const noResults = createOverlayContentLine(width, layout, borderFg, DEFAULT_OVERLAY_PALETTE.bodyBg);
901623
+ putOverlayText(noResults, layout.margin + 2, contentW, fitDisplay(FILE_PICKER_EMPTY_MESSAGE, contentW), { fg: "244", dim: true });
901624
+ lines.push(noResults);
901625
+ } else {
901626
+ const maxVisible = metrics.contentRows;
901627
+ let startIdx = 0;
901628
+ if (picker.results.length > maxVisible) {
901629
+ startIdx = Math.max(0, Math.min(picker.selectedIndex - Math.floor(maxVisible / 2), picker.results.length - maxVisible));
901630
+ }
901631
+ const endIdx = Math.min(startIdx + maxVisible, picker.results.length);
901632
+ for (let i5 = startIdx;i5 < endIdx; i5++) {
901633
+ const file2 = picker.results[i5];
901634
+ const isSelected = i5 === picker.selectedIndex;
901635
+ const indicator = isSelected ? `${OVERLAY_GLYPHS.selected} ` : " ";
901636
+ const displayFile = getDisplayWidth(file2) > contentW - 2 ? truncateDisplay(file2, contentW - 2) : file2;
901637
+ const line2 = createOverlayContentLine(width, layout, borderFg, isSelected ? selectedBg : DEFAULT_OVERLAY_PALETTE.bodyBg);
901638
+ putOverlayText(line2, layout.margin + 2, contentW, fitDisplay(indicator + fitDisplay(displayFile, contentW - 2), contentW), {
901639
+ fg: isSelected ? titleFg : file2.endsWith("/") ? titleFg : bodyFg,
901640
+ bg: isSelected ? selectedBg : DEFAULT_OVERLAY_PALETTE.bodyBg,
901641
+ bold: isSelected
901642
+ });
901643
+ lines.push(line2);
901644
+ }
901645
+ }
901646
+ const bottomLine = createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.bottomLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.bottomRight, borderFg, DEFAULT_OVERLAY_PALETTE.sectionBg);
901647
+ putOverlayText(bottomLine, layout.margin + 2, layout.width - 4, truncateDisplay(FILE_PICKER_HINTS, layout.width - 4), { fg: mutedFg, dim: true });
901648
+ lines.push(bottomLine);
901649
+ return lines;
901650
+ }
901651
+
901652
+ // src/renderer/selection-modal-overlay.ts
901653
+ var BORDER_FG = DEFAULT_OVERLAY_PALETTE.borderFg;
901654
+ var TITLE_FG = DEFAULT_OVERLAY_PALETTE.titleFg;
901655
+ var BODY_FG = DEFAULT_OVERLAY_PALETTE.bodyFg;
901656
+ var MUTED_FG = DEFAULT_OVERLAY_PALETTE.mutedFg;
901657
+ var CATEGORY_FG = "#4488cc";
901658
+ var SELECTED_BG = DEFAULT_OVERLAY_PALETTE.selectedBg;
901659
+ var SELECTION_MODAL_SEARCH_LABEL = " Search";
901660
+ var SELECTION_MODAL_RESULTS_LABEL = " Results";
901661
+ var SELECTION_MODAL_NO_MATCHING_ITEMS = "No matching items";
901662
+ var SELECTION_MODAL_NO_ITEMS = "No items";
901663
+ var SELECTION_MODAL_NAVIGATION_HINT = "[Up/Down] Navigate";
901664
+ var SELECTION_MODAL_CLOSE_HINT = "[Esc] Close";
901665
+ var SELECTION_MODAL_SEARCH_HINT = "[/] Search";
901666
+ var SELECTION_MODAL_SPACE_TOGGLE_HINT = "[Space] Toggle";
901667
+ function putText(line2, startX, maxWidth, text, style) {
901668
+ putOverlayText(line2, startX, maxWidth, text, style);
901669
+ }
901670
+ function primaryVerbForAction(primaryAction) {
901671
+ return primaryAction === "toggle" ? "[Enter] Toggle" : primaryAction === "edit" ? "[Enter] Edit" : primaryAction === "delete" ? "[Enter] Delete" : "[Enter] Select";
901672
+ }
901673
+ function renderSelectionModalOverlay(modal, width, viewportHeight = 24) {
901674
+ const lines = [];
901675
+ const metrics = getOverlaySurfaceMetrics(width, viewportHeight, {
901676
+ margin: 4,
901677
+ maxWidth: 72,
901678
+ chromeRows: modal.allowSearch ? 5 : 4,
901679
+ minContentRows: 6,
901680
+ maxContentRows: 10
901681
+ });
901682
+ const layout = createOverlayBoxLayout(width, metrics.margin, metrics.boxWidth);
901683
+ lines.push(createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.topLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.topRight, BORDER_FG, DEFAULT_OVERLAY_PALETTE.titleBg));
901684
+ const titleLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.titleBg);
901685
+ putText(titleLine, layout.margin + 2, layout.innerWidth, fitDisplay(truncateDisplay(modal.title, layout.innerWidth), layout.innerWidth), { fg: TITLE_FG, bold: true });
901686
+ lines.push(titleLine);
901687
+ if (modal.allowSearch) {
901688
+ const labelLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
901689
+ putText(labelLine, layout.margin + 2, layout.innerWidth, fitDisplay(SELECTION_MODAL_SEARCH_LABEL, layout.innerWidth), {
901690
+ fg: CATEGORY_FG,
901691
+ dim: true
901692
+ });
901693
+ lines.push(labelLine);
901694
+ const searchLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.inputBg);
901695
+ const prefix = "/ ";
901696
+ const queryAreaWidth = layout.innerWidth - getDisplayWidth(prefix);
901697
+ const queryValue = modal.query + (modal.searchFocused ? OVERLAY_GLYPHS.cursor : "");
901698
+ const queryText = fitDisplay(truncateDisplay(queryValue, queryAreaWidth), queryAreaWidth);
901699
+ putText(searchLine, layout.margin + 2, getDisplayWidth(prefix), prefix, { fg: modal.searchFocused ? BODY_FG : MUTED_FG });
901700
+ putText(searchLine, layout.margin + 2 + getDisplayWidth(prefix), queryAreaWidth, queryText, {
901701
+ fg: modal.query.length > 0 || modal.searchFocused ? BODY_FG : MUTED_FG
901702
+ });
901703
+ lines.push(searchLine);
901704
+ lines.push(createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.teeLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.teeRight, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg));
901705
+ } else {
901706
+ lines.push(createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg));
901707
+ }
901708
+ const listTitle = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
901709
+ putText(listTitle, layout.margin + 2, layout.innerWidth, fitDisplay(SELECTION_MODAL_RESULTS_LABEL, layout.innerWidth), {
901710
+ fg: CATEGORY_FG,
901711
+ dim: true
901712
+ });
901713
+ lines.push(listTitle);
901714
+ const items = modal.filteredItems;
901715
+ if (items.length === 0) {
901716
+ const line2 = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.bodyBg);
901717
+ const message = modal.query ? SELECTION_MODAL_NO_MATCHING_ITEMS : SELECTION_MODAL_NO_ITEMS;
901718
+ putText(line2, layout.margin + 2, layout.innerWidth, fitDisplay(message, layout.innerWidth), { fg: MUTED_FG, dim: true });
901719
+ lines.push(line2);
901720
+ } else {
901721
+ const maxVisible = metrics.contentRows;
901722
+ let startIdx = 0;
901723
+ if (items.length > maxVisible) {
901724
+ startIdx = Math.max(0, Math.min(modal.selectedIndex - Math.floor(maxVisible / 2), items.length - maxVisible));
901725
+ }
901726
+ const endIdx = Math.min(startIdx + maxVisible, items.length);
901727
+ let lastCategory;
901728
+ for (let i5 = startIdx;i5 < endIdx; i5++) {
901729
+ const item = items[i5];
901730
+ const isSelected = i5 === modal.selectedIndex;
901731
+ if (item.category && item.category !== lastCategory) {
901732
+ lastCategory = item.category;
901733
+ const categoryLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
901734
+ putText(categoryLine, layout.margin + 2, layout.innerWidth, fitDisplay(` ${item.category}`, layout.innerWidth), {
901735
+ fg: CATEGORY_FG,
901736
+ dim: true
901737
+ });
901738
+ lines.push(categoryLine);
901739
+ }
901740
+ const indicator = isSelected ? `${OVERLAY_GLYPHS.selected} ` : " ";
901741
+ const indicatorWidth = 2;
901742
+ const remaining = layout.innerWidth - indicatorWidth;
901743
+ const labelColor = isSelected ? TITLE_FG : item.fg ?? BODY_FG;
901744
+ const detailColor = isSelected ? BODY_FG : MUTED_FG;
901745
+ const labelWidth = item.detail ? fitLabelDetailColumns(item.label, item.detail, remaining).labelWidth : remaining;
901746
+ const labelLine = createOverlayContentLine(width, layout, BORDER_FG, isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg);
901747
+ putText(labelLine, layout.margin + 2, indicatorWidth, indicator, {
901748
+ fg: isSelected ? TITLE_FG : MUTED_FG,
901749
+ bg: isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg,
901750
+ bold: isSelected
901751
+ });
901752
+ putText(labelLine, layout.margin + 2 + indicatorWidth, labelWidth, fitDisplay(truncateDisplay(item.label, labelWidth), labelWidth), {
901753
+ fg: labelColor,
901754
+ bg: isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg,
901755
+ bold: isSelected
901756
+ });
901757
+ if (item.detail) {
901758
+ const detailWidth = fitLabelDetailColumns(item.label, item.detail, remaining).detailWidth;
901759
+ if (detailWidth >= 12) {
901760
+ putText(labelLine, layout.margin + 2 + indicatorWidth + labelWidth, 2, " ", {
901761
+ fg: BODY_FG,
901762
+ bg: isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg
901763
+ });
901764
+ putText(labelLine, layout.margin + 2 + indicatorWidth + labelWidth + 2, detailWidth, fitDisplay(truncateDisplay(item.detail, detailWidth), detailWidth), {
901765
+ fg: detailColor,
901766
+ bg: isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg
901767
+ });
901768
+ lines.push(labelLine);
901769
+ } else {
901770
+ lines.push(labelLine);
901771
+ const wrappedDetails = wrapWithHangingIndent(item.detail, Math.max(8, remaining), "", 2);
901772
+ for (const detailLineText of wrappedDetails) {
901773
+ const detailLine = createOverlayContentLine(width, layout, BORDER_FG, isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg);
901774
+ putText(detailLine, layout.margin + 2 + indicatorWidth, remaining, fitDisplay(truncateDisplay(detailLineText, remaining), remaining), {
901775
+ fg: detailColor,
901776
+ bg: isSelected ? SELECTED_BG : DEFAULT_OVERLAY_PALETTE.bodyBg,
901777
+ dim: !isSelected
901778
+ });
901779
+ lines.push(detailLine);
901780
+ }
901781
+ }
901782
+ } else {
901783
+ lines.push(labelLine);
901784
+ }
901785
+ }
901786
+ if (items.length > maxVisible) {
901787
+ const above = startIdx;
901788
+ const below = items.length - endIdx;
901789
+ const scrollHint = above > 0 && below > 0 ? `(${above} above, ${below} below)` : below > 0 ? `(${below} below)` : `(${above} above)`;
901790
+ const hintLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
901791
+ putText(hintLine, layout.margin + 2, layout.innerWidth, fitDisplay(scrollHint, layout.innerWidth), { fg: MUTED_FG, dim: true });
901792
+ lines.push(hintLine);
901793
+ }
901794
+ }
901795
+ const footerLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
901796
+ const selectedItem = modal.getSelected();
901797
+ const primaryVerb = primaryVerbForAction(selectedItem?.primaryAction);
901798
+ let hints = `${SELECTION_MODAL_NAVIGATION_HINT} ${primaryVerb} ${SELECTION_MODAL_CLOSE_HINT}`;
901799
+ if (modal.allowSearch)
901800
+ hints += ` ${SELECTION_MODAL_SEARCH_HINT}`;
901801
+ if (selectedItem?.primaryAction === "toggle" && !selectedItem.actions)
901802
+ hints += ` ${SELECTION_MODAL_SPACE_TOGGLE_HINT}`;
901803
+ if (selectedItem?.actions)
901804
+ hints += ` ${selectedItem.actions}`;
901805
+ putText(footerLine, layout.margin + 2, layout.innerWidth, fitDisplay(truncateDisplay(hints, layout.innerWidth), layout.innerWidth), { fg: MUTED_FG, dim: true });
901806
+ lines.push(footerLine);
901807
+ lines.push(createOverlayFilledBorderLine(width, layout, OVERLAY_GLYPHS.bottomLeft, OVERLAY_GLYPHS.horizontal, OVERLAY_GLYPHS.bottomRight, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg));
901808
+ return lines;
901809
+ }
901810
+
901811
+ // src/renderer/bottom-bar.ts
901812
+ function createBottomBarLine(width, style) {
901813
+ const line2 = createEmptyLine(width);
901814
+ for (let col = 0;col < width; col++) {
901815
+ line2[col] = createStyledCell(" ", {
901816
+ fg: style.fg,
901817
+ bg: style.bg,
901818
+ bold: style.bold ?? false,
901819
+ dim: style.dim ?? false,
901820
+ underline: style.underline ?? false
901821
+ });
901822
+ }
901823
+ return line2;
901824
+ }
901825
+ function writeBottomBarText(line2, startX, maxWidth, text, style) {
901826
+ let x2 = startX;
901827
+ let used = 0;
901828
+ for (const ch of text) {
901829
+ const cellWidth = getDisplayWidth(ch);
901830
+ if (cellWidth <= 0)
901831
+ continue;
901832
+ if (used + cellWidth > maxWidth || x2 >= line2.length)
901833
+ break;
901834
+ line2[x2] = createStyledCell(ch, {
901835
+ fg: style.fg,
901836
+ bg: style.bg,
901837
+ bold: style.bold ?? false,
901838
+ dim: style.dim ?? false,
901839
+ underline: style.underline ?? false
901840
+ });
901841
+ if (cellWidth > 1 && x2 + 1 < line2.length) {
901842
+ line2[x2 + 1] = createStyledCell(" ", {
901843
+ fg: style.fg,
901844
+ bg: style.bg,
901845
+ bold: style.bold ?? false,
901846
+ dim: style.dim ?? false,
901847
+ underline: style.underline ?? false
901848
+ });
901849
+ }
901850
+ x2 += cellWidth;
901851
+ used += cellWidth;
901852
+ }
901853
+ }
901854
+
901855
+ // src/renderer/search-overlay.ts
901856
+ var SEARCH_OVERLAY_LABEL = " Find: ";
901857
+ var SEARCH_OVERLAY_NO_MATCHES = "No matches";
901858
+ var SEARCH_OVERLAY_COUNT_SUFFIX = "up/down";
901859
+ var SEARCH_OVERLAY_LOCKED_HINTS = " [Up/Down] or [jk] navigate [Bksp] edit [Esc] close";
901860
+ var SEARCH_OVERLAY_UNLOCKED_HINTS = " [Enter/Tab] lock [Esc] close";
901861
+ function searchOverlayMatchCount(current, total) {
901862
+ return `${current}/${total} ${SEARCH_OVERLAY_COUNT_SUFFIX}`;
901863
+ }
901864
+ function renderSearchOverlay(manager5, width) {
901865
+ const matchCount = manager5.matches?.length > 0 ? searchOverlayMatchCount(manager5.currentMatch + 1, manager5.matches.length) : manager5.query.length > 0 ? SEARCH_OVERLAY_NO_MATCHES : "";
901866
+ const locked = manager5.locked;
901867
+ const cursor = locked ? "" : "\u2588";
901868
+ const queryDisplay = manager5.query + cursor;
901869
+ const hints = locked ? SEARCH_OVERLAY_LOCKED_HINTS : SEARCH_OVERLAY_UNLOCKED_HINTS;
901870
+ const label = SEARCH_OVERLAY_LABEL;
901871
+ const matchStr = matchCount ? ` ${matchCount}` : "";
901872
+ const leftPart = label + queryDisplay;
901873
+ const hintsW = getDisplayWidth(hints);
901874
+ const matchStrW = getDisplayWidth(matchStr);
901875
+ const leftWidth = width - hintsW - matchStrW - 2;
901876
+ const truncatedLeft = fitDisplay(getDisplayWidth(leftPart) > leftWidth ? truncateDisplay(leftPart, leftWidth) : leftPart, leftWidth);
901877
+ const fullLine = truncatedLeft + matchStr + hints + " ";
901878
+ const line2 = createBottomBarLine(width, { fg: "#000000", bg: "#00ffcc" });
901879
+ writeBottomBarText(line2, 0, width, fitDisplay(truncateDisplay(fullLine, width), width), { fg: "#000000", bg: "#00ffcc" });
901880
+ if (matchStr.length > 0) {
901881
+ const matchStart = getDisplayWidth(truncatedLeft);
901882
+ writeBottomBarText(line2, matchStart, matchStrW, matchStr, { fg: "#888888", bg: "#00ffcc", dim: true });
901883
+ }
901884
+ return [line2];
901885
+ }
901886
+
901887
+ // src/renderer/history-search-overlay.ts
901888
+ var HISTORY_SEARCH_PREFIX = "(reverse-i-search)`";
901889
+ var HISTORY_SEARCH_FAILED_PREFIX = "(failed reverse-i-search)`";
901890
+ var HISTORY_SEARCH_QUERY_SUFFIX = "': ";
901891
+ function historySearchLabel(prefix, query2) {
901892
+ return prefix + query2 + HISTORY_SEARCH_QUERY_SUFFIX;
901893
+ }
901894
+ function truncateToWidth3(text, maxWidth) {
901895
+ let usedWidth = 0;
901896
+ let result2 = "";
901897
+ let i5 = 0;
901898
+ while (i5 < text.length) {
901899
+ const code2 = text.codePointAt(i5);
901900
+ const charLen = code2 > 65535 ? 2 : 1;
901901
+ const charWidth = getDisplayWidth(text.slice(i5, i5 + charLen));
901902
+ if (usedWidth + charWidth > maxWidth)
901903
+ break;
901904
+ result2 += text.slice(i5, i5 + charLen);
901905
+ usedWidth += charWidth;
901906
+ i5 += charLen;
901907
+ }
901908
+ return result2 + " ".repeat(maxWidth - usedWidth);
901909
+ }
901910
+ function renderHistorySearchOverlay(historySearch, width) {
901911
+ if (width <= 0)
901912
+ return [];
901913
+ const match = historySearch.currentMatch;
901914
+ const hasMatch = match !== null && historySearch.query.length > 0;
901915
+ const noMatch = historySearch.query.length > 0 && !hasMatch;
901916
+ const prefix = noMatch ? HISTORY_SEARCH_FAILED_PREFIX : HISTORY_SEARCH_PREFIX;
901917
+ const matchText = hasMatch ? match?.entry ?? "" : "";
901918
+ const label = historySearchLabel(prefix, historySearch.query);
901919
+ const full = truncateToWidth3(label + matchText, width);
901920
+ const line2 = createBottomBarLine(width, { fg: "#000000", bg: "#00ffcc" });
901921
+ writeBottomBarText(line2, 0, width, full, { fg: "#000000", bg: "#00ffcc" });
901922
+ if (hasMatch && match) {
901923
+ const labelW = getDisplayWidth(label);
901924
+ const matchStartCol = labelW + match.matchStart;
901925
+ const matchEndCol = matchStartCol + match.matchLength;
901926
+ const highlightWidth = Math.max(0, matchEndCol - matchStartCol);
901927
+ const matchedSlice = truncateToWidth3(match.entry.slice(match.matchStart, match.matchStart + match.matchLength), highlightWidth);
901928
+ writeBottomBarText(line2, matchStartCol, highlightWidth, matchedSlice, {
901929
+ fg: "#000000",
901930
+ bg: "#00ffcc",
901931
+ bold: true,
901932
+ underline: true
901933
+ });
901934
+ }
901935
+ return [line2];
901936
+ }
901937
+
901607
901938
  // src/renderer/mcp-workspace.ts
901608
901939
  var MCP_WORKSPACE_TITLE = "MCP Workspace / Servers";
901609
901940
  var MCP_WORKSPACE_LEFT_HEADER = "Servers";
@@ -902813,17 +903144,23 @@ function buildLeftRows2(workspace, height) {
902813
903144
  }
902814
903145
  function actionCommand(action2) {
902815
903146
  if (action2.kind === "workspace")
902816
- return action2.targetCategoryId ? `open ${action2.targetCategoryId}` : "(workspace)";
903147
+ return "open area";
902817
903148
  if (action2.kind === "editor")
902818
- return action2.editorKind ? `edit ${action2.editorKind}` : "(editor)";
903149
+ return action2.editorKind ? `edit ${action2.editorKind}` : "edit form";
902819
903150
  if (action2.kind === "setting")
902820
- return action2.settingKey ? `set ${action2.settingKey}` : "set setting";
903151
+ return action2.settingKey ? `setting ${action2.settingKey}` : "setting";
902821
903152
  if (action2.kind === "settings-import")
902822
903153
  return "import GoodVibes settings";
903154
+ if (action2.kind === "model-picker")
903155
+ return action2.modelPickerFlow === "model" ? "model picker" : "provider/model picker";
903156
+ if (action2.kind === "settings-modal")
903157
+ return action2.settingsTarget ? `settings ${action2.settingsTarget}` : "settings";
902823
903158
  if (action2.kind === "local-selection")
902824
903159
  return action2.selectionDelta && action2.selectionDelta < 0 ? "select previous" : "select next";
902825
903160
  if (action2.kind === "local-operation")
902826
903161
  return action2.localOperation ?? "(local action)";
903162
+ if (action2.kind === "onboarding-complete")
903163
+ return "apply and close";
902827
903164
  return action2.command ?? "(guidance)";
902828
903165
  }
902829
903166
  function setupCounts(snapshot2) {
@@ -902837,6 +903174,11 @@ function setupCounts(snapshot2) {
902837
903174
  function setupStatusLabel(status) {
902838
903175
  return status === "ready" ? "Ready" : status === "recommended" ? "Recommended" : status === "blocked" ? "Blocked" : "Optional";
902839
903176
  }
903177
+ function formatMegabytes(bytes) {
903178
+ if (!Number.isFinite(bytes) || bytes <= 0)
903179
+ return "0 MB";
903180
+ return `${Math.round(bytes / (1024 * 1024))} MB`;
903181
+ }
902840
903182
  function compactText3(text, maxWidth = 104) {
902841
903183
  const normalized3 = text.replace(/\s+/g, " ").trim();
902842
903184
  if (normalized3.length === 0)
@@ -903007,6 +903349,27 @@ function snapshotLines(workspace, category, snapshot2) {
903007
903349
  base2.push({ text: `Chat route: ${snapshot2.provider} / ${snapshot2.modelDisplayName}`, fg: FULLSCREEN_PALETTE.info }, { text: `Session: ${snapshot2.sessionId}`, fg: FULLSCREEN_PALETTE.muted }, { text: `Policy: ${snapshot2.executionPolicy}; delegated review ${snapshot2.delegatedReviewPolicy}`, fg: FULLSCREEN_PALETTE.good }, conciseSetupLine(snapshot2), ...homeNextActionLines(snapshot2));
903008
903350
  } else if (category.id === "setup") {
903009
903351
  base2.push(...setupOverviewLines(snapshot2));
903352
+ } else if (category.id === "account-model") {
903353
+ base2.push({ text: `Chat route: ${snapshot2.provider} / ${snapshot2.modelDisplayName}`, fg: FULLSCREEN_PALETTE.info }, { text: `Subscriptions: ${snapshot2.activeSubscriptionCount} active; ${snapshot2.pendingSubscriptionCount} pending; ${snapshot2.availableSubscriptionProviderCount} available.`, fg: snapshot2.activeSubscriptionCount > 0 ? FULLSCREEN_PALETTE.good : snapshot2.pendingSubscriptionCount > 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted }, { text: `Embedding: ${snapshot2.embeddingProvider}; reasoning ${snapshot2.reasoningEffort}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Helper: ${snapshot2.helperEnabled ? "enabled" : "disabled"}; Tool LLM: ${snapshot2.toolLlmEnabled ? "enabled" : "disabled"}.`, fg: snapshot2.helperEnabled || snapshot2.toolLlmEnabled ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.muted }, { text: `Cache: ${snapshot2.cacheEnabled ? snapshot2.cacheStableTtl : "off"}; monitor ${snapshot2.cacheMonitorHitRate ? snapshot2.cacheHitRateWarningThreshold : "off"}; failure hints ${snapshot2.providerFailureHints ? "on" : "off"}.`, fg: snapshot2.cacheEnabled ? FULLSCREEN_PALETTE.info : FULLSCREEN_PALETTE.muted });
903354
+ } else if (category.id === "assistant-behavior") {
903355
+ base2.push({ text: `Interaction: ${snapshot2.hitlMode}; guidance ${snapshot2.guidanceMode}; history ${snapshot2.saveHistory ? "saved" : "off"}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Context: compact at ${snapshot2.autoCompactThreshold}; stale warnings ${snapshot2.staleContextWarnings ? "on" : "off"}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Reasoning display: thinking ${snapshot2.showThinking ? "on" : "off"}; summaries ${snapshot2.showReasoningSummary ? "on" : "off"}.`, fg: FULLSCREEN_PALETTE.muted });
903356
+ } else if (category.id === "tools-permissions") {
903357
+ base2.push({ text: `Permission mode: ${snapshot2.permissionMode}.`, fg: snapshot2.permissionMode === "allow-all" ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info }, { text: `Auto-approve ${snapshot2.autoApprove ? "on" : "off"}; tool auto-heal ${snapshot2.toolAutoHeal ? "on" : "off"}; token budget ${snapshot2.toolsDefaultTokenBudget}.`, fg: snapshot2.autoApprove ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info }, { text: `Artifact limit ${formatMegabytes(snapshot2.artifactMaxBytes)}; raw prompt telemetry ${snapshot2.rawPromptTelemetry ? "on" : "off"}.`, fg: snapshot2.rawPromptTelemetry ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted }, { text: `MCP servers: ${snapshot2.mcpConnectedServerCount}/${snapshot2.mcpServerCount} connected; quarantined ${snapshot2.mcpQuarantinedServerCount}.`, fg: snapshot2.mcpQuarantinedServerCount > 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info }, { text: "MCP and secret setup use forms; selecting a row does not run arbitrary tools.", fg: FULLSCREEN_PALETTE.good });
903358
+ } else if (category.id === "onboarding-display") {
903359
+ base2.push({ text: `Theme: ${snapshot2.theme}; streaming ${snapshot2.stream ? "on" : "off"}; line numbers ${snapshot2.lineNumbers}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Messages: operational ${snapshot2.operationalMessages}; system ${snapshot2.systemMessages}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Release channel: ${snapshot2.releaseChannel}.`, fg: FULLSCREEN_PALETTE.muted });
903360
+ } else if (category.id === "onboarding-channels") {
903361
+ const enabledCount = snapshot2.channels.filter((channel) => channel.enabled).length;
903362
+ const readyCount = snapshot2.channels.filter((channel) => channel.ready).length;
903363
+ const needsConfig = snapshot2.channels.filter((channel) => channel.setupState === "needs-config");
903364
+ const needsTarget = snapshot2.channels.filter((channel) => channel.setupState === "needs-target");
903365
+ base2.push({ text: `Channels: ${readyCount}/${snapshot2.channels.length} ready; ${enabledCount} enabled.`, fg: enabledCount > 0 ? FULLSCREEN_PALETTE.info : FULLSCREEN_PALETTE.muted }, { text: `Needs config: ${needsConfig.length}; needs target: ${needsTarget.length}.`, fg: needsConfig.length > 0 || needsTarget.length > 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.good }, { text: "Enable only the channels you want; hidden channel fields appear after the channel is enabled.", fg: FULLSCREEN_PALETTE.good });
903366
+ } else if (category.id === "onboarding-voice-media") {
903367
+ const readiness = snapshot2.voiceMediaReadiness;
903368
+ base2.push({ text: `Voice: ${snapshot2.voiceSurfaceEnabled ? "enabled" : "disabled"}; TTS ${snapshot2.ttsProvider}; voice ${snapshot2.ttsVoice}.`, fg: snapshot2.voiceSurfaceEnabled ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.info }, { text: `Media readiness: ${readiness.readyMediaProviderCount}/${snapshot2.mediaProviderCount}; generation providers ${snapshot2.mediaGenerationProviderCount}.`, fg: readiness.readyMediaProviderCount > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.muted }, { text: `Telephony channel: ${snapshot2.channels.find((channel) => channel.id === "telephony")?.setupState ?? "disabled"}.`, fg: FULLSCREEN_PALETTE.info });
903369
+ } else if (category.id === "onboarding-context") {
903370
+ base2.push({ text: `Local context: ${snapshot2.localMemoryCount} memories, ${snapshot2.localNoteCount} notes, ${snapshot2.localPersonaCount} personas.`, fg: FULLSCREEN_PALETTE.info }, { text: `Skills: ${snapshot2.enabledSkillCount}/${snapshot2.localSkillCount} enabled; routines ${snapshot2.enabledRoutineCount}/${snapshot2.localRoutineCount} enabled.`, fg: FULLSCREEN_PALETTE.info }, { text: `Discovered files: personas ${snapshot2.discoveredBehavior.personas.count}, skills ${snapshot2.discoveredBehavior.skills.count}, routines ${snapshot2.discoveredBehavior.routines.count}.`, fg: FULLSCREEN_PALETTE.muted });
903371
+ } else if (category.id === "onboarding-automation") {
903372
+ base2.push({ text: `Automation: ${snapshot2.automationEnabled ? "enabled" : "disabled"}; max ${snapshot2.automationMaxConcurrentRuns} concurrent; history ${snapshot2.automationRunHistoryLimit}.`, fg: snapshot2.automationEnabled ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.muted }, { text: `Timeout ${snapshot2.automationDefaultTimeoutMs} ms; catch-up ${snapshot2.automationCatchUpWindowMinutes} min; cooldown ${snapshot2.automationFailureCooldownMs} ms.`, fg: FULLSCREEN_PALETTE.info }, { text: `Delete one-shot jobs after success: ${snapshot2.automationDeleteAfterRun ? "yes" : "no"}.`, fg: snapshot2.automationDeleteAfterRun ? FULLSCREEN_PALETTE.info : FULLSCREEN_PALETTE.muted });
903010
903373
  } else if (category.id === "artifacts") {
903011
903374
  const mediaReady = snapshot2.voiceMediaReadiness.readyMediaProviderCount;
903012
903375
  base2.push({ text: `Chat: ${snapshot2.provider} / ${snapshot2.modelDisplayName}; Knowledge: ${snapshot2.knowledgeRoute}`, fg: FULLSCREEN_PALETTE.info }, { text: `Media: ${mediaReady}/${snapshot2.mediaProviderCount} ready; generation ${snapshot2.mediaGenerationProviderCount}.`, fg: mediaReady > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, { text: "Files: attach, export, inspect, ingest reviewed sources, or generate media.", fg: FULLSCREEN_PALETTE.good }, { text: "Knowledge ingest and media generation require explicit actions.", fg: FULLSCREEN_PALETTE.warn });
@@ -903263,17 +903626,20 @@ function normalizeFullscreenViewport(lines, width, height) {
903263
903626
  viewport.push(createEmptyLine(width));
903264
903627
  return viewport;
903265
903628
  }
903266
- function createAgentWorkspaceFullscreenComposite(workspace, width, height) {
903629
+ function createFullscreenCompositeFromLines(lines, width, height) {
903267
903630
  return {
903268
903631
  width,
903269
903632
  height,
903270
903633
  header: [],
903271
- viewport: normalizeFullscreenViewport(renderAgentWorkspace(workspace, width, height), width, height),
903634
+ viewport: normalizeFullscreenViewport(lines, width, height),
903272
903635
  footer: [],
903273
903636
  forceFullRedraw: true,
903274
903637
  panelWidth: 0
903275
903638
  };
903276
903639
  }
903640
+ function createAgentWorkspaceFullscreenComposite(workspace, width, height) {
903641
+ return createFullscreenCompositeFromLines(renderAgentWorkspace(workspace, width, height), width, height);
903642
+ }
903277
903643
 
903278
903644
  // src/shell/service-settings-sync.ts
903279
903645
  var AGENT_EXTERNAL_HOST_SERVICE_MESSAGE = "GoodVibes Agent uses a connected GoodVibes host and does not install, start, stop, restart, or uninstall it. Manage host lifecycle outside Agent.";
@@ -905782,6 +906148,14 @@ async function main() {
905782
906148
  input.setPanelMouseLayout(null);
905783
906149
  activeConversationWidth = width;
905784
906150
  conversation.setSplashSuppressed(true);
906151
+ if (input.modelPicker.active) {
906152
+ compositor.composite(createFullscreenCompositeFromLines(renderModelWorkspace(input.modelPicker, width, height), width, height));
906153
+ return;
906154
+ }
906155
+ if (input.settingsModal.active) {
906156
+ compositor.composite(createFullscreenCompositeFromLines(renderSettingsModal(input.settingsModal, width, height), width, height));
906157
+ return;
906158
+ }
905785
906159
  compositor.composite(createAgentWorkspaceFullscreenComposite(input.agentWorkspace, width, height));
905786
906160
  return;
905787
906161
  }