@pellux/goodvibes-agent 1.1.5 → 1.1.6

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,12 @@
2
2
 
3
3
  Product-facing release notes for GoodVibes Agent.
4
4
 
5
+ ## 1.1.6 - 2026-06-05
6
+
7
+ - Fixed Import GoodVibes settings so it also imports active and pending provider subscriptions from the GoodVibes TUI user store into Agent-owned subscription state.
8
+ - Preserved existing Agent-only subscriptions while merging imported provider sessions by provider id.
9
+ - Updated onboarding copy and added regression coverage for subscription import.
10
+
5
11
  ## 1.1.5 - 2026-06-05
6
12
 
7
13
  - Replaced onboarding with the real Agent setup flow for subscription login, provider/model selection, settings persistence, channels, voice, local context, automation, and finish.
@@ -450372,6 +450372,23 @@ 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
+ }
450375
450392
  function rowObject(columns, values2) {
450376
450393
  return Object.fromEntries(columns.map((column, index) => [column, values2[index]]));
450377
450394
  }
@@ -763654,6 +763671,9 @@ var init_ingest = __esm(() => {
763654
763671
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/browser-history/index.js
763655
763672
  var init_browser_history = __esm(() => {
763656
763673
  init_ingest();
763674
+ init_discover();
763675
+ init_readers();
763676
+ init_paths2();
763657
763677
  });
763658
763678
 
763659
763679
  // node_modules/graphql/jsutils/devAssert.mjs
@@ -781293,6 +781313,7 @@ var init_semantic = __esm(() => {
781293
781313
  init_llm();
781294
781314
  init_gap_repair();
781295
781315
  init_service4();
781316
+ init_self_improvement();
781296
781317
  });
781297
781318
 
781298
781319
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/home-graph/helpers.js
@@ -785261,8 +785282,40 @@ var init_map_view = __esm(() => {
785261
785282
  });
785262
785283
 
785263
785284
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/home-graph/types.js
785264
- var HOME_GRAPH_CAPABILITIES;
785285
+ var HOME_GRAPH_NODE_KINDS, HOME_GRAPH_RELATIONS, HOME_GRAPH_CAPABILITIES;
785265
785286
  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
+ ];
785266
785319
  HOME_GRAPH_CAPABILITIES = [
785267
785320
  "knowledge-space-isolation",
785268
785321
  "snapshot-sync",
@@ -786669,6 +786722,7 @@ var init_service5 = __esm(() => {
786669
786722
  var init_home_graph = __esm(() => {
786670
786723
  init_service5();
786671
786724
  init_extension();
786725
+ init_types15();
786672
786726
  });
786673
786727
 
786674
786728
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/store-refinement.js
@@ -788996,10 +789050,14 @@ var init_service6 = __esm(() => {
788996
789050
  var init_project_planning = __esm(() => {
788997
789051
  init_service6();
788998
789052
  init_helpers3();
789053
+ init_readiness();
788999
789054
  });
789000
789055
 
789001
789056
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/persistence.js
789002
- var init_persistence = () => {};
789057
+ var init_persistence = __esm(() => {
789058
+ init_store_schema();
789059
+ init_store_load();
789060
+ });
789003
789061
 
789004
789062
  // node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/projections.js
789005
789063
  class KnowledgeProjectionService {
@@ -792507,21 +792565,21 @@ var init_service7 = __esm(() => {
792507
792565
  var exports_knowledge = {};
792508
792566
  __export(exports_knowledge, {
792509
792567
  withKnowledgeSpace: () => withKnowledgeSpace,
792510
- uniqKnowledgeValues: () => uniq3,
792511
- stabilizeKnowledgeText: () => stableText2,
792512
- runKnowledgeSemanticSelfImprovement: () => runKnowledgeSemanticSelfImprovement2,
792568
+ uniqKnowledgeValues: () => uniq2,
792569
+ stabilizeKnowledgeText: () => stableText,
792570
+ runKnowledgeSemanticSelfImprovement: () => runKnowledgeSemanticSelfImprovement,
792513
792571
  resolveProjectPlanningSpace: () => resolveProjectPlanningSpace,
792514
- resolveKnowledgeDbPathFromControlPlaneDir: () => resolveKnowledgeDbPathFromControlPlaneDir2,
792572
+ resolveKnowledgeDbPathFromControlPlaneDir: () => resolveKnowledgeDbPathFromControlPlaneDir,
792515
792573
  renderPacket: () => renderPacket,
792516
792574
  renderKnowledgeSchemaSql: () => renderKnowledgeSchemaSql,
792517
792575
  renderKnowledgeMap: () => renderKnowledgeMap,
792518
792576
  readKnowledgeSearchText: () => readKnowledgeSearchText,
792519
- readBrowserKnowledgeProfile: () => readBrowserKnowledgeProfile2,
792577
+ readBrowserKnowledgeProfile: () => readBrowserKnowledgeProfile,
792520
792578
  projectPlanningSourceId: () => projectPlanningSourceId,
792521
792579
  projectPlanningProjectIdFromPath: () => projectPlanningProjectIdFromPath,
792522
792580
  projectPlanningCanonicalUri: () => projectPlanningCanonicalUri,
792523
792581
  projectKnowledgeSpaceId: () => projectKnowledgeSpaceId,
792524
- parseKnowledgeJsonValue: () => parseJsonValue2,
792582
+ parseKnowledgeJsonValue: () => parseJsonValue,
792525
792583
  normalizeProjectId: () => normalizeProjectId,
792526
792584
  normalizeKnowledgeSpaceId: () => normalizeKnowledgeSpaceId,
792527
792585
  normalizeHomeAssistantInstallationId: () => normalizeHomeAssistantInstallationId,
@@ -792529,12 +792587,12 @@ __export(exports_knowledge, {
792529
792587
  materializeGeneratedKnowledgeProjection: () => materializeGeneratedKnowledgeProjection,
792530
792588
  looksLikeRawPdfPayload: () => looksLikeRawPdfPayload,
792531
792589
  looksBinaryLikeText: () => looksBinaryLikeText,
792532
- loadKnowledgeStoreSnapshot: () => loadKnowledgeStoreSnapshot2,
792590
+ loadKnowledgeStoreSnapshot: () => loadKnowledgeStoreSnapshot,
792533
792591
  listGeneratedKnowledgePages: () => listGeneratedKnowledgePages,
792534
- listBrowserKinds: () => listBrowserKinds2,
792592
+ listBrowserKinds: () => listBrowserKinds,
792535
792593
  knowledgeSpaceMetadata: () => knowledgeSpaceMetadata,
792536
792594
  knowledgePageSourceWeight: () => knowledgePageSourceWeight,
792537
- knowledgeNowMs: () => nowMs2,
792595
+ knowledgeNowMs: () => nowMs,
792538
792596
  knowledgeExtractionNeedsRefresh: () => knowledgeExtractionNeedsRefresh,
792539
792597
  isUsefulKnowledgePageSourceCandidate: () => isUsefulKnowledgePageSourceCandidate,
792540
792598
  isUsefulKnowledgePageSource: () => isUsefulKnowledgePageSource,
@@ -792554,12 +792612,12 @@ __export(exports_knowledge, {
792554
792612
  generatedKnowledgeSourceId: () => generatedKnowledgeSourceId,
792555
792613
  generatedKnowledgeCanonicalUri: () => generatedKnowledgeCanonicalUri,
792556
792614
  extractKnowledgeArtifact: () => extractKnowledgeArtifact,
792557
- evaluateProjectPlanningReadiness: () => evaluateProjectPlanningReadiness2,
792558
- discoverBrowserKnowledgeProfiles: () => discoverBrowserKnowledgeProfiles2,
792615
+ evaluateProjectPlanningReadiness: () => evaluateProjectPlanningReadiness,
792616
+ discoverBrowserKnowledgeProfiles: () => discoverBrowserKnowledgeProfiles,
792559
792617
  createWebKnowledgeGapRepairer: () => createWebKnowledgeGapRepairer,
792560
792618
  createProviderBackedKnowledgeSemanticLlm: () => createProviderBackedKnowledgeSemanticLlm,
792561
792619
  createMemoryApi: () => createMemoryApi,
792562
- createKnowledgeSchema: () => createSchema3,
792620
+ createKnowledgeSchema: () => createSchema2,
792563
792621
  createKnowledgeApi: () => createKnowledgeApi,
792564
792622
  createDefaultKnowledgeConnectorRegistry: () => createDefaultKnowledgeConnectorRegistry,
792565
792623
  compareKnowledgePageSources: () => compareKnowledgePageSources,
@@ -794998,7 +795056,7 @@ var init_delivery_manager = __esm(() => {
794998
795056
  });
794999
795057
 
795000
795058
  // node_modules/@pellux/goodvibes-sdk/dist/platform/automation/scheduler-capacity.js
795001
- function computeSchedulerCapacity(slotsTotal, runs, nowMs3 = Date.now()) {
795059
+ function computeSchedulerCapacity(slotsTotal, runs, nowMs2 = Date.now()) {
795002
795060
  let slotsInUse = 0;
795003
795061
  const queuedRuns = [];
795004
795062
  for (const run7 of runs) {
@@ -795008,7 +795066,7 @@ function computeSchedulerCapacity(slotsTotal, runs, nowMs3 = Date.now()) {
795008
795066
  queuedRuns.push(run7);
795009
795067
  }
795010
795068
  const queueDepth = queuedRuns.length;
795011
- const oldestQueuedAgeMs = queueDepth > 0 ? nowMs3 - Math.min(...queuedRuns.map((r6) => r6.queuedAt)) : null;
795069
+ const oldestQueuedAgeMs = queueDepth > 0 ? nowMs2 - Math.min(...queuedRuns.map((r6) => r6.queuedAt)) : null;
795012
795070
  return { slotsTotal, slotsInUse, queueDepth, oldestQueuedAgeMs };
795013
795071
  }
795014
795072
 
@@ -817034,7 +817092,7 @@ var createStyledCell = (char, overrides = {}) => ({
817034
817092
  // src/version.ts
817035
817093
  import { readFileSync } from "fs";
817036
817094
  import { join } from "path";
817037
- var _version = "1.1.5";
817095
+ var _version = "1.1.6";
817038
817096
  try {
817039
817097
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf-8"));
817040
817098
  _version = typeof pkg.version === "string" ? pkg.version : _version;
@@ -839547,7 +839605,7 @@ var WORK_PLAN_STATUSES = [
839547
839605
  "failed",
839548
839606
  "cancelled"
839549
839607
  ];
839550
- function nowMs3() {
839608
+ function nowMs2() {
839551
839609
  return Date.now();
839552
839610
  }
839553
839611
  function isObject4(value) {
@@ -839653,7 +839711,7 @@ class WorkPlanStore {
839653
839711
  if (!normalizedTitle)
839654
839712
  throw new Error("Work plan item title is required.");
839655
839713
  const plan = this.readPlan();
839656
- const time4 = nowMs3();
839714
+ const time4 = nowMs2();
839657
839715
  const item = {
839658
839716
  id: createItemId(),
839659
839717
  title: normalizedTitle,
@@ -839677,7 +839735,7 @@ class WorkPlanStore {
839677
839735
  updateItem(idOrPrefix, patch2) {
839678
839736
  const plan = this.readPlan();
839679
839737
  const item = this.resolveItem(plan, idOrPrefix);
839680
- const time4 = nowMs3();
839738
+ const time4 = nowMs2();
839681
839739
  const nextStatus = patch2.status ?? item.status;
839682
839740
  const next = this.pruneItem({
839683
839741
  ...item,
@@ -839710,7 +839768,7 @@ class WorkPlanStore {
839710
839768
  removeItem(idOrPrefix) {
839711
839769
  const plan = this.readPlan();
839712
839770
  const item = this.resolveItem(plan, idOrPrefix);
839713
- const time4 = nowMs3();
839771
+ const time4 = nowMs2();
839714
839772
  const remaining = plan.items.filter((candidate) => candidate.id !== item.id);
839715
839773
  this.writePlan({
839716
839774
  ...plan,
@@ -839730,7 +839788,7 @@ class WorkPlanStore {
839730
839788
  ...plan,
839731
839789
  items: remaining,
839732
839790
  activeItemId: remaining[0]?.id,
839733
- updatedAt: nowMs3()
839791
+ updatedAt: nowMs2()
839734
839792
  });
839735
839793
  return removed;
839736
839794
  }
@@ -839769,7 +839827,7 @@ class WorkPlanStore {
839769
839827
  const parsed = JSON.parse(raw);
839770
839828
  if (!isObject4(parsed))
839771
839829
  return this.createEmptyPlan();
839772
- const time4 = nowMs3();
839830
+ const time4 = nowMs2();
839773
839831
  const createdAt = typeof parsed.createdAt === "number" ? parsed.createdAt : time4;
839774
839832
  const updatedAt = typeof parsed.updatedAt === "number" ? parsed.updatedAt : createdAt;
839775
839833
  const items = Array.isArray(parsed.items) ? parsed.items.map((item) => normalizeItem(item, createdAt)).filter((item) => item !== null) : [];
@@ -839788,7 +839846,7 @@ class WorkPlanStore {
839788
839846
  };
839789
839847
  }
839790
839848
  createEmptyPlan() {
839791
- const time4 = nowMs3();
839849
+ const time4 = nowMs2();
839792
839850
  return {
839793
839851
  id: createPlanId(this.options.projectId, this.options.projectRoot),
839794
839852
  projectId: this.options.projectId,
@@ -890625,7 +890683,7 @@ var AGENT_WORKSPACE_CATEGORIES = [
890625
890683
  summary: "Import preferences, sign in, and choose the main model.",
890626
890684
  detail: "Start here on a fresh install. Every row either saves state, opens the shared model picker, or opens a confirmed in-modal form.",
890627
890685
  actions: [
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" },
890686
+ { id: "import-goodvibes-tui-settings", label: "Import GoodVibes settings", detail: "Copy existing display, provider, subscription, behavior, permission, TTS, channel, helper, tool, release, and automation values into Agent-owned state.", kind: "settings-import", safety: "safe" },
890629
890687
  { 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
890688
  { 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
890689
  { 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" },
@@ -896068,6 +896126,62 @@ function canImportTuiSetting(key) {
896068
896126
  function valuesMatch(left, right) {
896069
896127
  return JSON.stringify(left) === JSON.stringify(right);
896070
896128
  }
896129
+ function readRecordMap(record2, key) {
896130
+ const value = record2[key];
896131
+ return isRecord45(value) ? Object.values(value) : [];
896132
+ }
896133
+ function isProviderSubscription(value) {
896134
+ return isRecord45(value) && typeof value.provider === "string" && typeof value.accessToken === "string" && typeof value.tokenType === "string" && value.authMode === "oauth" && typeof value.overrideAmbientApiKeys === "boolean" && typeof value.createdAt === "number" && typeof value.updatedAt === "number";
896135
+ }
896136
+ function isPendingSubscriptionLogin(value) {
896137
+ return isRecord45(value) && typeof value.provider === "string" && typeof value.state === "string" && typeof value.verifier === "string" && typeof value.redirectUri === "string" && typeof value.createdAt === "number";
896138
+ }
896139
+ function importTuiSubscriptions(context, parseErrors) {
896140
+ const shellPaths3 = context.workspace.shellPaths;
896141
+ const manager5 = context.platform.subscriptionManager;
896142
+ const result2 = {
896143
+ importedActive: [],
896144
+ importedPending: [],
896145
+ unchangedActive: [],
896146
+ unchangedPending: [],
896147
+ skipped: []
896148
+ };
896149
+ if (!shellPaths3 || !manager5)
896150
+ return result2;
896151
+ const sourcePath = shellPaths3.resolveUserPath(GOODVIBES_TUI_SURFACE_ROOT, "subscriptions.json");
896152
+ try {
896153
+ const store2 = readJsonRecord(sourcePath);
896154
+ if (!store2)
896155
+ return result2;
896156
+ for (const entry of readRecordMap(store2, "subscriptions")) {
896157
+ if (!isProviderSubscription(entry)) {
896158
+ result2.skipped.push("active subscription with invalid shape");
896159
+ continue;
896160
+ }
896161
+ if (valuesMatch(manager5.get(entry.provider), entry)) {
896162
+ result2.unchangedActive.push(entry.provider);
896163
+ continue;
896164
+ }
896165
+ manager5.saveSubscription(entry);
896166
+ result2.importedActive.push(entry.provider);
896167
+ }
896168
+ for (const entry of readRecordMap(store2, "pending")) {
896169
+ if (!isPendingSubscriptionLogin(entry)) {
896170
+ result2.skipped.push("pending subscription with invalid shape");
896171
+ continue;
896172
+ }
896173
+ if (valuesMatch(manager5.getPending(entry.provider), entry)) {
896174
+ result2.unchangedPending.push(entry.provider);
896175
+ continue;
896176
+ }
896177
+ manager5.savePending(entry);
896178
+ result2.importedPending.push(entry.provider);
896179
+ }
896180
+ } catch (error53) {
896181
+ parseErrors.push(`subscriptions: ${error53 instanceof Error ? error53.message : String(error53)}`);
896182
+ }
896183
+ return result2;
896184
+ }
896071
896185
  function agentWorkspaceSettingSchema(context, key) {
896072
896186
  return context?.platform?.configManager?.getSchema().find((setting) => setting.key === key) ?? null;
896073
896187
  }
@@ -896171,7 +896285,7 @@ async function applyAgentWorkspaceSettingValue(context, setting, value) {
896171
896285
  async function importAgentWorkspaceTuiSettings(context) {
896172
896286
  const shellPaths3 = context?.workspace?.shellPaths;
896173
896287
  const configManager = context?.platform?.configManager;
896174
- if (!shellPaths3 || !configManager) {
896288
+ if (!context || !shellPaths3 || !configManager) {
896175
896289
  return {
896176
896290
  status: "GoodVibes TUI settings import is unavailable in this runtime.",
896177
896291
  runtimeSnapshot: null,
@@ -896205,8 +896319,11 @@ async function importAgentWorkspaceTuiSettings(context) {
896205
896319
  parseErrors.push(`${source.label}: ${error53 instanceof Error ? error53.message : String(error53)}`);
896206
896320
  }
896207
896321
  }
896208
- if (values2.size === 0) {
896209
- const detail = parseErrors.length > 0 ? `No importable settings found. ${parseErrors.join("; ")}` : "No GoodVibes TUI settings file with importable Agent-owned settings was found.";
896322
+ const subscriptions = importTuiSubscriptions(context, parseErrors);
896323
+ const subscriptionImports = subscriptions.importedActive.length + subscriptions.importedPending.length;
896324
+ const subscriptionUnchanged = subscriptions.unchangedActive.length + subscriptions.unchangedPending.length;
896325
+ if (values2.size === 0 && subscriptionImports === 0 && subscriptionUnchanged === 0 && subscriptions.skipped.length === 0) {
896326
+ const detail = parseErrors.length > 0 ? `No importable settings or subscriptions found. ${parseErrors.join("; ")}` : "No GoodVibes TUI settings or subscription store with importable Agent-owned state was found.";
896210
896327
  return {
896211
896328
  status: "No GoodVibes TUI settings imported.",
896212
896329
  runtimeSnapshot: null,
@@ -896236,15 +896353,20 @@ async function importAgentWorkspaceTuiSettings(context) {
896236
896353
  skipped.push(`${setting.key}: ${error53 instanceof Error ? error53.message : String(error53)}`);
896237
896354
  }
896238
896355
  }
896356
+ skipped.push(...subscriptions.skipped);
896357
+ const changedCount = imported.length + subscriptionImports;
896358
+ const unchangedCount = unchanged.length + subscriptionUnchanged;
896239
896359
  return {
896240
- status: imported.length > 0 ? `Imported ${imported.length} GoodVibes TUI setting(s).` : "No GoodVibes TUI settings changed.",
896360
+ status: changedCount > 0 ? `Imported ${changedCount} GoodVibes TUI item(s).` : "No GoodVibes TUI settings changed.",
896241
896361
  runtimeSnapshot: context ? buildAgentWorkspaceRuntimeSnapshot(context) : null,
896242
896362
  result: {
896243
- kind: skipped.length > 0 && imported.length === 0 ? "error" : imported.length > 0 ? "refreshed" : "guidance",
896244
- title: imported.length > 0 ? "GoodVibes TUI settings imported" : "No settings changed",
896363
+ kind: skipped.length > 0 && changedCount === 0 ? "error" : changedCount > 0 ? "refreshed" : "guidance",
896364
+ title: changedCount > 0 ? "GoodVibes TUI settings imported" : "No settings changed",
896245
896365
  detail: [
896246
896366
  imported.length > 0 ? `Imported: ${imported.slice(0, 10).join(", ")}${imported.length > 10 ? `, +${imported.length - 10} more` : ""}.` : "",
896247
- unchanged.length > 0 ? `${unchanged.length} setting(s) already matched.` : "",
896367
+ subscriptions.importedActive.length > 0 ? `Imported active subscription(s): ${subscriptions.importedActive.join(", ")}.` : "",
896368
+ subscriptions.importedPending.length > 0 ? `Imported pending subscription(s): ${subscriptions.importedPending.join(", ")}.` : "",
896369
+ unchangedCount > 0 ? `${unchangedCount} item(s) already matched.` : "",
896248
896370
  skipped.length > 0 ? `Skipped: ${skipped.slice(0, 5).join("; ")}${skipped.length > 5 ? `; +${skipped.length - 5} more` : ""}.` : "",
896249
896371
  parseErrors.length > 0 ? `Parse issues: ${parseErrors.join("; ")}.` : ""
896250
896372
  ].filter((line2) => line2.length > 0).join(" "),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "1.1.5",
3
+ "version": "1.1.6",
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",
@@ -43,7 +43,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
43
43
  summary: 'Import preferences, sign in, and choose the main model.',
44
44
  detail: 'Start here on a fresh install. Every row either saves state, opens the shared model picker, or opens a confirmed in-modal form.',
45
45
  actions: [
46
- { 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' },
46
+ { id: 'import-goodvibes-tui-settings', label: 'Import GoodVibes settings', detail: 'Copy existing display, provider, subscription, behavior, permission, TTS, channel, helper, tool, release, and automation values into Agent-owned state.', kind: 'settings-import', safety: 'safe' },
47
47
  { 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' },
48
48
  { 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' },
49
49
  { 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' },
@@ -1,5 +1,6 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import type { ConfigKey, ConfigSetting } from '@pellux/goodvibes-sdk/platform/config';
3
+ import type { PendingSubscriptionLogin, ProviderSubscription } from '@pellux/goodvibes-sdk/platform/config';
3
4
  import { setHarnessSetting } from '../agent/harness-control.ts';
4
5
  import { isExternalHostOwnedSettingKey } from '../config/agent-settings-policy.ts';
5
6
  import { buildAgentWorkspaceRuntimeSnapshot } from './agent-workspace-snapshot.ts';
@@ -83,6 +84,83 @@ function valuesMatch(left: unknown, right: unknown): boolean {
83
84
  return JSON.stringify(left) === JSON.stringify(right);
84
85
  }
85
86
 
87
+ function readRecordMap(record: Record<string, unknown>, key: string): readonly unknown[] {
88
+ const value = record[key];
89
+ return isRecord(value) ? Object.values(value) : [];
90
+ }
91
+
92
+ function isProviderSubscription(value: unknown): value is ProviderSubscription {
93
+ return isRecord(value)
94
+ && typeof value.provider === 'string'
95
+ && typeof value.accessToken === 'string'
96
+ && typeof value.tokenType === 'string'
97
+ && value.authMode === 'oauth'
98
+ && typeof value.overrideAmbientApiKeys === 'boolean'
99
+ && typeof value.createdAt === 'number'
100
+ && typeof value.updatedAt === 'number';
101
+ }
102
+
103
+ function isPendingSubscriptionLogin(value: unknown): value is PendingSubscriptionLogin {
104
+ return isRecord(value)
105
+ && typeof value.provider === 'string'
106
+ && typeof value.state === 'string'
107
+ && typeof value.verifier === 'string'
108
+ && typeof value.redirectUri === 'string'
109
+ && typeof value.createdAt === 'number';
110
+ }
111
+
112
+ function importTuiSubscriptions(context: CommandContext, parseErrors: string[]): {
113
+ readonly importedActive: string[];
114
+ readonly importedPending: string[];
115
+ readonly unchangedActive: string[];
116
+ readonly unchangedPending: string[];
117
+ readonly skipped: string[];
118
+ } {
119
+ const shellPaths = context.workspace.shellPaths;
120
+ const manager = context.platform.subscriptionManager;
121
+ const result = {
122
+ importedActive: [] as string[],
123
+ importedPending: [] as string[],
124
+ unchangedActive: [] as string[],
125
+ unchangedPending: [] as string[],
126
+ skipped: [] as string[],
127
+ };
128
+ if (!shellPaths || !manager) return result;
129
+
130
+ const sourcePath = shellPaths.resolveUserPath(GOODVIBES_TUI_SURFACE_ROOT, 'subscriptions.json');
131
+ try {
132
+ const store = readJsonRecord(sourcePath);
133
+ if (!store) return result;
134
+ for (const entry of readRecordMap(store, 'subscriptions')) {
135
+ if (!isProviderSubscription(entry)) {
136
+ result.skipped.push('active subscription with invalid shape');
137
+ continue;
138
+ }
139
+ if (valuesMatch(manager.get(entry.provider), entry)) {
140
+ result.unchangedActive.push(entry.provider);
141
+ continue;
142
+ }
143
+ manager.saveSubscription(entry);
144
+ result.importedActive.push(entry.provider);
145
+ }
146
+ for (const entry of readRecordMap(store, 'pending')) {
147
+ if (!isPendingSubscriptionLogin(entry)) {
148
+ result.skipped.push('pending subscription with invalid shape');
149
+ continue;
150
+ }
151
+ if (valuesMatch(manager.getPending(entry.provider), entry)) {
152
+ result.unchangedPending.push(entry.provider);
153
+ continue;
154
+ }
155
+ manager.savePending(entry);
156
+ result.importedPending.push(entry.provider);
157
+ }
158
+ } catch (error) {
159
+ parseErrors.push(`subscriptions: ${error instanceof Error ? error.message : String(error)}`);
160
+ }
161
+ return result;
162
+ }
163
+
86
164
  export function agentWorkspaceSettingSchema(context: CommandContext | null, key: string): ConfigSetting | null {
87
165
  return context?.platform?.configManager
88
166
  ?.getSchema()
@@ -200,7 +278,7 @@ export async function applyAgentWorkspaceSettingValue(
200
278
  export async function importAgentWorkspaceTuiSettings(context: CommandContext | null): Promise<TuiSettingsImportOutcome> {
201
279
  const shellPaths = context?.workspace?.shellPaths;
202
280
  const configManager = context?.platform?.configManager;
203
- if (!shellPaths || !configManager) {
281
+ if (!context || !shellPaths || !configManager) {
204
282
  return {
205
283
  status: 'GoodVibes TUI settings import is unavailable in this runtime.',
206
284
  runtimeSnapshot: null,
@@ -232,11 +310,14 @@ export async function importAgentWorkspaceTuiSettings(context: CommandContext |
232
310
  parseErrors.push(`${source.label}: ${error instanceof Error ? error.message : String(error)}`);
233
311
  }
234
312
  }
313
+ const subscriptions = importTuiSubscriptions(context, parseErrors);
314
+ const subscriptionImports = subscriptions.importedActive.length + subscriptions.importedPending.length;
315
+ const subscriptionUnchanged = subscriptions.unchangedActive.length + subscriptions.unchangedPending.length;
235
316
 
236
- if (values.size === 0) {
317
+ if (values.size === 0 && subscriptionImports === 0 && subscriptionUnchanged === 0 && subscriptions.skipped.length === 0) {
237
318
  const detail = parseErrors.length > 0
238
- ? `No importable settings found. ${parseErrors.join('; ')}`
239
- : 'No GoodVibes TUI settings file with importable Agent-owned settings was found.';
319
+ ? `No importable settings or subscriptions found. ${parseErrors.join('; ')}`
320
+ : 'No GoodVibes TUI settings or subscription store with importable Agent-owned state was found.';
240
321
  return {
241
322
  status: 'No GoodVibes TUI settings imported.',
242
323
  runtimeSnapshot: null,
@@ -266,16 +347,21 @@ export async function importAgentWorkspaceTuiSettings(context: CommandContext |
266
347
  skipped.push(`${setting.key}: ${error instanceof Error ? error.message : String(error)}`);
267
348
  }
268
349
  }
350
+ skipped.push(...subscriptions.skipped);
351
+ const changedCount = imported.length + subscriptionImports;
352
+ const unchangedCount = unchanged.length + subscriptionUnchanged;
269
353
 
270
354
  return {
271
- status: imported.length > 0 ? `Imported ${imported.length} GoodVibes TUI setting(s).` : 'No GoodVibes TUI settings changed.',
355
+ status: changedCount > 0 ? `Imported ${changedCount} GoodVibes TUI item(s).` : 'No GoodVibes TUI settings changed.',
272
356
  runtimeSnapshot: context ? buildAgentWorkspaceRuntimeSnapshot(context) : null,
273
357
  result: {
274
- kind: skipped.length > 0 && imported.length === 0 ? 'error' : imported.length > 0 ? 'refreshed' : 'guidance',
275
- title: imported.length > 0 ? 'GoodVibes TUI settings imported' : 'No settings changed',
358
+ kind: skipped.length > 0 && changedCount === 0 ? 'error' : changedCount > 0 ? 'refreshed' : 'guidance',
359
+ title: changedCount > 0 ? 'GoodVibes TUI settings imported' : 'No settings changed',
276
360
  detail: [
277
361
  imported.length > 0 ? `Imported: ${imported.slice(0, 10).join(', ')}${imported.length > 10 ? `, +${imported.length - 10} more` : ''}.` : '',
278
- unchanged.length > 0 ? `${unchanged.length} setting(s) already matched.` : '',
362
+ subscriptions.importedActive.length > 0 ? `Imported active subscription(s): ${subscriptions.importedActive.join(', ')}.` : '',
363
+ subscriptions.importedPending.length > 0 ? `Imported pending subscription(s): ${subscriptions.importedPending.join(', ')}.` : '',
364
+ unchangedCount > 0 ? `${unchangedCount} item(s) already matched.` : '',
279
365
  skipped.length > 0 ? `Skipped: ${skipped.slice(0, 5).join('; ')}${skipped.length > 5 ? `; +${skipped.length - 5} more` : ''}.` : '',
280
366
  parseErrors.length > 0 ? `Parse issues: ${parseErrors.join('; ')}.` : '',
281
367
  ].filter((line) => line.length > 0).join(' '),
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.1.5';
9
+ let _version = '1.1.6';
10
10
  try {
11
11
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
12
12
  readonly version?: unknown;