@pellux/goodvibes-agent 1.0.44 → 1.1.1

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,14 @@
2
2
 
3
3
  Product-facing release notes for GoodVibes Agent.
4
4
 
5
+ ## 1.1.1 - 2026-06-05
6
+
7
+ - Fix first-run onboarding so clean launches open the fullscreen setup workspace until the user explicitly chooses Finish -> Apply & close.
8
+
9
+ ## 1.1.0 - 2026-06-05
10
+
11
+ - Add a final onboarding Finish category with Apply & close completion that saves the user onboarding marker and keeps future normal launches in the main conversation.
12
+
5
13
  ## 1.0.44 - 2026-06-05
6
14
 
7
15
  - Compact Agent workspace top-pane copy across every category so the fullscreen onboarding surface keeps settings and actions visible.
@@ -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
 
@@ -817087,7 +817145,7 @@ var createStyledCell = (char, overrides = {}) => ({
817087
817145
  // src/version.ts
817088
817146
  import { readFileSync } from "fs";
817089
817147
  import { join } from "path";
817090
- var _version = "1.0.44";
817148
+ var _version = "1.1.1";
817091
817149
  try {
817092
817150
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf-8"));
817093
817151
  _version = typeof pkg.version === "string" ? pkg.version : _version;
@@ -839600,7 +839658,7 @@ var WORK_PLAN_STATUSES = [
839600
839658
  "failed",
839601
839659
  "cancelled"
839602
839660
  ];
839603
- function nowMs3() {
839661
+ function nowMs2() {
839604
839662
  return Date.now();
839605
839663
  }
839606
839664
  function isObject4(value) {
@@ -839706,7 +839764,7 @@ class WorkPlanStore {
839706
839764
  if (!normalizedTitle)
839707
839765
  throw new Error("Work plan item title is required.");
839708
839766
  const plan = this.readPlan();
839709
- const time4 = nowMs3();
839767
+ const time4 = nowMs2();
839710
839768
  const item = {
839711
839769
  id: createItemId(),
839712
839770
  title: normalizedTitle,
@@ -839730,7 +839788,7 @@ class WorkPlanStore {
839730
839788
  updateItem(idOrPrefix, patch2) {
839731
839789
  const plan = this.readPlan();
839732
839790
  const item = this.resolveItem(plan, idOrPrefix);
839733
- const time4 = nowMs3();
839791
+ const time4 = nowMs2();
839734
839792
  const nextStatus = patch2.status ?? item.status;
839735
839793
  const next = this.pruneItem({
839736
839794
  ...item,
@@ -839763,7 +839821,7 @@ class WorkPlanStore {
839763
839821
  removeItem(idOrPrefix) {
839764
839822
  const plan = this.readPlan();
839765
839823
  const item = this.resolveItem(plan, idOrPrefix);
839766
- const time4 = nowMs3();
839824
+ const time4 = nowMs2();
839767
839825
  const remaining = plan.items.filter((candidate) => candidate.id !== item.id);
839768
839826
  this.writePlan({
839769
839827
  ...plan,
@@ -839783,7 +839841,7 @@ class WorkPlanStore {
839783
839841
  ...plan,
839784
839842
  items: remaining,
839785
839843
  activeItemId: remaining[0]?.id,
839786
- updatedAt: nowMs3()
839844
+ updatedAt: nowMs2()
839787
839845
  });
839788
839846
  return removed;
839789
839847
  }
@@ -839822,7 +839880,7 @@ class WorkPlanStore {
839822
839880
  const parsed = JSON.parse(raw);
839823
839881
  if (!isObject4(parsed))
839824
839882
  return this.createEmptyPlan();
839825
- const time4 = nowMs3();
839883
+ const time4 = nowMs2();
839826
839884
  const createdAt = typeof parsed.createdAt === "number" ? parsed.createdAt : time4;
839827
839885
  const updatedAt = typeof parsed.updatedAt === "number" ? parsed.updatedAt : createdAt;
839828
839886
  const items = Array.isArray(parsed.items) ? parsed.items.map((item) => normalizeItem(item, createdAt)).filter((item) => item !== null) : [];
@@ -839841,7 +839899,7 @@ class WorkPlanStore {
839841
839899
  };
839842
839900
  }
839843
839901
  createEmptyPlan() {
839844
- const time4 = nowMs3();
839902
+ const time4 = nowMs2();
839845
839903
  return {
839846
839904
  id: createPlanId(this.options.projectId, this.options.projectRoot),
839847
839905
  projectId: this.options.projectId,
@@ -849793,13 +849851,13 @@ init_state3();
849793
849851
 
849794
849852
  // src/input/commands/recall-shared.ts
849795
849853
  var VALID_CLASSES = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
849796
- var VALID_SCOPES = ["session", "project", "team"];
849854
+ var VALID_SCOPES2 = ["session", "project", "team"];
849797
849855
  var VALID_REVIEW_STATES = ["fresh", "reviewed", "stale", "contradicted"];
849798
849856
  function isValidClass(s4) {
849799
849857
  return VALID_CLASSES.includes(s4);
849800
849858
  }
849801
849859
  function isValidScope(s4) {
849802
- return VALID_SCOPES.includes(s4);
849860
+ return VALID_SCOPES2.includes(s4);
849803
849861
  }
849804
849862
  function isValidReviewState(s4) {
849805
849863
  return VALID_REVIEW_STATES.includes(s4);
@@ -849842,7 +849900,7 @@ function handleRecallSearch(args2, context) {
849842
849900
  if (isValidScope(scope))
849843
849901
  filter.scope = scope;
849844
849902
  else {
849845
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
849903
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
849846
849904
  return;
849847
849905
  }
849848
849906
  }
@@ -850017,7 +850075,7 @@ function handleRecallList(args2, context) {
850017
850075
  if (scopeIdx !== -1 && args2[scopeIdx + 1]) {
850018
850076
  const scope = args2[scopeIdx + 1];
850019
850077
  if (!isValidScope(scope)) {
850020
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
850078
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850021
850079
  return;
850022
850080
  }
850023
850081
  filter.scope = scope;
@@ -850067,7 +850125,7 @@ async function handleRecallAdd(args2, context) {
850067
850125
  const tags = tagsRaw ? tagsRaw.split(",").map((token) => token.trim()).filter(Boolean) : [];
850068
850126
  const scope = scopeRaw && isValidScope(scopeRaw) ? scopeRaw : "project";
850069
850127
  if (scopeRaw && !isValidScope(scopeRaw)) {
850070
- context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES.join(", ")}.`);
850128
+ context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850071
850129
  return;
850072
850130
  }
850073
850131
  const provenance = [];
@@ -850201,7 +850259,7 @@ function handleRecallExport(args2, context) {
850201
850259
  if (scopeIdx !== -1 && commandArgs[scopeIdx + 1]) {
850202
850260
  const scope = commandArgs[scopeIdx + 1];
850203
850261
  if (!isValidScope(scope)) {
850204
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
850262
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850205
850263
  return;
850206
850264
  }
850207
850265
  filter.scope = scope;
@@ -850280,7 +850338,7 @@ function handleRecallHandoffExport(args2, context) {
850280
850338
  const scopeIdx = commandArgs.indexOf("--scope");
850281
850339
  const scopeRaw = scopeIdx !== -1 ? commandArgs[scopeIdx + 1] : "team";
850282
850340
  if (!scopeRaw || !isValidScope(scopeRaw)) {
850283
- context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES.join(", ")}.`);
850341
+ context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850284
850342
  return;
850285
850343
  }
850286
850344
  const bundle = memory.exportBundle({ scope: scopeRaw });
@@ -850396,7 +850454,7 @@ function handleRecallPromote(args2, context) {
850396
850454
  const id = parsed.rest[0];
850397
850455
  const scope = parsed.rest[1];
850398
850456
  if (!id || !scope || !isValidScope(scope)) {
850399
- context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES.join("|")}> --yes`);
850457
+ context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES2.join("|")}> --yes`);
850400
850458
  return;
850401
850459
  }
850402
850460
  if (!parsed.yes) {
@@ -858574,7 +858632,8 @@ var AGENT_WORKSPACE_CATEGORY_IDS = [
858574
858632
  "work",
858575
858633
  "host",
858576
858634
  "automation",
858577
- "delegate"
858635
+ "delegate",
858636
+ "finish"
858578
858637
  ];
858579
858638
 
858580
858639
  // src/input/commands/agent-workspace-runtime.ts
@@ -863014,7 +863073,7 @@ function registerBriefRuntimeCommands(registry5) {
863014
863073
 
863015
863074
  // src/cli/bundle-command.ts
863016
863075
  import { existsSync as existsSync80, mkdirSync as mkdirSync64, readFileSync as readFileSync87, writeFileSync as writeFileSync55 } from "fs";
863017
- import { dirname as dirname61 } from "path";
863076
+ import { dirname as dirname62 } from "path";
863018
863077
  // src/runtime/onboarding/state.ts
863019
863078
  import { existsSync as existsSync76, mkdirSync as mkdirSync62, readFileSync as readFileSync84, writeFileSync as writeFileSync53 } from "fs";
863020
863079
  var ONBOARDING_RUNTIME_STATE_FILE = "onboarding-state.json";
@@ -863659,9 +863718,11 @@ function deriveStep1CapabilityFlags(snapshot) {
863659
863718
  }
863660
863719
  // src/runtime/onboarding/markers.ts
863661
863720
  import { existsSync as existsSync77, mkdirSync as mkdirSync63, readFileSync as readFileSync85, writeFileSync as writeFileSync54 } from "fs";
863721
+ import { dirname as dirname60 } from "path";
863662
863722
  var ONBOARDING_CHECK_MARKER_FILE = "onboarding-checked.json";
863663
- function resolveMarkerPath(shellPaths, scope) {
863664
- return scope === "project" ? shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, ONBOARDING_CHECK_MARKER_FILE) : shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, ONBOARDING_CHECK_MARKER_FILE);
863723
+ var ONBOARDING_COMPLETION_MARKER_FILE = "onboarding-complete.json";
863724
+ function resolveMarkerPath(shellPaths, scope, fileName = ONBOARDING_CHECK_MARKER_FILE) {
863725
+ return scope === "project" ? shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, fileName) : shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, fileName);
863665
863726
  }
863666
863727
  function isObject6(value) {
863667
863728
  return typeof value === "object" && value !== null;
@@ -863699,8 +863760,8 @@ function pickEffectiveMarker(user) {
863699
863760
  function getOnboardingCheckMarkerPath(shellPaths, scope = "user") {
863700
863761
  return resolveMarkerPath(shellPaths, scope);
863701
863762
  }
863702
- function readOnboardingCheckMarker(shellPaths, scope = "user") {
863703
- const path7 = resolveMarkerPath(shellPaths, scope);
863763
+ function readOnboardingMarker(shellPaths, scope, fileName) {
863764
+ const path7 = resolveMarkerPath(shellPaths, scope, fileName);
863704
863765
  if (!existsSync77(path7))
863705
863766
  return buildMissingMarkerState(scope, path7);
863706
863767
  try {
@@ -863719,6 +863780,12 @@ function readOnboardingCheckMarker(shellPaths, scope = "user") {
863719
863780
  return buildParseErrorState(scope, path7, parseError);
863720
863781
  }
863721
863782
  }
863783
+ function readOnboardingCheckMarker(shellPaths, scope = "user") {
863784
+ return readOnboardingMarker(shellPaths, scope, ONBOARDING_CHECK_MARKER_FILE);
863785
+ }
863786
+ function readOnboardingCompletionMarker(shellPaths, scope = "user") {
863787
+ return readOnboardingMarker(shellPaths, scope, ONBOARDING_COMPLETION_MARKER_FILE);
863788
+ }
863722
863789
  function readOnboardingCheckMarkers(shellPaths) {
863723
863790
  const user = readOnboardingCheckMarker(shellPaths, "user");
863724
863791
  const project = readOnboardingCheckMarker(shellPaths, "project");
@@ -863728,9 +863795,32 @@ function readOnboardingCheckMarkers(shellPaths) {
863728
863795
  effective: pickEffectiveMarker(user)
863729
863796
  };
863730
863797
  }
863798
+ function writeOnboardingMarker(shellPaths, options, fileName) {
863799
+ const scope = options.scope ?? "user";
863800
+ const path7 = resolveMarkerPath(shellPaths, scope, fileName);
863801
+ const checkedAt = options.checkedAt ?? Date.now();
863802
+ const payload = {
863803
+ version: 1,
863804
+ checkedAt,
863805
+ updatedAt: options.updatedAt ?? checkedAt,
863806
+ source: options.source ?? "wizard",
863807
+ ...options.mode ? { mode: options.mode } : {},
863808
+ ...options.workspaceRoot ? { workspaceRoot: options.workspaceRoot } : {}
863809
+ };
863810
+ mkdirSync63(dirname60(path7), { recursive: true });
863811
+ writeFileSync54(path7, `${JSON.stringify(payload, null, 2)}
863812
+ `, "utf-8");
863813
+ return readOnboardingMarker(shellPaths, scope, fileName);
863814
+ }
863815
+ function writeOnboardingCheckMarker(shellPaths, options = {}) {
863816
+ return writeOnboardingMarker(shellPaths, options, ONBOARDING_CHECK_MARKER_FILE);
863817
+ }
863818
+ function writeOnboardingCompletionMarker(shellPaths, options = {}) {
863819
+ return writeOnboardingMarker(shellPaths, options, ONBOARDING_COMPLETION_MARKER_FILE);
863820
+ }
863731
863821
  // src/cli/help.ts
863732
863822
  import { existsSync as existsSync78, readFileSync as readFileSync86 } from "fs";
863733
- import { dirname as dirname60, join as join93 } from "path";
863823
+ import { dirname as dirname61, join as join93 } from "path";
863734
863824
  import { fileURLToPath as fileURLToPath4 } from "url";
863735
863825
  function readJsonVersion(path7) {
863736
863826
  try {
@@ -863743,7 +863833,7 @@ function readJsonVersion(path7) {
863743
863833
  }
863744
863834
  }
863745
863835
  function getPackageVersion() {
863746
- const here = dirname60(fileURLToPath4(import.meta.url));
863836
+ const here = dirname61(fileURLToPath4(import.meta.url));
863747
863837
  return readJsonVersion(join93(here, "..", "..", "package.json")) ?? VERSION;
863748
863838
  }
863749
863839
  function renderGoodVibesVersion(binary2 = "goodvibes-agent") {
@@ -864687,7 +864777,7 @@ async function handleBundleCommand(runtime2) {
864687
864777
  }
864688
864778
  };
864689
864779
  const targetPath = shellPaths.resolveWorkspacePath(outputPath);
864690
- mkdirSync64(dirname61(targetPath), { recursive: true });
864780
+ mkdirSync64(dirname62(targetPath), { recursive: true });
864691
864781
  writeFileSync55(targetPath, redactSerializedSecrets(JSON.stringify(bundle, null, 2), sensitiveValues) + `
864692
864782
  `, "utf-8");
864693
864783
  return {
@@ -865305,7 +865395,7 @@ function formatProviderAuthRoute(route) {
865305
865395
 
865306
865396
  // src/cli/management-commands.ts
865307
865397
  import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync56 } from "fs";
865308
- import { dirname as dirname62 } from "path";
865398
+ import { dirname as dirname63 } from "path";
865309
865399
  init_config8();
865310
865400
  init_config8();
865311
865401
  init_config8();
@@ -865615,7 +865705,7 @@ async function handleSessions(runtime2) {
865615
865705
  `;
865616
865706
  if (outputPath) {
865617
865707
  const targetPath = services.shellPaths.resolveWorkspacePath(outputPath);
865618
- mkdirSync65(dirname62(targetPath), { recursive: true });
865708
+ mkdirSync65(dirname63(targetPath), { recursive: true });
865619
865709
  writeFileSync56(targetPath, text, "utf-8");
865620
865710
  return [
865621
865711
  "Session exported",
@@ -866498,10 +866588,10 @@ Run goodvibes-agent skills discover to inspect available skill files.`, 1);
866498
866588
 
866499
866589
  // src/cli/memory-command.ts
866500
866590
  import { mkdirSync as mkdirSync66, readFileSync as readFileSync88, writeFileSync as writeFileSync57 } from "fs";
866501
- import { dirname as dirname63, resolve as resolve39 } from "path";
866591
+ import { dirname as dirname64, resolve as resolve39 } from "path";
866502
866592
  init_state3();
866503
866593
  var VALID_CLASSES2 = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
866504
- var VALID_SCOPES3 = ["session", "project", "team"];
866594
+ var VALID_SCOPES4 = ["session", "project", "team"];
866505
866595
  var VALID_REVIEW_STATES3 = ["fresh", "reviewed", "stale", "contradicted"];
866506
866596
  var VALID_PROVENANCE_KINDS = ["session", "turn", "task", "event", "file"];
866507
866597
  var VALUE_OPTIONS = new Set([
@@ -866601,7 +866691,7 @@ function isMemoryClass2(value) {
866601
866691
  return VALID_CLASSES2.includes(value);
866602
866692
  }
866603
866693
  function isMemoryScope2(value) {
866604
- return VALID_SCOPES3.includes(value);
866694
+ return VALID_SCOPES4.includes(value);
866605
866695
  }
866606
866696
  function isReviewState(value) {
866607
866697
  return VALID_REVIEW_STATES3.includes(value);
@@ -866616,7 +866706,7 @@ function requireClass(value) {
866616
866706
  }
866617
866707
  function requireScope(value) {
866618
866708
  if (!value || !isMemoryScope2(value))
866619
- throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES3.join(", ")}`);
866709
+ throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES4.join(", ")}`);
866620
866710
  return value;
866621
866711
  }
866622
866712
  function optionalScope(value) {
@@ -866794,7 +866884,7 @@ function resolvePath4(runtime2, path7) {
866794
866884
  return resolve39(runtime2.workingDirectory, path7);
866795
866885
  }
866796
866886
  function writeBundle(path7, bundle) {
866797
- mkdirSync66(dirname63(path7), { recursive: true });
866887
+ mkdirSync66(dirname64(path7), { recursive: true });
866798
866888
  writeFileSync57(path7, `${JSON.stringify(bundle, null, 2)}
866799
866889
  `);
866800
866890
  }
@@ -883827,7 +883917,7 @@ function describeHarnessDelegationRoute(context, args2) {
883827
883917
 
883828
883918
  // src/tools/agent-harness-keybinding-metadata.ts
883829
883919
  import { existsSync as existsSync83, mkdirSync as mkdirSync68, readFileSync as readFileSync90, writeFileSync as writeFileSync59 } from "fs";
883830
- import { dirname as dirname64 } from "path";
883920
+ import { dirname as dirname65 } from "path";
883831
883921
  var FIXED_SHORTCUTS = [
883832
883922
  { key: "Enter", description: "Send prompt" },
883833
883923
  { key: "Shift+Enter / Ctrl+J", description: "Insert newline" },
@@ -884207,7 +884297,7 @@ function readOverrideFile(configPath) {
884207
884297
  return parsed;
884208
884298
  }
884209
884299
  function writeOverrideFile(configPath, overrides) {
884210
- mkdirSync68(dirname64(configPath), { recursive: true });
884300
+ mkdirSync68(dirname65(configPath), { recursive: true });
884211
884301
  writeFileSync59(configPath, `${JSON.stringify(overrides, null, 2)}
884212
884302
  `, "utf-8");
884213
884303
  }
@@ -890239,6 +890329,10 @@ function activateAgentWorkspaceSelection(workspace, requestRender) {
890239
890329
  workspace.applyLocalLibraryOperation(action2.localOperation);
890240
890330
  return;
890241
890331
  }
890332
+ if (action2.kind === "onboarding-complete") {
890333
+ workspace.completeOnboarding();
890334
+ return;
890335
+ }
890242
890336
  if (action2.kind === "guidance" || !action2.command) {
890243
890337
  handleGuidanceOrWorkspaceAction(workspace, action2);
890244
890338
  return;
@@ -890965,6 +891059,17 @@ var AGENT_WORKSPACE_CATEGORIES = [
890965
891059
  { id: "review-command", label: "Review delegation command", detail: "Use the confirmed delegation form only when the user explicitly asks for code review/build execution. Include the actual task text, preserve the full original ask, and request delegated review only when asked.", kind: "guidance", safety: "delegates" },
890966
891060
  { id: "delegation-status", label: "Delegation status", detail: "Inspect build-delegation receipts and shared-session status without starting coding work.", command: "/delegate status", kind: "command", safety: "read-only" }
890967
891061
  ]
891062
+ },
891063
+ {
891064
+ id: "finish",
891065
+ group: "FINISH",
891066
+ label: "Finish",
891067
+ summary: "Acknowledge setup and close onboarding.",
891068
+ detail: "Use this final step after reviewing setup. Apply & close writes the user onboarding completion marker so normal future launches start in the main conversation.",
891069
+ actions: [
891070
+ { id: "onboarding-apply-close", label: "Apply & close", detail: "Acknowledge onboarding as finished, persist the user completion marker, and close the fullscreen Agent workspace.", kind: "onboarding-complete", safety: "safe" },
891071
+ { id: "finish-review-setup", label: "Review setup first", detail: "Jump back to setup before acknowledging onboarding as finished.", targetCategoryId: "setup", kind: "workspace", safety: "safe" }
891072
+ ]
890968
891073
  }
890969
891074
  ];
890970
891075
 
@@ -895834,6 +895939,47 @@ class AgentWorkspace {
895834
895939
  openDeleteEditor: (kind2, selected) => this.openDeleteEditor(kind2, selected)
895835
895940
  });
895836
895941
  }
895942
+ completeOnboarding() {
895943
+ const shellPaths3 = this.context?.workspace?.shellPaths;
895944
+ if (!shellPaths3) {
895945
+ this.status = "Cannot complete onboarding without Agent shell paths.";
895946
+ this.lastActionResult = {
895947
+ kind: "error",
895948
+ title: "Onboarding completion unavailable",
895949
+ detail: "The Agent workspace cannot locate the user onboarding completion marker path for this runtime.",
895950
+ safety: "safe"
895951
+ };
895952
+ return;
895953
+ }
895954
+ try {
895955
+ const marker = {
895956
+ scope: "user",
895957
+ source: "wizard",
895958
+ mode: "new",
895959
+ workspaceRoot: shellPaths3.workingDirectory
895960
+ };
895961
+ writeOnboardingCheckMarker(shellPaths3, marker);
895962
+ writeOnboardingCompletionMarker(shellPaths3, marker);
895963
+ this.status = "Onboarding applied and closed.";
895964
+ this.lastActionResult = {
895965
+ kind: "refreshed",
895966
+ title: "Onboarding complete",
895967
+ detail: "Saved the user onboarding completion marker. Future normal launches start in the main conversation.",
895968
+ safety: "safe"
895969
+ };
895970
+ if (!this.context?.dismissAgentWorkspace?.())
895971
+ this.close();
895972
+ } catch (error53) {
895973
+ const detail = error53 instanceof Error ? error53.message : String(error53);
895974
+ this.status = "Onboarding completion failed.";
895975
+ this.lastActionResult = {
895976
+ kind: "error",
895977
+ title: "Onboarding completion failed",
895978
+ detail,
895979
+ safety: "safe"
895980
+ };
895981
+ }
895982
+ }
895837
895983
  selectedItemForOperation(operation) {
895838
895984
  if (operation.startsWith("memory-"))
895839
895985
  return this.selectedLocalLibraryItem("memory");
@@ -902437,6 +902583,8 @@ function snapshotLines(workspace, category, snapshot2) {
902437
902583
  base2.push({ text: `Automation: ${ready.length} schedule-ready routine(s); receipts ${snapshot2.routineScheduleReceiptCount}.`, fg: ready.length > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, automationNextActionLine(snapshot2), compactRoutineReceiptLine(snapshot2), { text: "Reminders and routine promotion require confirmation.", fg: FULLSCREEN_PALETTE.warn });
902438
902584
  } else if (category.id === "delegate") {
902439
902585
  base2.push({ text: "Build/fix/review work is handed to GoodVibes TUI.", fg: FULLSCREEN_PALETTE.info }, { text: `Delegated review policy: ${snapshot2.delegatedReviewPolicy}`, fg: FULLSCREEN_PALETTE.warn }, { text: "No coding-role Agent jobs are created here.", fg: FULLSCREEN_PALETTE.good });
902586
+ } else if (category.id === "finish") {
902587
+ base2.push({ text: "Apply & close marks onboarding finished for this user.", fg: FULLSCREEN_PALETTE.good }, { text: "Future normal launches start in the main conversation.", fg: FULLSCREEN_PALETTE.info }, { text: "Use /agent, /setup, or /onboarding to reopen this workspace later.", fg: FULLSCREEN_PALETTE.muted });
902440
902588
  }
902441
902589
  if (snapshot2.warnings.length > 0) {
902442
902590
  base2.push({ text: `Warnings: ${snapshot2.warnings.map((warning) => compactText3(warning, 60)).join("; ")}`, fg: FULLSCREEN_PALETTE.warn });
@@ -903756,7 +903904,7 @@ function getInteractiveTerminalLaunchError(input) {
903756
903904
  }
903757
903905
  function applyInitialTuiCliState(options) {
903758
903906
  const { cli, input, commandRegistry, commandContext, shellPaths: shellPaths3, render } = options;
903759
- const globalOnboardingMarker = readOnboardingCheckMarker(shellPaths3, "user");
903907
+ const onboardingCompletionMarker = readOnboardingCompletionMarker(shellPaths3, "user");
903760
903908
  const seededPrompt = cli.flags.prompt ?? (cli.rawCommand === undefined && cli.positionals.length > 0 ? cli.positionals.join(" ") : undefined);
903761
903909
  if (cli.command === "onboarding") {
903762
903910
  input.openAgentWorkspace(commandContext);
@@ -903765,10 +903913,8 @@ function applyInitialTuiCliState(options) {
903765
903913
  if (target) {
903766
903914
  commandRegistry.execute("session", ["resume", target], commandContext).then(() => render());
903767
903915
  }
903768
- } else if (!globalOnboardingMarker.exists) {
903769
- input.openAgentWorkspace(commandContext);
903770
- } else if (cli.command === "tui" && seededPrompt === undefined) {
903771
- input.openAgentWorkspace(commandContext);
903916
+ } else if (!onboardingCompletionMarker.payload) {
903917
+ input.openAgentWorkspace(commandContext, "setup");
903772
903918
  }
903773
903919
  if (seededPrompt) {
903774
903920
  input.prompt = seededPrompt;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "1.0.44",
3
+ "version": "1.1.1",
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",
@@ -1,6 +1,6 @@
1
1
  import type { CommandContext, CommandRegistry } from '../input/command-registry.ts';
2
2
  import type { InputHandler } from '../input/handler.ts';
3
- import { readOnboardingCheckMarker } from '../runtime/onboarding/index.ts';
3
+ import { readOnboardingCompletionMarker } from '../runtime/onboarding/index.ts';
4
4
  import type { GoodVibesCliParseResult } from './types.ts';
5
5
 
6
6
  export type InteractiveTerminalCheckInput = {
@@ -95,11 +95,11 @@ export function applyInitialTuiCliState(options: {
95
95
  readonly input: InputHandler;
96
96
  readonly commandRegistry: CommandRegistry;
97
97
  readonly commandContext: CommandContext;
98
- readonly shellPaths: Parameters<typeof readOnboardingCheckMarker>[0];
98
+ readonly shellPaths: Parameters<typeof readOnboardingCompletionMarker>[0];
99
99
  readonly render: () => void;
100
100
  }): void {
101
101
  const { cli, input, commandRegistry, commandContext, shellPaths, render } = options;
102
- const globalOnboardingMarker = readOnboardingCheckMarker(shellPaths, 'user');
102
+ const onboardingCompletionMarker = readOnboardingCompletionMarker(shellPaths, 'user');
103
103
  const seededPrompt = cli.flags.prompt ?? (cli.rawCommand === undefined && cli.positionals.length > 0 ? cli.positionals.join(' ') : undefined);
104
104
  if (cli.command === 'onboarding') {
105
105
  input.openAgentWorkspace(commandContext);
@@ -108,10 +108,8 @@ export function applyInitialTuiCliState(options: {
108
108
  if (target) {
109
109
  void commandRegistry.execute('session', ['resume', target], commandContext).then(() => render());
110
110
  }
111
- } else if (!globalOnboardingMarker.exists) {
112
- input.openAgentWorkspace(commandContext);
113
- } else if (cli.command === 'tui' && seededPrompt === undefined) {
114
- input.openAgentWorkspace(commandContext);
111
+ } else if (!onboardingCompletionMarker.payload) {
112
+ input.openAgentWorkspace(commandContext, 'setup');
115
113
  }
116
114
 
117
115
  if (seededPrompt) {
@@ -36,6 +36,7 @@ interface AgentWorkspaceActivationHost {
36
36
  moveLocalLibraryItemSelection(kind: AgentWorkspaceLocalEditorKind, delta: number): void;
37
37
  selectedLocalLibraryItem(kind: AgentWorkspaceLocalEditorKind): AgentWorkspaceLocalLibraryItem | null;
38
38
  applyLocalLibraryOperation(operation: AgentWorkspaceLocalOperation): void;
39
+ completeOnboarding(): void;
39
40
  hasCommandDispatch(): boolean;
40
41
  dispatchWorkspaceCommand: AgentWorkspaceCommandDispatcher;
41
42
  commitActionSearchSelection(): boolean;
@@ -89,6 +90,10 @@ export function activateAgentWorkspaceSelection(
89
90
  workspace.applyLocalLibraryOperation(action.localOperation);
90
91
  return;
91
92
  }
93
+ if (action.kind === 'onboarding-complete') {
94
+ workspace.completeOnboarding();
95
+ return;
96
+ }
92
97
  if (action.kind === 'guidance' || !action.command) {
93
98
  handleGuidanceOrWorkspaceAction(workspace, action);
94
99
  return;
@@ -609,6 +609,17 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
609
609
  { id: 'delegation-status', label: 'Delegation status', detail: 'Inspect build-delegation receipts and shared-session status without starting coding work.', command: '/delegate status', kind: 'command', safety: 'read-only' },
610
610
  ],
611
611
  },
612
+ {
613
+ id: 'finish',
614
+ group: 'FINISH',
615
+ label: 'Finish',
616
+ summary: 'Acknowledge setup and close onboarding.',
617
+ detail: 'Use this final step after reviewing setup. Apply & close writes the user onboarding completion marker so normal future launches start in the main conversation.',
618
+ actions: [
619
+ { id: 'onboarding-apply-close', label: 'Apply & close', detail: 'Acknowledge onboarding as finished, persist the user completion marker, and close the fullscreen Agent workspace.', kind: 'onboarding-complete', safety: 'safe' },
620
+ { id: 'finish-review-setup', label: 'Review setup first', detail: 'Jump back to setup before acknowledging onboarding as finished.', targetCategoryId: 'setup', kind: 'workspace', safety: 'safe' },
621
+ ],
622
+ },
612
623
  ];
613
624
 
614
625
  export function renderAgentWorkspacePackageText(): string {
@@ -27,11 +27,12 @@ export const AGENT_WORKSPACE_CATEGORY_IDS = [
27
27
  'host',
28
28
  'automation',
29
29
  'delegate',
30
+ 'finish',
30
31
  ] as const;
31
32
 
32
33
  export type AgentWorkspaceCategoryId = (typeof AGENT_WORKSPACE_CATEGORY_IDS)[number];
33
34
 
34
- export type AgentWorkspaceActionKind = 'command' | 'guidance' | 'workspace' | 'editor' | 'local-selection' | 'local-operation';
35
+ export type AgentWorkspaceActionKind = 'command' | 'guidance' | 'workspace' | 'editor' | 'local-selection' | 'local-operation' | 'onboarding-complete';
35
36
 
36
37
  export type AgentWorkspaceLocalEditorKind = 'memory' | 'note' | 'persona' | 'skill' | 'routine' | 'profile';
37
38
 
@@ -20,6 +20,7 @@ import { buildAgentWorkspaceRequirements } from './agent-workspace-requirements.
20
20
  import { appendAgentWorkspaceActionSearchText, backspaceAgentWorkspaceActionSearch, beginAgentWorkspaceActionSearch, clearAgentWorkspaceActionSearch, commitAgentWorkspaceActionSearchSelection, searchAgentWorkspaceActions } from './agent-workspace-search.ts';
21
21
  import { buildAgentWorkspaceRuntimeSnapshot } from './agent-workspace-snapshot.ts';
22
22
  import type { AgentWorkspaceAction, AgentWorkspaceActionResult, AgentWorkspaceActionSearchResult, AgentWorkspaceCategory, AgentWorkspaceCommandDispatcher, AgentWorkspaceEditorField, AgentWorkspaceFocusPane, AgentWorkspaceLocalEditor, AgentWorkspaceLocalEditorKind, AgentWorkspaceLocalLibraryItem, AgentWorkspaceLocalOperation, AgentWorkspacePromptDispatcher, AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
23
+ import { writeOnboardingCheckMarker, writeOnboardingCompletionMarker } from '../runtime/onboarding/index.ts';
23
24
 
24
25
  export type { AgentWorkspaceChannelRisk, AgentWorkspaceChannelStatus } from './agent-workspace-channels.ts';
25
26
  export type { AgentWorkspaceAction, AgentWorkspaceActionResult, AgentWorkspaceActionSearchResult, AgentWorkspaceCategory, AgentWorkspaceCategoryId, AgentWorkspaceCommandDispatcher, AgentWorkspaceEditorField, AgentWorkspaceFocusPane, AgentWorkspaceLocalEditor, AgentWorkspaceLocalEditorKind, AgentWorkspaceLocalLibraryItem, AgentWorkspaceLocalOperation, AgentWorkspacePromptDispatcher, AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
@@ -306,6 +307,48 @@ export class AgentWorkspace {
306
307
  });
307
308
  }
308
309
 
310
+ completeOnboarding(): void {
311
+ const shellPaths = this.context?.workspace?.shellPaths;
312
+ if (!shellPaths) {
313
+ this.status = 'Cannot complete onboarding without Agent shell paths.';
314
+ this.lastActionResult = {
315
+ kind: 'error',
316
+ title: 'Onboarding completion unavailable',
317
+ detail: 'The Agent workspace cannot locate the user onboarding completion marker path for this runtime.',
318
+ safety: 'safe',
319
+ };
320
+ return;
321
+ }
322
+
323
+ try {
324
+ const marker = {
325
+ scope: 'user',
326
+ source: 'wizard',
327
+ mode: 'new',
328
+ workspaceRoot: shellPaths.workingDirectory,
329
+ } as const;
330
+ writeOnboardingCheckMarker(shellPaths, marker);
331
+ writeOnboardingCompletionMarker(shellPaths, marker);
332
+ this.status = 'Onboarding applied and closed.';
333
+ this.lastActionResult = {
334
+ kind: 'refreshed',
335
+ title: 'Onboarding complete',
336
+ detail: 'Saved the user onboarding completion marker. Future normal launches start in the main conversation.',
337
+ safety: 'safe',
338
+ };
339
+ if (!this.context?.dismissAgentWorkspace?.()) this.close();
340
+ } catch (error) {
341
+ const detail = error instanceof Error ? error.message : String(error);
342
+ this.status = 'Onboarding completion failed.';
343
+ this.lastActionResult = {
344
+ kind: 'error',
345
+ title: 'Onboarding completion failed',
346
+ detail,
347
+ safety: 'safe',
348
+ };
349
+ }
350
+ }
351
+
309
352
  private selectedItemForOperation(operation: AgentWorkspaceLocalOperation): AgentWorkspaceLocalLibraryItem | null {
310
353
  if (operation.startsWith('memory-')) return this.selectedLocalLibraryItem('memory');
311
354
  if (operation.startsWith('note-')) return this.selectedLocalLibraryItem('note');
@@ -408,6 +408,12 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
408
408
  { text: `Delegated review policy: ${snapshot.delegatedReviewPolicy}`, fg: PALETTE.warn },
409
409
  { text: 'No coding-role Agent jobs are created here.', fg: PALETTE.good },
410
410
  );
411
+ } else if (category.id === 'finish') {
412
+ base.push(
413
+ { text: 'Apply & close marks onboarding finished for this user.', fg: PALETTE.good },
414
+ { text: 'Future normal launches start in the main conversation.', fg: PALETTE.info },
415
+ { text: 'Use /agent, /setup, or /onboarding to reopen this workspace later.', fg: PALETTE.muted },
416
+ );
411
417
  }
412
418
  if (snapshot.warnings.length > 0) {
413
419
  base.push({ text: `Warnings: ${snapshot.warnings.map((warning) => compactText(warning, 60)).join('; ')}`, fg: PALETTE.warn });
@@ -11,6 +11,7 @@ import type {
11
11
  import { GOODVIBES_AGENT_SURFACE_ROOT } from '../../config/surface.ts';
12
12
 
13
13
  const ONBOARDING_CHECK_MARKER_FILE = 'onboarding-checked.json';
14
+ const ONBOARDING_COMPLETION_MARKER_FILE = 'onboarding-complete.json';
14
15
 
15
16
  type OnboardingShellPaths = Pick<
16
17
  ShellPathService,
@@ -20,10 +21,11 @@ type OnboardingShellPaths = Pick<
20
21
  function resolveMarkerPath(
21
22
  shellPaths: OnboardingShellPaths,
22
23
  scope: OnboardingStateScope,
24
+ fileName = ONBOARDING_CHECK_MARKER_FILE,
23
25
  ): string {
24
26
  return scope === 'project'
25
- ? shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, ONBOARDING_CHECK_MARKER_FILE)
26
- : shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, ONBOARDING_CHECK_MARKER_FILE);
27
+ ? shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, fileName)
28
+ : shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, fileName);
27
29
  }
28
30
 
29
31
  function isObject(value: unknown): value is Record<string, unknown> {
@@ -87,11 +89,12 @@ export function getOnboardingCheckMarkerPath(
87
89
  return resolveMarkerPath(shellPaths, scope);
88
90
  }
89
91
 
90
- export function readOnboardingCheckMarker(
92
+ function readOnboardingMarker(
91
93
  shellPaths: OnboardingShellPaths,
92
- scope: OnboardingStateScope = 'user',
94
+ scope: OnboardingStateScope,
95
+ fileName: string,
93
96
  ): OnboardingCheckMarkerState {
94
- const path = resolveMarkerPath(shellPaths, scope);
97
+ const path = resolveMarkerPath(shellPaths, scope, fileName);
95
98
  if (!existsSync(path)) return buildMissingMarkerState(scope, path);
96
99
 
97
100
  try {
@@ -112,6 +115,27 @@ export function readOnboardingCheckMarker(
112
115
  }
113
116
  }
114
117
 
118
+ export function readOnboardingCheckMarker(
119
+ shellPaths: OnboardingShellPaths,
120
+ scope: OnboardingStateScope = 'user',
121
+ ): OnboardingCheckMarkerState {
122
+ return readOnboardingMarker(shellPaths, scope, ONBOARDING_CHECK_MARKER_FILE);
123
+ }
124
+
125
+ export function getOnboardingCompletionMarkerPath(
126
+ shellPaths: OnboardingShellPaths,
127
+ scope: OnboardingStateScope = 'user',
128
+ ): string {
129
+ return resolveMarkerPath(shellPaths, scope, ONBOARDING_COMPLETION_MARKER_FILE);
130
+ }
131
+
132
+ export function readOnboardingCompletionMarker(
133
+ shellPaths: OnboardingShellPaths,
134
+ scope: OnboardingStateScope = 'user',
135
+ ): OnboardingCheckMarkerState {
136
+ return readOnboardingMarker(shellPaths, scope, ONBOARDING_COMPLETION_MARKER_FILE);
137
+ }
138
+
115
139
  export function readOnboardingCheckMarkers(
116
140
  shellPaths: OnboardingShellPaths,
117
141
  ): OnboardingCheckMarkersState {
@@ -125,12 +149,13 @@ export function readOnboardingCheckMarkers(
125
149
  };
126
150
  }
127
151
 
128
- export function writeOnboardingCheckMarker(
152
+ function writeOnboardingMarker(
129
153
  shellPaths: OnboardingShellPaths,
130
- options: WriteOnboardingCheckMarkerOptions = {},
154
+ options: WriteOnboardingCheckMarkerOptions,
155
+ fileName: string,
131
156
  ): OnboardingCheckMarkerState {
132
157
  const scope = options.scope ?? 'user';
133
- const path = resolveMarkerPath(shellPaths, scope);
158
+ const path = resolveMarkerPath(shellPaths, scope, fileName);
134
159
  const checkedAt = options.checkedAt ?? Date.now();
135
160
  const payload: OnboardingCheckMarkerPayload = {
136
161
  version: 1,
@@ -144,5 +169,19 @@ export function writeOnboardingCheckMarker(
144
169
  mkdirSync(dirname(path), { recursive: true });
145
170
  writeFileSync(path, `${JSON.stringify(payload, null, 2)}\n`, 'utf-8');
146
171
 
147
- return readOnboardingCheckMarker(shellPaths, scope);
172
+ return readOnboardingMarker(shellPaths, scope, fileName);
173
+ }
174
+
175
+ export function writeOnboardingCheckMarker(
176
+ shellPaths: OnboardingShellPaths,
177
+ options: WriteOnboardingCheckMarkerOptions = {},
178
+ ): OnboardingCheckMarkerState {
179
+ return writeOnboardingMarker(shellPaths, options, ONBOARDING_CHECK_MARKER_FILE);
180
+ }
181
+
182
+ export function writeOnboardingCompletionMarker(
183
+ shellPaths: OnboardingShellPaths,
184
+ options: WriteOnboardingCheckMarkerOptions = {},
185
+ ): OnboardingCheckMarkerState {
186
+ return writeOnboardingMarker(shellPaths, options, ONBOARDING_COMPLETION_MARKER_FILE);
148
187
  }
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.44';
9
+ let _version = '1.1.1';
10
10
  try {
11
11
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
12
12
  readonly version?: unknown;