@pellux/goodvibes-agent 1.0.39 → 1.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  Product-facing release notes for GoodVibes Agent.
4
4
 
5
+ ## 1.0.40 - 2026-06-04
6
+
7
+ - Onboarding now uses a dedicated fullscreen workspace renderer copied from the settings-style workspace, so setup can be tuned without changing Settings, MCP, or Agent workspaces.
8
+ - First-run setup keeps the settings-style left rail, detail pane, field pane, and footer while the shell gives it the full terminal height, hiding the prompt/input area until setup is complete.
9
+
5
10
  ## 1.0.39 - 2026-06-04
6
11
 
7
12
  - Removed the body-scoped onboarding overlay fallback so onboarding can only render through the shell fullscreen composite.
@@ -389782,23 +389782,6 @@ function createSchema2(db) {
389782
389782
  `);
389783
389783
  db.run(`CREATE INDEX IF NOT EXISTS idx_knowledge_schedules_job_id ON knowledge_schedules(job_id)`);
389784
389784
  }
389785
- function getKnowledgeSchemaStatements() {
389786
- const statements = [];
389787
- createSchema2({
389788
- run(sql) {
389789
- const normalized = sql.trim();
389790
- if (normalized.length > 0)
389791
- statements.push(normalized);
389792
- }
389793
- });
389794
- return statements;
389795
- }
389796
- function renderKnowledgeSchemaSql() {
389797
- return `${getKnowledgeSchemaStatements().map((statement) => statement.endsWith(";") ? statement : `${statement};`).join(`
389798
-
389799
- `)}
389800
- `;
389801
- }
389802
389785
  function rowObject(columns, values2) {
389803
389786
  return Object.fromEntries(columns.map((column, index) => [column, values2[index]]));
389804
389787
  }
@@ -703136,9 +703119,6 @@ var init_ingest = __esm(() => {
703136
703119
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/browser-history/index.js
703137
703120
  var init_browser_history = __esm(() => {
703138
703121
  init_ingest();
703139
- init_discover();
703140
- init_readers();
703141
- init_paths2();
703142
703122
  });
703143
703123
 
703144
703124
  // node_modules/graphql/jsutils/devAssert.mjs
@@ -720778,7 +720758,6 @@ var init_semantic = __esm(() => {
720778
720758
  init_llm();
720779
720759
  init_gap_repair();
720780
720760
  init_service4();
720781
- init_self_improvement();
720782
720761
  });
720783
720762
 
720784
720763
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/home-graph/helpers.js
@@ -724747,40 +724726,8 @@ var init_map_view = __esm(() => {
724747
724726
  });
724748
724727
 
724749
724728
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/home-graph/types.js
724750
- var HOME_GRAPH_NODE_KINDS, HOME_GRAPH_RELATIONS, HOME_GRAPH_CAPABILITIES;
724729
+ var HOME_GRAPH_CAPABILITIES;
724751
724730
  var init_types6 = __esm(() => {
724752
- HOME_GRAPH_NODE_KINDS = [
724753
- "ha_home",
724754
- "ha_entity",
724755
- "ha_device",
724756
- "ha_area",
724757
- "ha_automation",
724758
- "ha_script",
724759
- "ha_scene",
724760
- "ha_label",
724761
- "ha_integration",
724762
- "ha_room",
724763
- "ha_device_passport",
724764
- "ha_maintenance_item",
724765
- "ha_troubleshooting_case",
724766
- "ha_purchase",
724767
- "ha_network_node"
724768
- ];
724769
- HOME_GRAPH_RELATIONS = [
724770
- "controls",
724771
- "located_in",
724772
- "belongs_to_device",
724773
- "has_manual",
724774
- "has_receipt",
724775
- "has_warranty",
724776
- "has_issue",
724777
- "fixed_by",
724778
- "uses_battery",
724779
- "connected_via",
724780
- "part_of_network",
724781
- "mentioned_by",
724782
- "source_for"
724783
- ];
724784
724731
  HOME_GRAPH_CAPABILITIES = [
724785
724732
  "knowledge-space-isolation",
724786
724733
  "snapshot-sync",
@@ -726187,7 +726134,6 @@ var init_service5 = __esm(() => {
726187
726134
  var init_home_graph = __esm(() => {
726188
726135
  init_service5();
726189
726136
  init_extension();
726190
- init_types6();
726191
726137
  });
726192
726138
 
726193
726139
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/store-refinement.js
@@ -728515,14 +728461,10 @@ var init_service6 = __esm(() => {
728515
728461
  var init_project_planning = __esm(() => {
728516
728462
  init_service6();
728517
728463
  init_helpers3();
728518
- init_readiness();
728519
728464
  });
728520
728465
 
728521
728466
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/persistence.js
728522
- var init_persistence = __esm(() => {
728523
- init_store_schema();
728524
- init_store_load();
728525
- });
728467
+ var init_persistence = () => {};
728526
728468
 
728527
728469
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/projections.js
728528
728470
  class KnowledgeProjectionService {
@@ -732030,21 +731972,21 @@ var init_service7 = __esm(() => {
732030
731972
  var exports_knowledge = {};
732031
731973
  __export(exports_knowledge, {
732032
731974
  withKnowledgeSpace: () => withKnowledgeSpace,
732033
- uniqKnowledgeValues: () => uniq2,
732034
- stabilizeKnowledgeText: () => stableText,
732035
- runKnowledgeSemanticSelfImprovement: () => runKnowledgeSemanticSelfImprovement,
731975
+ uniqKnowledgeValues: () => uniq3,
731976
+ stabilizeKnowledgeText: () => stableText2,
731977
+ runKnowledgeSemanticSelfImprovement: () => runKnowledgeSemanticSelfImprovement2,
732036
731978
  resolveProjectPlanningSpace: () => resolveProjectPlanningSpace,
732037
- resolveKnowledgeDbPathFromControlPlaneDir: () => resolveKnowledgeDbPathFromControlPlaneDir,
731979
+ resolveKnowledgeDbPathFromControlPlaneDir: () => resolveKnowledgeDbPathFromControlPlaneDir2,
732038
731980
  renderPacket: () => renderPacket,
732039
731981
  renderKnowledgeSchemaSql: () => renderKnowledgeSchemaSql,
732040
731982
  renderKnowledgeMap: () => renderKnowledgeMap,
732041
731983
  readKnowledgeSearchText: () => readKnowledgeSearchText,
732042
- readBrowserKnowledgeProfile: () => readBrowserKnowledgeProfile,
731984
+ readBrowserKnowledgeProfile: () => readBrowserKnowledgeProfile2,
732043
731985
  projectPlanningSourceId: () => projectPlanningSourceId,
732044
731986
  projectPlanningProjectIdFromPath: () => projectPlanningProjectIdFromPath,
732045
731987
  projectPlanningCanonicalUri: () => projectPlanningCanonicalUri,
732046
731988
  projectKnowledgeSpaceId: () => projectKnowledgeSpaceId,
732047
- parseKnowledgeJsonValue: () => parseJsonValue,
731989
+ parseKnowledgeJsonValue: () => parseJsonValue2,
732048
731990
  normalizeProjectId: () => normalizeProjectId,
732049
731991
  normalizeKnowledgeSpaceId: () => normalizeKnowledgeSpaceId,
732050
731992
  normalizeHomeAssistantInstallationId: () => normalizeHomeAssistantInstallationId,
@@ -732052,12 +731994,12 @@ __export(exports_knowledge, {
732052
731994
  materializeGeneratedKnowledgeProjection: () => materializeGeneratedKnowledgeProjection,
732053
731995
  looksLikeRawPdfPayload: () => looksLikeRawPdfPayload,
732054
731996
  looksBinaryLikeText: () => looksBinaryLikeText,
732055
- loadKnowledgeStoreSnapshot: () => loadKnowledgeStoreSnapshot,
731997
+ loadKnowledgeStoreSnapshot: () => loadKnowledgeStoreSnapshot2,
732056
731998
  listGeneratedKnowledgePages: () => listGeneratedKnowledgePages,
732057
- listBrowserKinds: () => listBrowserKinds,
731999
+ listBrowserKinds: () => listBrowserKinds2,
732058
732000
  knowledgeSpaceMetadata: () => knowledgeSpaceMetadata,
732059
732001
  knowledgePageSourceWeight: () => knowledgePageSourceWeight,
732060
- knowledgeNowMs: () => nowMs,
732002
+ knowledgeNowMs: () => nowMs2,
732061
732003
  knowledgeExtractionNeedsRefresh: () => knowledgeExtractionNeedsRefresh,
732062
732004
  isUsefulKnowledgePageSourceCandidate: () => isUsefulKnowledgePageSourceCandidate,
732063
732005
  isUsefulKnowledgePageSource: () => isUsefulKnowledgePageSource,
@@ -732077,12 +732019,12 @@ __export(exports_knowledge, {
732077
732019
  generatedKnowledgeSourceId: () => generatedKnowledgeSourceId,
732078
732020
  generatedKnowledgeCanonicalUri: () => generatedKnowledgeCanonicalUri,
732079
732021
  extractKnowledgeArtifact: () => extractKnowledgeArtifact,
732080
- evaluateProjectPlanningReadiness: () => evaluateProjectPlanningReadiness,
732081
- discoverBrowserKnowledgeProfiles: () => discoverBrowserKnowledgeProfiles,
732022
+ evaluateProjectPlanningReadiness: () => evaluateProjectPlanningReadiness2,
732023
+ discoverBrowserKnowledgeProfiles: () => discoverBrowserKnowledgeProfiles2,
732082
732024
  createWebKnowledgeGapRepairer: () => createWebKnowledgeGapRepairer,
732083
732025
  createProviderBackedKnowledgeSemanticLlm: () => createProviderBackedKnowledgeSemanticLlm,
732084
732026
  createMemoryApi: () => createMemoryApi,
732085
- createKnowledgeSchema: () => createSchema2,
732027
+ createKnowledgeSchema: () => createSchema3,
732086
732028
  createKnowledgeApi: () => createKnowledgeApi,
732087
732029
  createDefaultKnowledgeConnectorRegistry: () => createDefaultKnowledgeConnectorRegistry,
732088
732030
  compareKnowledgePageSources: () => compareKnowledgePageSources,
@@ -734521,7 +734463,7 @@ var init_delivery_manager = __esm(() => {
734521
734463
  });
734522
734464
 
734523
734465
  // node_modules/@pellux/goodvibes-sdk/dist/platform/automation/scheduler-capacity.js
734524
- function computeSchedulerCapacity(slotsTotal, runs, nowMs2 = Date.now()) {
734466
+ function computeSchedulerCapacity(slotsTotal, runs, nowMs3 = Date.now()) {
734525
734467
  let slotsInUse = 0;
734526
734468
  const queuedRuns = [];
734527
734469
  for (const run7 of runs) {
@@ -734531,7 +734473,7 @@ function computeSchedulerCapacity(slotsTotal, runs, nowMs2 = Date.now()) {
734531
734473
  queuedRuns.push(run7);
734532
734474
  }
734533
734475
  const queueDepth = queuedRuns.length;
734534
- const oldestQueuedAgeMs = queueDepth > 0 ? nowMs2 - Math.min(...queuedRuns.map((r5) => r5.queuedAt)) : null;
734476
+ const oldestQueuedAgeMs = queueDepth > 0 ? nowMs3 - Math.min(...queuedRuns.map((r5) => r5.queuedAt)) : null;
734535
734477
  return { slotsTotal, slotsInUse, queueDepth, oldestQueuedAgeMs };
734536
734478
  }
734537
734479
 
@@ -817145,7 +817087,7 @@ var createStyledCell = (char, overrides = {}) => ({
817145
817087
  // src/version.ts
817146
817088
  import { readFileSync } from "fs";
817147
817089
  import { join } from "path";
817148
- var _version = "1.0.39";
817090
+ var _version = "1.0.40";
817149
817091
  try {
817150
817092
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf-8"));
817151
817093
  _version = typeof pkg.version === "string" ? pkg.version : _version;
@@ -840228,7 +840170,7 @@ var WORK_PLAN_STATUSES = [
840228
840170
  "failed",
840229
840171
  "cancelled"
840230
840172
  ];
840231
- function nowMs2() {
840173
+ function nowMs3() {
840232
840174
  return Date.now();
840233
840175
  }
840234
840176
  function isObject5(value) {
@@ -840334,7 +840276,7 @@ class WorkPlanStore {
840334
840276
  if (!normalizedTitle)
840335
840277
  throw new Error("Work plan item title is required.");
840336
840278
  const plan = this.readPlan();
840337
- const time4 = nowMs2();
840279
+ const time4 = nowMs3();
840338
840280
  const item = {
840339
840281
  id: createItemId(),
840340
840282
  title: normalizedTitle,
@@ -840358,7 +840300,7 @@ class WorkPlanStore {
840358
840300
  updateItem(idOrPrefix, patch2) {
840359
840301
  const plan = this.readPlan();
840360
840302
  const item = this.resolveItem(plan, idOrPrefix);
840361
- const time4 = nowMs2();
840303
+ const time4 = nowMs3();
840362
840304
  const nextStatus = patch2.status ?? item.status;
840363
840305
  const next = this.pruneItem({
840364
840306
  ...item,
@@ -840391,7 +840333,7 @@ class WorkPlanStore {
840391
840333
  removeItem(idOrPrefix) {
840392
840334
  const plan = this.readPlan();
840393
840335
  const item = this.resolveItem(plan, idOrPrefix);
840394
- const time4 = nowMs2();
840336
+ const time4 = nowMs3();
840395
840337
  const remaining = plan.items.filter((candidate) => candidate.id !== item.id);
840396
840338
  this.writePlan({
840397
840339
  ...plan,
@@ -840411,7 +840353,7 @@ class WorkPlanStore {
840411
840353
  ...plan,
840412
840354
  items: remaining,
840413
840355
  activeItemId: remaining[0]?.id,
840414
- updatedAt: nowMs2()
840356
+ updatedAt: nowMs3()
840415
840357
  });
840416
840358
  return removed;
840417
840359
  }
@@ -840450,7 +840392,7 @@ class WorkPlanStore {
840450
840392
  const parsed = JSON.parse(raw);
840451
840393
  if (!isObject5(parsed))
840452
840394
  return this.createEmptyPlan();
840453
- const time4 = nowMs2();
840395
+ const time4 = nowMs3();
840454
840396
  const createdAt = typeof parsed.createdAt === "number" ? parsed.createdAt : time4;
840455
840397
  const updatedAt = typeof parsed.updatedAt === "number" ? parsed.updatedAt : createdAt;
840456
840398
  const items = Array.isArray(parsed.items) ? parsed.items.map((item) => normalizeItem(item, createdAt)).filter((item) => item !== null) : [];
@@ -840469,7 +840411,7 @@ class WorkPlanStore {
840469
840411
  };
840470
840412
  }
840471
840413
  createEmptyPlan() {
840472
- const time4 = nowMs2();
840414
+ const time4 = nowMs3();
840473
840415
  return {
840474
840416
  id: createPlanId(this.options.projectId, this.options.projectRoot),
840475
840417
  projectId: this.options.projectId,
@@ -848701,13 +848643,13 @@ init_state3();
848701
848643
 
848702
848644
  // src/input/commands/recall-shared.ts
848703
848645
  var VALID_CLASSES = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
848704
- var VALID_SCOPES = ["session", "project", "team"];
848646
+ var VALID_SCOPES2 = ["session", "project", "team"];
848705
848647
  var VALID_REVIEW_STATES = ["fresh", "reviewed", "stale", "contradicted"];
848706
848648
  function isValidClass(s4) {
848707
848649
  return VALID_CLASSES.includes(s4);
848708
848650
  }
848709
848651
  function isValidScope(s4) {
848710
- return VALID_SCOPES.includes(s4);
848652
+ return VALID_SCOPES2.includes(s4);
848711
848653
  }
848712
848654
  function isValidReviewState(s4) {
848713
848655
  return VALID_REVIEW_STATES.includes(s4);
@@ -848750,7 +848692,7 @@ function handleRecallSearch(args2, context) {
848750
848692
  if (isValidScope(scope))
848751
848693
  filter.scope = scope;
848752
848694
  else {
848753
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
848695
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
848754
848696
  return;
848755
848697
  }
848756
848698
  }
@@ -848925,7 +848867,7 @@ function handleRecallList(args2, context) {
848925
848867
  if (scopeIdx !== -1 && args2[scopeIdx + 1]) {
848926
848868
  const scope = args2[scopeIdx + 1];
848927
848869
  if (!isValidScope(scope)) {
848928
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
848870
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
848929
848871
  return;
848930
848872
  }
848931
848873
  filter.scope = scope;
@@ -848975,7 +848917,7 @@ async function handleRecallAdd(args2, context) {
848975
848917
  const tags = tagsRaw ? tagsRaw.split(",").map((token) => token.trim()).filter(Boolean) : [];
848976
848918
  const scope = scopeRaw && isValidScope(scopeRaw) ? scopeRaw : "project";
848977
848919
  if (scopeRaw && !isValidScope(scopeRaw)) {
848978
- context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES.join(", ")}.`);
848920
+ context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES2.join(", ")}.`);
848979
848921
  return;
848980
848922
  }
848981
848923
  const provenance = [];
@@ -849109,7 +849051,7 @@ function handleRecallExport(args2, context) {
849109
849051
  if (scopeIdx !== -1 && commandArgs[scopeIdx + 1]) {
849110
849052
  const scope = commandArgs[scopeIdx + 1];
849111
849053
  if (!isValidScope(scope)) {
849112
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
849054
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
849113
849055
  return;
849114
849056
  }
849115
849057
  filter.scope = scope;
@@ -849188,7 +849130,7 @@ function handleRecallHandoffExport(args2, context) {
849188
849130
  const scopeIdx = commandArgs.indexOf("--scope");
849189
849131
  const scopeRaw = scopeIdx !== -1 ? commandArgs[scopeIdx + 1] : "team";
849190
849132
  if (!scopeRaw || !isValidScope(scopeRaw)) {
849191
- context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES.join(", ")}.`);
849133
+ context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES2.join(", ")}.`);
849192
849134
  return;
849193
849135
  }
849194
849136
  const bundle = memory.exportBundle({ scope: scopeRaw });
@@ -849304,7 +849246,7 @@ function handleRecallPromote(args2, context) {
849304
849246
  const id = parsed.rest[0];
849305
849247
  const scope = parsed.rest[1];
849306
849248
  if (!id || !scope || !isValidScope(scope)) {
849307
- context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES.join("|")}> --yes`);
849249
+ context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES2.join("|")}> --yes`);
849308
849250
  return;
849309
849251
  }
849310
849252
  if (!parsed.yes) {
@@ -863229,7 +863171,7 @@ import { mkdirSync as mkdirSync64, readFileSync as readFileSync85, writeFileSync
863229
863171
  import { dirname as dirname63, resolve as resolve39 } from "path";
863230
863172
  init_state3();
863231
863173
  var VALID_CLASSES2 = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
863232
- var VALID_SCOPES3 = ["session", "project", "team"];
863174
+ var VALID_SCOPES4 = ["session", "project", "team"];
863233
863175
  var VALID_REVIEW_STATES3 = ["fresh", "reviewed", "stale", "contradicted"];
863234
863176
  var VALID_PROVENANCE_KINDS = ["session", "turn", "task", "event", "file"];
863235
863177
  var VALUE_OPTIONS = new Set([
@@ -863329,7 +863271,7 @@ function isMemoryClass2(value) {
863329
863271
  return VALID_CLASSES2.includes(value);
863330
863272
  }
863331
863273
  function isMemoryScope2(value) {
863332
- return VALID_SCOPES3.includes(value);
863274
+ return VALID_SCOPES4.includes(value);
863333
863275
  }
863334
863276
  function isReviewState(value) {
863335
863277
  return VALID_REVIEW_STATES3.includes(value);
@@ -863344,7 +863286,7 @@ function requireClass(value) {
863344
863286
  }
863345
863287
  function requireScope(value) {
863346
863288
  if (!value || !isMemoryScope2(value))
863347
- throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES3.join(", ")}`);
863289
+ throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES4.join(", ")}`);
863348
863290
  return value;
863349
863291
  }
863350
863292
  function optionalScope(value) {
@@ -906477,6 +906419,128 @@ function handleBlockingShellInput(options) {
906477
906419
  return { handled: false, pendingPermission, recoveryPending };
906478
906420
  }
906479
906421
 
906422
+ // src/renderer/onboarding/onboarding-workspace.ts
906423
+ var WORKSPACE_PALETTE2 = FULLSCREEN_PALETTE;
906424
+ function drawVertical3(line2, x2, bg = "") {
906425
+ if (x2 <= 0 || x2 >= line2.length - 1)
906426
+ return;
906427
+ drawVerticalRule(line2, x2, WORKSPACE_PALETTE2.border, bg);
906428
+ }
906429
+ function drawHorizontalRange2(line2, startX, endX, bg = "") {
906430
+ drawHorizontalRule(line2, Math.max(1, startX), Math.min(line2.length - 2, endX), WORKSPACE_PALETTE2.border, bg);
906431
+ }
906432
+ function leftWidthFor2(width, explicit) {
906433
+ if (explicit !== undefined)
906434
+ return clamp3(explicit, 14, Math.max(14, width - 24));
906435
+ return width < 80 ? clamp3(Math.round(width * 0.32), 14, Math.max(14, width - 24)) : clamp3(Math.round(width * 0.22), 24, 34);
906436
+ }
906437
+ function getFullscreenWorkspaceMetrics2(options) {
906438
+ const safeWidth = Math.max(1, options.width);
906439
+ const safeHeight = Math.max(12, options.height);
906440
+ const leftWidth = leftWidthFor2(safeWidth, options.leftWidth);
906441
+ const centerWidth = Math.max(20, safeWidth - leftWidth - 3);
906442
+ const bodyTop = 3;
906443
+ const footerY = safeHeight - 2;
906444
+ const bodyRows = Math.max(4, footerY - bodyTop);
906445
+ const contextWidth = Math.max(10, centerWidth - 2);
906446
+ const maxContextRows = Math.max(3, bodyRows - 4);
906447
+ const minContextRows = clamp3(options.minContextRows ?? 10, 3, maxContextRows);
906448
+ const contextRows = clamp3(Math.round(bodyRows * (options.contextRatio ?? 0.4)), Math.min(minContextRows, maxContextRows), maxContextRows);
906449
+ const controlRows = Math.max(3, bodyRows - contextRows - 1);
906450
+ return { safeWidth, safeHeight, leftWidth, centerWidth, bodyRows, contextWidth, contextRows, controlRows };
906451
+ }
906452
+ function rowFg2(row, fallback) {
906453
+ if (row.fg)
906454
+ return row.fg;
906455
+ if (row.kind === "group")
906456
+ return WORKSPACE_PALETTE2.subtitle;
906457
+ if (row.kind === "more")
906458
+ return WORKSPACE_PALETTE2.dim;
906459
+ return fallback;
906460
+ }
906461
+ function renderFullscreenWorkspace2(options) {
906462
+ const { safeWidth, safeHeight, leftWidth, centerWidth, bodyRows, contextWidth, contextRows } = getFullscreenWorkspaceMetrics2(options);
906463
+ const leftStart = 1;
906464
+ const dividerX = leftWidth + 1;
906465
+ const centerStart = dividerX + 1;
906466
+ const centerEnd = safeWidth - 2;
906467
+ const bodyTop = 3;
906468
+ const separatorY = bodyTop + contextRows;
906469
+ const lines = [];
906470
+ const top = borderLine(safeWidth, GLYPHS.frame.topLeft, GLYPHS.frame.horizontal, GLYPHS.frame.topRight);
906471
+ writeText2(top, 2, safeWidth - 4, ` ${options.title} `, { fg: WORKSPACE_PALETTE2.title, bold: true });
906472
+ if (options.stateLabel) {
906473
+ writeText2(top, Math.max(2, safeWidth - options.stateLabel.length - 4), options.stateLabel.length, options.stateLabel, {
906474
+ fg: WORKSPACE_PALETTE2.subtitle
906475
+ });
906476
+ }
906477
+ lines.push(top);
906478
+ const header = contentLine(safeWidth, WORKSPACE_PALETTE2.footerBg);
906479
+ drawVertical3(header, dividerX, WORKSPACE_PALETTE2.footerBg);
906480
+ writeText2(header, leftStart + 1, leftWidth - 2, options.leftHeader, {
906481
+ fg: WORKSPACE_PALETTE2.subtitle,
906482
+ bold: true,
906483
+ bg: WORKSPACE_PALETTE2.footerBg
906484
+ });
906485
+ writeText2(header, centerStart + 1, centerWidth - 2, options.mainHeader, {
906486
+ fg: WORKSPACE_PALETTE2.subtitle,
906487
+ bold: true,
906488
+ bg: WORKSPACE_PALETTE2.footerBg
906489
+ });
906490
+ lines.push(header);
906491
+ const headerSep = contentLine(safeWidth, "");
906492
+ drawVertical3(headerSep, dividerX);
906493
+ drawHorizontalRange2(headerSep, 1, safeWidth - 2);
906494
+ lines.push(headerSep);
906495
+ for (let row = 0;row < bodyRows; row += 1) {
906496
+ const y2 = bodyTop + row;
906497
+ const inContext = y2 < separatorY;
906498
+ const inSeparator = y2 === separatorY;
906499
+ const bg = inSeparator ? "" : inContext ? WORKSPACE_PALETTE2.contextBg : WORKSPACE_PALETTE2.controlsBg;
906500
+ const line2 = contentLine(safeWidth, bg);
906501
+ fillRange(line2, 1, dividerX - 1, WORKSPACE_PALETTE2.categoryBg);
906502
+ drawVertical3(line2, dividerX, bg);
906503
+ const leftRow = options.leftRows[row] ?? { text: "", kind: "empty" };
906504
+ if (leftRow.selected)
906505
+ fillRange(line2, leftStart, dividerX - 1, WORKSPACE_PALETTE2.selectedBg);
906506
+ writeText2(line2, leftStart + 1, leftWidth - 3, leftRow.text, {
906507
+ fg: leftRow.selected ? WORKSPACE_PALETTE2.text : rowFg2(leftRow, WORKSPACE_PALETTE2.muted),
906508
+ bg: leftRow.selected ? WORKSPACE_PALETTE2.selectedBg : WORKSPACE_PALETTE2.categoryBg,
906509
+ bold: leftRow.bold ?? (leftRow.selected || leftRow.kind === "group"),
906510
+ dim: leftRow.dim
906511
+ });
906512
+ if (inSeparator) {
906513
+ drawHorizontalRange2(line2, centerStart, centerEnd);
906514
+ } else if (inContext) {
906515
+ const contextRow = options.contextRows[row] ?? { text: "", kind: "empty" };
906516
+ writeText2(line2, centerStart + 1, contextWidth, contextRow.text, {
906517
+ fg: rowFg2(contextRow, WORKSPACE_PALETTE2.text),
906518
+ bg,
906519
+ bold: contextRow.bold,
906520
+ dim: contextRow.dim ?? contextRow.text.length === 0
906521
+ });
906522
+ } else {
906523
+ const controlRow = options.controlRows[row - contextRows - 1] ?? { text: "", kind: "empty" };
906524
+ if (controlRow.selected)
906525
+ fillRange(line2, centerStart, centerEnd, WORKSPACE_PALETTE2.selectedBg);
906526
+ writeText2(line2, centerStart + 1, contextWidth, controlRow.text, {
906527
+ fg: controlRow.selected ? WORKSPACE_PALETTE2.text : rowFg2(controlRow, WORKSPACE_PALETTE2.text),
906528
+ bg: controlRow.selected ? WORKSPACE_PALETTE2.selectedBg : bg,
906529
+ bold: controlRow.bold ?? controlRow.selected,
906530
+ dim: controlRow.dim ?? controlRow.text.length === 0
906531
+ });
906532
+ }
906533
+ lines.push(line2);
906534
+ }
906535
+ const footer = contentLine(safeWidth, WORKSPACE_PALETTE2.footerBg);
906536
+ writeText2(footer, 2, safeWidth - 4, options.footer, { fg: WORKSPACE_PALETTE2.muted, bg: WORKSPACE_PALETTE2.footerBg });
906537
+ lines.push(footer);
906538
+ lines.push(borderLine(safeWidth, GLYPHS.frame.bottomLeft, GLYPHS.frame.horizontal, GLYPHS.frame.bottomRight));
906539
+ while (lines.length < safeHeight)
906540
+ lines.unshift(makeLine(safeWidth));
906541
+ return lines.slice(-safeHeight);
906542
+ }
906543
+
906480
906544
  // src/renderer/onboarding/onboarding-wizard.ts
906481
906545
  function modeLabel(mode) {
906482
906546
  if (mode === "edit")
@@ -906754,8 +906818,8 @@ function renderOnboardingWizard(wizard, width, viewportHeight) {
906754
906818
  contextRatio: 0.42,
906755
906819
  minContextRows: 8
906756
906820
  };
906757
- const metrics = getFullscreenWorkspaceMetrics(layoutOptions);
906758
- return renderFullscreenWorkspace({
906821
+ const metrics = getFullscreenWorkspaceMetrics2(layoutOptions);
906822
+ return renderFullscreenWorkspace2({
906759
906823
  width,
906760
906824
  height: viewportHeight,
906761
906825
  title: "GoodVibes Agent / Onboarding Wizard",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "1.0.39",
3
+ "version": "1.0.40",
4
4
  "private": false,
5
5
  "description": "GoodVibes personal operator assistant TUI with a proactive Agent product brain, isolated Agent Knowledge, local profiles, routines, skills, personas, and explicit build delegation.",
6
6
  "type": "module",
@@ -6,7 +6,7 @@ import {
6
6
  stableWindow,
7
7
  WORKSPACE_PALETTE as PALETTE,
8
8
  type WorkspaceRow,
9
- } from '../fullscreen-workspace.ts';
9
+ } from './onboarding-workspace.ts';
10
10
  import { GLYPHS } from '../ui-primitives.ts';
11
11
  import {
12
12
  type OnboardingWizardController,
@@ -0,0 +1,199 @@
1
+ import type { Line } from '../../types/grid.ts';
2
+ import { GLYPHS } from '../ui-primitives.ts';
3
+ import {
4
+ borderLine,
5
+ clamp,
6
+ contentLine,
7
+ drawHorizontalRule,
8
+ drawVerticalRule,
9
+ fillRange,
10
+ FULLSCREEN_PALETTE,
11
+ makeLine,
12
+ writeText,
13
+ } from '../fullscreen-primitives.ts';
14
+
15
+ export {
16
+ borderLine,
17
+ clamp,
18
+ contentLine,
19
+ fillRange,
20
+ makeLine,
21
+ padDisplay,
22
+ stableWindow,
23
+ writeText,
24
+ } from '../fullscreen-primitives.ts';
25
+ export { FULLSCREEN_PALETTE as WORKSPACE_PALETTE } from '../fullscreen-primitives.ts';
26
+
27
+ const WORKSPACE_PALETTE = FULLSCREEN_PALETTE;
28
+
29
+ export interface WorkspaceRow {
30
+ readonly text: string;
31
+ readonly selected?: boolean;
32
+ readonly bold?: boolean;
33
+ readonly dim?: boolean;
34
+ readonly fg?: string;
35
+ readonly bg?: string;
36
+ readonly kind?: 'group' | 'item' | 'more' | 'empty';
37
+ }
38
+
39
+ export interface FullscreenWorkspaceRenderOptions {
40
+ readonly width: number;
41
+ readonly height: number;
42
+ readonly title: string;
43
+ readonly stateLabel?: string;
44
+ readonly leftHeader: string;
45
+ readonly mainHeader: string;
46
+ readonly leftRows: readonly WorkspaceRow[];
47
+ readonly contextRows: readonly WorkspaceRow[];
48
+ readonly controlRows: readonly WorkspaceRow[];
49
+ readonly footer: string;
50
+ readonly leftWidth?: number;
51
+ readonly contextRatio?: number;
52
+ readonly minContextRows?: number;
53
+ }
54
+
55
+ export interface FullscreenWorkspaceMetrics {
56
+ readonly safeWidth: number;
57
+ readonly safeHeight: number;
58
+ readonly leftWidth: number;
59
+ readonly centerWidth: number;
60
+ readonly bodyRows: number;
61
+ readonly contextWidth: number;
62
+ readonly contextRows: number;
63
+ readonly controlRows: number;
64
+ }
65
+
66
+ export function drawVertical(line: Line, x: number, bg = ''): void {
67
+ if (x <= 0 || x >= line.length - 1) return;
68
+ drawVerticalRule(line, x, WORKSPACE_PALETTE.border, bg);
69
+ }
70
+
71
+ export function drawHorizontalRange(line: Line, startX: number, endX: number, bg = ''): void {
72
+ drawHorizontalRule(line, Math.max(1, startX), Math.min(line.length - 2, endX), WORKSPACE_PALETTE.border, bg);
73
+ }
74
+
75
+ function leftWidthFor(width: number, explicit?: number): number {
76
+ if (explicit !== undefined) return clamp(explicit, 14, Math.max(14, width - 24));
77
+ return width < 80
78
+ ? clamp(Math.round(width * 0.32), 14, Math.max(14, width - 24))
79
+ : clamp(Math.round(width * 0.22), 24, 34);
80
+ }
81
+
82
+ export function getFullscreenWorkspaceMetrics(options: Pick<
83
+ FullscreenWorkspaceRenderOptions,
84
+ 'width' | 'height' | 'leftWidth' | 'contextRatio' | 'minContextRows'
85
+ >): FullscreenWorkspaceMetrics {
86
+ const safeWidth = Math.max(1, options.width);
87
+ const safeHeight = Math.max(12, options.height);
88
+ const leftWidth = leftWidthFor(safeWidth, options.leftWidth);
89
+ const centerWidth = Math.max(20, safeWidth - leftWidth - 3);
90
+ const bodyTop = 3;
91
+ const footerY = safeHeight - 2;
92
+ const bodyRows = Math.max(4, footerY - bodyTop);
93
+ const contextWidth = Math.max(10, centerWidth - 2);
94
+ const maxContextRows = Math.max(3, bodyRows - 4);
95
+ const minContextRows = clamp(options.minContextRows ?? 10, 3, maxContextRows);
96
+ const contextRows = clamp(
97
+ Math.round(bodyRows * (options.contextRatio ?? 0.4)),
98
+ Math.min(minContextRows, maxContextRows),
99
+ maxContextRows,
100
+ );
101
+ const controlRows = Math.max(3, bodyRows - contextRows - 1);
102
+ return { safeWidth, safeHeight, leftWidth, centerWidth, bodyRows, contextWidth, contextRows, controlRows };
103
+ }
104
+
105
+ function rowFg(row: WorkspaceRow, fallback: string): string {
106
+ if (row.fg) return row.fg;
107
+ if (row.kind === 'group') return WORKSPACE_PALETTE.subtitle;
108
+ if (row.kind === 'more') return WORKSPACE_PALETTE.dim;
109
+ return fallback;
110
+ }
111
+
112
+ export function renderFullscreenWorkspace(options: FullscreenWorkspaceRenderOptions): Line[] {
113
+ const { safeWidth, safeHeight, leftWidth, centerWidth, bodyRows, contextWidth, contextRows } = getFullscreenWorkspaceMetrics(options);
114
+ const leftStart = 1;
115
+ const dividerX = leftWidth + 1;
116
+ const centerStart = dividerX + 1;
117
+ const centerEnd = safeWidth - 2;
118
+ const bodyTop = 3;
119
+ const separatorY = bodyTop + contextRows;
120
+ const lines: Line[] = [];
121
+
122
+ const top = borderLine(safeWidth, GLYPHS.frame.topLeft, GLYPHS.frame.horizontal, GLYPHS.frame.topRight);
123
+ writeText(top, 2, safeWidth - 4, ` ${options.title} `, { fg: WORKSPACE_PALETTE.title, bold: true });
124
+ if (options.stateLabel) {
125
+ writeText(top, Math.max(2, safeWidth - options.stateLabel.length - 4), options.stateLabel.length, options.stateLabel, {
126
+ fg: WORKSPACE_PALETTE.subtitle,
127
+ });
128
+ }
129
+ lines.push(top);
130
+
131
+ const header = contentLine(safeWidth, WORKSPACE_PALETTE.footerBg);
132
+ drawVertical(header, dividerX, WORKSPACE_PALETTE.footerBg);
133
+ writeText(header, leftStart + 1, leftWidth - 2, options.leftHeader, {
134
+ fg: WORKSPACE_PALETTE.subtitle,
135
+ bold: true,
136
+ bg: WORKSPACE_PALETTE.footerBg,
137
+ });
138
+ writeText(header, centerStart + 1, centerWidth - 2, options.mainHeader, {
139
+ fg: WORKSPACE_PALETTE.subtitle,
140
+ bold: true,
141
+ bg: WORKSPACE_PALETTE.footerBg,
142
+ });
143
+ lines.push(header);
144
+
145
+ const headerSep = contentLine(safeWidth, '');
146
+ drawVertical(headerSep, dividerX);
147
+ drawHorizontalRange(headerSep, 1, safeWidth - 2);
148
+ lines.push(headerSep);
149
+
150
+ for (let row = 0; row < bodyRows; row += 1) {
151
+ const y = bodyTop + row;
152
+ const inContext = y < separatorY;
153
+ const inSeparator = y === separatorY;
154
+ const bg = inSeparator ? '' : inContext ? WORKSPACE_PALETTE.contextBg : WORKSPACE_PALETTE.controlsBg;
155
+ const line = contentLine(safeWidth, bg);
156
+ fillRange(line, 1, dividerX - 1, WORKSPACE_PALETTE.categoryBg);
157
+ drawVertical(line, dividerX, bg);
158
+
159
+ const leftRow = options.leftRows[row] ?? { text: '', kind: 'empty' as const };
160
+ if (leftRow.selected) fillRange(line, leftStart, dividerX - 1, WORKSPACE_PALETTE.selectedBg);
161
+ writeText(line, leftStart + 1, leftWidth - 3, leftRow.text, {
162
+ fg: leftRow.selected ? WORKSPACE_PALETTE.text : rowFg(leftRow, WORKSPACE_PALETTE.muted),
163
+ bg: leftRow.selected ? WORKSPACE_PALETTE.selectedBg : WORKSPACE_PALETTE.categoryBg,
164
+ bold: leftRow.bold ?? (leftRow.selected || leftRow.kind === 'group'),
165
+ dim: leftRow.dim,
166
+ });
167
+
168
+ if (inSeparator) {
169
+ drawHorizontalRange(line, centerStart, centerEnd);
170
+ } else if (inContext) {
171
+ const contextRow = options.contextRows[row] ?? { text: '', kind: 'empty' as const };
172
+ writeText(line, centerStart + 1, contextWidth, contextRow.text, {
173
+ fg: rowFg(contextRow, WORKSPACE_PALETTE.text),
174
+ bg,
175
+ bold: contextRow.bold,
176
+ dim: contextRow.dim ?? contextRow.text.length === 0,
177
+ });
178
+ } else {
179
+ const controlRow = options.controlRows[row - contextRows - 1] ?? { text: '', kind: 'empty' as const };
180
+ if (controlRow.selected) fillRange(line, centerStart, centerEnd, WORKSPACE_PALETTE.selectedBg);
181
+ writeText(line, centerStart + 1, contextWidth, controlRow.text, {
182
+ fg: controlRow.selected ? WORKSPACE_PALETTE.text : rowFg(controlRow, WORKSPACE_PALETTE.text),
183
+ bg: controlRow.selected ? WORKSPACE_PALETTE.selectedBg : bg,
184
+ bold: controlRow.bold ?? controlRow.selected,
185
+ dim: controlRow.dim ?? controlRow.text.length === 0,
186
+ });
187
+ }
188
+
189
+ lines.push(line);
190
+ }
191
+
192
+ const footer = contentLine(safeWidth, WORKSPACE_PALETTE.footerBg);
193
+ writeText(footer, 2, safeWidth - 4, options.footer, { fg: WORKSPACE_PALETTE.muted, bg: WORKSPACE_PALETTE.footerBg });
194
+ lines.push(footer);
195
+ lines.push(borderLine(safeWidth, GLYPHS.frame.bottomLeft, GLYPHS.frame.horizontal, GLYPHS.frame.bottomRight));
196
+
197
+ while (lines.length < safeHeight) lines.unshift(makeLine(safeWidth));
198
+ return lines.slice(-safeHeight);
199
+ }
package/src/version.ts CHANGED
@@ -6,7 +6,7 @@ import { join } from 'node:path';
6
6
  // The prebuild script updates the fallback value before compilation.
7
7
  // Uses import.meta.dir (Bun) to locate package.json relative to this file,
8
8
  // which is correct regardless of the process working directory.
9
- let _version = '1.0.39';
9
+ let _version = '1.0.40';
10
10
  try {
11
11
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
12
12
  readonly version?: unknown;