@pellux/goodvibes-agent 1.0.10 → 1.0.11

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.0.11 - 2026-06-03
6
+
7
+ - Model-visible harness parity now opens conversation search, prompt history search, slash-command mode, file picker, and nearest-block actions through confirmation-gated visible shell routes.
8
+ - Documentation now names the current UI surface inventory for 1.0.x so users and the model share the same harness map.
9
+ - Harness assertions cover the new visible surface routes and preserve the existing safety boundary.
10
+
5
11
  ## 1.0.10 - 2026-06-03
6
12
 
7
13
  - Expose the runtime activity monitor as a model-visible, confirmation-gated harness UI surface, wire the shell opener through CommandContext, and refresh package-facing docs and focused coverage for the current 1.0.x surface map.
package/README.md CHANGED
@@ -66,7 +66,7 @@ Use the workspace as the primary product surface:
66
66
 
67
67
  Inside the Agent workspace, press `/` to search every workspace action by name, category, command, or detail. This is the primary discovery path for product actions; slash commands and CLI subcommands remain power-user/scriptable mirrors.
68
68
 
69
- The model has the same harness map through `agent_harness`: it can list Agent workspace actions, list built-in panels and their workspace routes, inspect modal/overlay/picker UI surfaces, list top-level CLI mirrors, inspect fixed shortcuts and configurable keybindings, list slash commands, inspect command policy metadata, inspect model tool definitions, inspect or change Agent settings with confirmation, run concrete workspace or slash-command mirrors with confirmation, and report connected-host capability and live readiness posture. CLI mirror modes are read-only catalog and parser inspection; inside the main conversation, the model uses the returned preferred model tool, workspace action, setting mode, or confirmed slash-command mirror instead of launching hidden nested CLI processes. Panel modes expose catalog/open state and route visible panel/workspace changes through the current Agent shell bridge with confirmation. UI surface modes expose help, shortcuts, context, runtime activity, bookmarks, model/provider pickers, TTS provider/voice pickers, session/profile pickers, the panel-picker compatibility route, security/knowledge/subscription operator surfaces, settings, MCP workspace, onboarding, and Agent workspace entrypoints; `open_ui_surface` is confirmation-gated and only performs visible shell navigation. Shortcut modes expose fixed runtime/editor controls plus the live resolved keybinding table; `set_keybinding` and `reset_keybinding` write the same `keybindings.json` file the user edits and require confirmation. Workspace action discovery can inline editor field schemas with `includeParameters:true`; profile editors use the current starter-template inventory, and routine schedule editors can prefill a selected local routine from `recordId`. Selection-based local workspace actions accept a local `recordId` so the model can use the same note promotion and local registry flows as the TUI. The `connected_host` report includes route families, allowed capabilities, blocked lifecycle/non-Agent surfaces, and availability for the first-class Agent tools. The `connected_host_status` report performs a read-only live check of the connected-host status route and the isolated Agent Knowledge status route, reports SDK compatibility, token posture, endpoint bindings, route readiness, and actionable findings, and still refuses connected-host lifecycle control. The model uses those first-class tools for product workflows where they exist, such as Agent Knowledge, local memory/notes/personas/skills/routines, channel sends, notifications, reminders, media generation, work plans, and connected-host operator actions.
69
+ The model has the same harness map through `agent_harness`: it can list Agent workspace actions, list built-in panels and their workspace routes, inspect modal/overlay/picker UI surfaces, list top-level CLI mirrors, inspect fixed shortcuts and configurable keybindings, list slash commands, inspect command policy metadata, inspect model tool definitions, inspect or change Agent settings with confirmation, run concrete workspace or slash-command mirrors with confirmation, and report connected-host capability and live readiness posture. CLI mirror modes are read-only catalog and parser inspection; inside the main conversation, the model uses the returned preferred model tool, workspace action, setting mode, or confirmed slash-command mirror instead of launching hidden nested CLI processes. Panel modes expose catalog/open state and route visible panel/workspace changes through the current Agent shell bridge with confirmation. UI surface modes expose help, shortcuts, conversation search, prompt-history search, slash-command mode, file picker, block actions, context, runtime activity, bookmarks, model/provider pickers, TTS provider/voice pickers, session/profile pickers, the panel-picker compatibility route, security/knowledge/subscription operator surfaces, settings, MCP workspace, onboarding, and Agent workspace entrypoints; `open_ui_surface` is confirmation-gated and only performs visible shell navigation. Shortcut modes expose fixed runtime/editor controls plus the live resolved keybinding table; `set_keybinding` and `reset_keybinding` write the same `keybindings.json` file the user edits and require confirmation. Workspace action discovery can inline editor field schemas with `includeParameters:true`; profile editors use the current starter-template inventory, and routine schedule editors can prefill a selected local routine from `recordId`. Selection-based local workspace actions accept a local `recordId` so the model can use the same note promotion and local registry flows as the TUI. The `connected_host` report includes route families, allowed capabilities, blocked lifecycle/non-Agent surfaces, and availability for the first-class Agent tools. The `connected_host_status` report performs a read-only live check of the connected-host status route and the isolated Agent Knowledge status route, reports SDK compatibility, token posture, endpoint bindings, route readiness, and actionable findings, and still refuses connected-host lifecycle control. The model uses those first-class tools for product workflows where they exist, such as Agent Knowledge, local memory/notes/personas/skills/routines, channel sends, notifications, reminders, media generation, work plans, and connected-host operator actions.
70
70
 
71
71
  The setup workspace surfaces discovered Agent-local persona, skill, and routine markdown files so day-one setup can import useful behavior instead of starting from blank records. It can also create one initial scratchpad note, local persona, skill, and routine directly during first-run setup; those records stay in Agent-local registries and never write to default knowledge or non-Agent segments.
72
72
 
@@ -816508,7 +816508,7 @@ var createStyledCell = (char, overrides = {}) => ({
816508
816508
  // src/version.ts
816509
816509
  import { readFileSync } from "fs";
816510
816510
  import { join } from "path";
816511
- var _version = "1.0.10";
816511
+ var _version = "1.0.11";
816512
816512
  var _sdkVersion = "0.33.35";
816513
816513
  try {
816514
816514
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf-8"));
@@ -847717,13 +847717,13 @@ init_state3();
847717
847717
 
847718
847718
  // src/input/commands/recall-shared.ts
847719
847719
  var VALID_CLASSES = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
847720
- var VALID_SCOPES2 = ["session", "project", "team"];
847720
+ var VALID_SCOPES = ["session", "project", "team"];
847721
847721
  var VALID_REVIEW_STATES = ["fresh", "reviewed", "stale", "contradicted"];
847722
847722
  function isValidClass(s4) {
847723
847723
  return VALID_CLASSES.includes(s4);
847724
847724
  }
847725
847725
  function isValidScope(s4) {
847726
- return VALID_SCOPES2.includes(s4);
847726
+ return VALID_SCOPES.includes(s4);
847727
847727
  }
847728
847728
  function isValidReviewState(s4) {
847729
847729
  return VALID_REVIEW_STATES.includes(s4);
@@ -847766,7 +847766,7 @@ function handleRecallSearch(args2, context) {
847766
847766
  if (isValidScope(scope))
847767
847767
  filter.scope = scope;
847768
847768
  else {
847769
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
847769
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
847770
847770
  return;
847771
847771
  }
847772
847772
  }
@@ -847941,7 +847941,7 @@ function handleRecallList(args2, context) {
847941
847941
  if (scopeIdx !== -1 && args2[scopeIdx + 1]) {
847942
847942
  const scope = args2[scopeIdx + 1];
847943
847943
  if (!isValidScope(scope)) {
847944
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
847944
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
847945
847945
  return;
847946
847946
  }
847947
847947
  filter.scope = scope;
@@ -847991,7 +847991,7 @@ async function handleRecallAdd(args2, context) {
847991
847991
  const tags = tagsRaw ? tagsRaw.split(",").map((token) => token.trim()).filter(Boolean) : [];
847992
847992
  const scope = scopeRaw && isValidScope(scopeRaw) ? scopeRaw : "project";
847993
847993
  if (scopeRaw && !isValidScope(scopeRaw)) {
847994
- context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES2.join(", ")}.`);
847994
+ context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES.join(", ")}.`);
847995
847995
  return;
847996
847996
  }
847997
847997
  const provenance = [];
@@ -848125,7 +848125,7 @@ function handleRecallExport(args2, context) {
848125
848125
  if (scopeIdx !== -1 && commandArgs[scopeIdx + 1]) {
848126
848126
  const scope = commandArgs[scopeIdx + 1];
848127
848127
  if (!isValidScope(scope)) {
848128
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
848128
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
848129
848129
  return;
848130
848130
  }
848131
848131
  filter.scope = scope;
@@ -848204,7 +848204,7 @@ function handleRecallHandoffExport(args2, context) {
848204
848204
  const scopeIdx = commandArgs.indexOf("--scope");
848205
848205
  const scopeRaw = scopeIdx !== -1 ? commandArgs[scopeIdx + 1] : "team";
848206
848206
  if (!scopeRaw || !isValidScope(scopeRaw)) {
848207
- context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES2.join(", ")}.`);
848207
+ context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES.join(", ")}.`);
848208
848208
  return;
848209
848209
  }
848210
848210
  const bundle = memory.exportBundle({ scope: scopeRaw });
@@ -848320,7 +848320,7 @@ function handleRecallPromote(args2, context) {
848320
848320
  const id = parsed.rest[0];
848321
848321
  const scope = parsed.rest[1];
848322
848322
  if (!id || !scope || !isValidScope(scope)) {
848323
- context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES2.join("|")}> --yes`);
848323
+ context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES.join("|")}> --yes`);
848324
848324
  return;
848325
848325
  }
848326
848326
  if (!parsed.yes) {
@@ -862165,7 +862165,7 @@ import { mkdirSync as mkdirSync64, readFileSync as readFileSync86, writeFileSync
862165
862165
  import { dirname as dirname63, resolve as resolve39 } from "path";
862166
862166
  init_state3();
862167
862167
  var VALID_CLASSES2 = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
862168
- var VALID_SCOPES4 = ["session", "project", "team"];
862168
+ var VALID_SCOPES3 = ["session", "project", "team"];
862169
862169
  var VALID_REVIEW_STATES3 = ["fresh", "reviewed", "stale", "contradicted"];
862170
862170
  var VALID_PROVENANCE_KINDS = ["session", "turn", "task", "event", "file"];
862171
862171
  var VALUE_OPTIONS = new Set([
@@ -862265,7 +862265,7 @@ function isMemoryClass2(value) {
862265
862265
  return VALID_CLASSES2.includes(value);
862266
862266
  }
862267
862267
  function isMemoryScope2(value) {
862268
- return VALID_SCOPES4.includes(value);
862268
+ return VALID_SCOPES3.includes(value);
862269
862269
  }
862270
862270
  function isReviewState(value) {
862271
862271
  return VALID_REVIEW_STATES3.includes(value);
@@ -862280,7 +862280,7 @@ function requireClass(value) {
862280
862280
  }
862281
862281
  function requireScope(value) {
862282
862282
  if (!value || !isMemoryScope2(value))
862283
- throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES4.join(", ")}`);
862283
+ throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES3.join(", ")}`);
862284
862284
  return value;
862285
862285
  }
862286
862286
  function optionalScope(value) {
@@ -880878,6 +880878,17 @@ function optionalPane(args2) {
880878
880878
  const pane = readString56(args2.pane);
880879
880879
  return pane === "top" || pane === "bottom" ? pane : undefined;
880880
880880
  }
880881
+ function surfaceInputText(args2) {
880882
+ return readString56(args2.prefix || args2.key || (args2.surfaceId ? args2.query : undefined) || args2.target) || undefined;
880883
+ }
880884
+ function filePickerOptions(args2) {
880885
+ const target = readString56(args2.target).toLowerCase();
880886
+ const injectMode = target === "inject" || target === "inject-mode" || target === "!@";
880887
+ return {
880888
+ injectMode,
880889
+ query: readString56(args2.prefix || args2.key || (args2.surfaceId ? args2.query : undefined)) || undefined
880890
+ };
880891
+ }
880881
880892
  function openAgentWorkspaceCategory(context, surface, categoryId, extra = {}) {
880882
880893
  if (!context.openAgentWorkspace)
880883
880894
  return routeUnavailable(surface);
@@ -881187,6 +881198,105 @@ var UI_SURFACES = [
881187
881198
  return opened(surface);
881188
881199
  }
881189
881200
  },
881201
+ {
881202
+ id: "conversation-search",
881203
+ label: "Conversation Search",
881204
+ kind: "overlay",
881205
+ summary: "Visible transcript search overlay opened by the same shell route as Ctrl+F.",
881206
+ command: "Ctrl+F",
881207
+ preferredModelRoute: "Use conversation/session/content modes for model-readable inspection; use this surface for visible transcript search navigation.",
881208
+ parameters: ["query", "prefix", "key"],
881209
+ available: (context) => typeof context.openConversationSearch === "function",
881210
+ open: (context, args2) => {
881211
+ const surface = findSurfaceById("conversation-search");
881212
+ if (!context.openConversationSearch)
881213
+ return routeUnavailable(surface);
881214
+ const query2 = surfaceInputText(args2);
881215
+ context.openConversationSearch(query2);
881216
+ return opened(surface, { query: query2 ?? "" });
881217
+ }
881218
+ },
881219
+ {
881220
+ id: "prompt-history-search",
881221
+ label: "Prompt History Search",
881222
+ kind: "overlay",
881223
+ summary: "Visible reverse prompt-history search opened by the same shell route as Ctrl+R.",
881224
+ command: "Ctrl+R",
881225
+ preferredModelRoute: "Use this only for visible prompt recall; accepting a result remains an explicit interactive shell action.",
881226
+ parameters: ["query", "prefix", "key"],
881227
+ available: (context) => typeof context.openPromptHistorySearch === "function",
881228
+ open: (context, args2) => {
881229
+ const surface = findSurfaceById("prompt-history-search");
881230
+ if (!context.openPromptHistorySearch)
881231
+ return routeUnavailable(surface);
881232
+ const query2 = surfaceInputText(args2);
881233
+ context.openPromptHistorySearch(query2);
881234
+ return opened(surface, { query: query2 ?? "" });
881235
+ }
881236
+ },
881237
+ {
881238
+ id: "slash-command-mode",
881239
+ label: "Slash Command Mode",
881240
+ kind: "overlay",
881241
+ summary: "Slash-command autocomplete route opened by the same shell path as typing / in an empty prompt.",
881242
+ command: "/",
881243
+ preferredModelRoute: "Use commands/command for model-readable command discovery and run_command for confirmed command execution.",
881244
+ parameters: ["query", "prefix", "key"],
881245
+ available: (context) => typeof context.openSlashCommandMode === "function",
881246
+ open: (context, args2) => {
881247
+ const surface = findSurfaceById("slash-command-mode");
881248
+ if (!context.openSlashCommandMode)
881249
+ return routeUnavailable(surface);
881250
+ const query2 = surfaceInputText(args2);
881251
+ const openedCommandMode = context.openSlashCommandMode(query2);
881252
+ return openedCommandMode ? opened(surface, { query: query2 ?? "" }) : {
881253
+ status: "not_opened",
881254
+ surface: surface.id,
881255
+ kind: surface.kind,
881256
+ query: query2 ?? "",
881257
+ note: "The current prompt contains a non-command draft, so the shell opener refused to replace it."
881258
+ };
881259
+ }
881260
+ },
881261
+ {
881262
+ id: "file-picker",
881263
+ label: "File Picker",
881264
+ kind: "picker",
881265
+ summary: "Visible project file picker opened by the same prompt route as @ and !@ references.",
881266
+ command: "@",
881267
+ preferredModelRoute: "Use first-class file, workspace, or artifact tools for model operation; use this for visible file reference navigation.",
881268
+ parameters: ["target=reference|inject", "query", "prefix", "key"],
881269
+ available: (context) => typeof context.openFilePicker === "function",
881270
+ open: (context, args2) => {
881271
+ const surface = findSurfaceById("file-picker");
881272
+ if (!context.openFilePicker)
881273
+ return routeUnavailable(surface);
881274
+ const options = filePickerOptions(args2);
881275
+ const openedFilePicker = context.openFilePicker(options);
881276
+ return openedFilePicker ? opened(surface, { mode: options.injectMode ? "inject" : "reference", query: options.query ?? "" }) : routeUnavailable(surface);
881277
+ }
881278
+ },
881279
+ {
881280
+ id: "block-actions",
881281
+ label: "Block Actions",
881282
+ kind: "overlay",
881283
+ summary: "Visible nearest-block action menu opened by the same shell route as pressing Enter on an empty prompt near transcript content.",
881284
+ command: "Enter on empty prompt",
881285
+ preferredModelRoute: "Use conversation/session/content modes or confirmed slash-command mirrors for concrete block operations; use this surface for visible block-action navigation.",
881286
+ available: (context) => typeof context.openBlockActions === "function",
881287
+ open: (context) => {
881288
+ const surface = findSurfaceById("block-actions");
881289
+ if (!context.openBlockActions)
881290
+ return routeUnavailable(surface);
881291
+ const openedBlockActions = context.openBlockActions();
881292
+ return openedBlockActions ? opened(surface) : {
881293
+ status: "not_opened",
881294
+ surface: surface.id,
881295
+ kind: surface.kind,
881296
+ note: "The shell opener requires an empty prompt and a nearby rendered conversation block."
881297
+ };
881298
+ }
881299
+ },
881190
881300
  {
881191
881301
  id: "help-overlay",
881192
881302
  label: "Help Overlay",
@@ -899921,6 +900031,75 @@ function wireShellUiOpeners(options) {
899921
900031
  input.processModal.open();
899922
900032
  render();
899923
900033
  };
900034
+ commandContext.openConversationSearch = (query2) => {
900035
+ input.searchManager.open();
900036
+ const searchQuery = query2?.trim() ?? "";
900037
+ if (searchQuery.length > 0) {
900038
+ input.searchManager.search(searchQuery, input.getHistory());
900039
+ }
900040
+ render();
900041
+ };
900042
+ commandContext.openPromptHistorySearch = (query2) => {
900043
+ input.historySearch.open(input.prompt);
900044
+ const searchQuery = query2?.trim() ?? "";
900045
+ if (searchQuery.length > 0) {
900046
+ input.historySearch.search(searchQuery);
900047
+ }
900048
+ render();
900049
+ };
900050
+ commandContext.openSlashCommandMode = (query2) => {
900051
+ const normalizedQuery = query2?.trim().replace(/^\/+/, "") ?? "";
900052
+ if (input.prompt.length > 0 && !input.prompt.startsWith("/")) {
900053
+ return false;
900054
+ }
900055
+ input.modalOpened("command");
900056
+ input.commandMode = true;
900057
+ if (input.prompt.length === 0 || !input.prompt.startsWith("/") || normalizedQuery.length > 0) {
900058
+ input.saveUndoState();
900059
+ input.prompt = `/${normalizedQuery}`;
900060
+ input.cursorPos = input.prompt.length;
900061
+ }
900062
+ const commandQuery = input.prompt.startsWith("/") ? input.prompt.slice(1) : "";
900063
+ const hasArgs = commandQuery.includes(" ");
900064
+ if (hasArgs)
900065
+ input.autocomplete?.reset();
900066
+ else
900067
+ input.autocomplete?.update(commandQuery);
900068
+ input.ensureInputCursorVisible();
900069
+ input.syncFeedContextMutableFields();
900070
+ render();
900071
+ return true;
900072
+ };
900073
+ commandContext.openFilePicker = (options2) => {
900074
+ const injectMode = Boolean(options2?.injectMode);
900075
+ const query2 = options2?.query?.trim() ?? "";
900076
+ const marker = `${injectMode ? "!@" : "@"}${query2}`;
900077
+ const insertPos = input.cursorPos;
900078
+ input.saveUndoState();
900079
+ input.prompt = input.prompt.slice(0, insertPos) + marker + input.prompt.slice(insertPos);
900080
+ input.cursorPos = insertPos + marker.length;
900081
+ input.modalOpened("filePicker");
900082
+ input.filePicker.open(insertPos, injectMode);
900083
+ if (query2.length > 0)
900084
+ input.filePicker.setQuery(query2);
900085
+ input.ensureInputCursorVisible();
900086
+ input.syncFeedContextMutableFields();
900087
+ render();
900088
+ return true;
900089
+ };
900090
+ commandContext.openBlockActions = () => {
900091
+ if (input.prompt.trim().length > 0 || input.commandMode) {
900092
+ return false;
900093
+ }
900094
+ const nearest = conversation.findNearestBlock(input.getScrollTop());
900095
+ if (!nearest) {
900096
+ return false;
900097
+ }
900098
+ input.modalOpened("blockActions");
900099
+ input.blockActionsMenu.open(nearest);
900100
+ render();
900101
+ return true;
900102
+ };
899924
900103
  commandContext.openHelpOverlay = () => {
899925
900104
  if (!input.helpOverlayActive)
899926
900105
  input.modalOpened("help");
@@ -44,7 +44,7 @@ After setup has been applied once, the TUI opens directly into the Agent operato
44
44
 
45
45
  Press `/` inside the Agent workspace to search every workspace action by name, category, command, or detail. Use that finder before reaching for shell commands; CLI subcommands are scriptable mirrors of these TUI workflows.
46
46
 
47
- The model can inspect and use the same harness surface through Agent-owned tools. `agent_harness` exposes workspace action discovery, built-in panel discovery/routing, modal/overlay/picker UI surface discovery/routing, top-level CLI mirror discovery, fixed shortcut and configurable keybinding discovery, keybinding mutation with confirmation, slash-command discovery, command policy metadata, command execution with confirmation, model tool discovery, settings inspection/mutation, connected-host capability inventory, and live connected-host readiness posture. CLI mirror modes are read-only catalog/parser inspection and point the model to the matching in-process tool, workspace action, setting mode, or slash-command mirror. Panel modes expose catalog/open state and route visible panel/workspace changes through the current Agent shell bridge with confirmation. UI surface modes expose help, shortcuts, context, runtime activity, bookmarks, model/provider pickers, TTS provider/voice pickers, session/profile pickers, the panel-picker compatibility route, security/knowledge/subscription operator surfaces, settings, MCP workspace, onboarding, and Agent workspace entrypoints; `open_ui_surface` is confirmation-gated and only performs visible shell navigation. Shortcut modes expose the fixed runtime/editor shortcuts and the live keybindings table; confirmed keybinding edits write the same `keybindings.json` file the user edits and reload the runtime manager. Workspace action discovery can include editor field schemas with `includeParameters:true`, including starter-template defaults for profile creation and selected-routine defaults for routine schedule promotion when `recordId` is supplied. Selection-based local workspace actions accept a local `recordId`, so the model can use the same note promotion and local registry flows as the TUI. First-class model tools cover the main product workflows directly: Agent Knowledge, Agent Knowledge ingest, Agent-local memory/notes/personas/skills/routines, operator actions, notifications, channel sends, reminders, generated media, and work plans.
47
+ The model can inspect and use the same harness surface through Agent-owned tools. `agent_harness` exposes workspace action discovery, built-in panel discovery/routing, modal/overlay/picker UI surface discovery/routing, top-level CLI mirror discovery, fixed shortcut and configurable keybinding discovery, keybinding mutation with confirmation, slash-command discovery, command policy metadata, command execution with confirmation, model tool discovery, settings inspection/mutation, connected-host capability inventory, and live connected-host readiness posture. CLI mirror modes are read-only catalog/parser inspection and point the model to the matching in-process tool, workspace action, setting mode, or slash-command mirror. Panel modes expose catalog/open state and route visible panel/workspace changes through the current Agent shell bridge with confirmation. UI surface modes expose help, shortcuts, conversation search, prompt-history search, slash-command mode, file picker, block actions, context, runtime activity, bookmarks, model/provider pickers, TTS provider/voice pickers, session/profile pickers, the panel-picker compatibility route, security/knowledge/subscription operator surfaces, settings, MCP workspace, onboarding, and Agent workspace entrypoints; `open_ui_surface` is confirmation-gated and only performs visible shell navigation. Shortcut modes expose the fixed runtime/editor shortcuts and the live keybindings table; confirmed keybinding edits write the same `keybindings.json` file the user edits and reload the runtime manager. Workspace action discovery can include editor field schemas with `includeParameters:true`, including starter-template defaults for profile creation and selected-routine defaults for routine schedule promotion when `recordId` is supplied. Selection-based local workspace actions accept a local `recordId`, so the model can use the same note promotion and local registry flows as the TUI. First-class model tools cover the main product workflows directly: Agent Knowledge, Agent Knowledge ingest, Agent-local memory/notes/personas/skills/routines, operator actions, notifications, channel sends, reminders, generated media, and work plans.
48
48
 
49
49
  Use the Artifacts area for concrete files and generated output: attach images to prompts, export conversations or saved sessions, ingest local source files and URL lists into Agent Knowledge, import bookmarks or browser history, inspect source records, and generate media artifacts from confirmed prompts.
50
50
 
@@ -52,7 +52,7 @@ The main Agent model has an Agent-owned harness bridge rather than generic SDK s
52
52
 
53
53
  `agent_harness` discovery modes are read-only. `summary` reports the model access map; `panels` and `panel` return the built-in panel catalog, current open/focused state, and each panel's matching Agent workspace route; `ui_surfaces` and `ui_surface` return modal, overlay, picker, and workspace entrypoints with shell-opener availability and preferred model routes; `cli_commands` and `cli_command` return top-level package CLI mirror metadata, parser output, blocked command tokens, and preferred in-process model routes; `shortcuts` returns fixed runtime/editor shortcuts plus configurable keybindings; `keybindings` and `keybinding` return the live resolved keybinding table, default bindings, custom state, and config path; `commands` and `command` return slash-command descriptions plus effect/confirmation/preferred-tool/boundary policy metadata; `workspace_actions` lists Agent workspace actions and can inline editor field schemas with `includeParameters:true`; `workspace_action` returns one action with its editor schema; `tools` can inline model tool JSON schemas with `includeParameters:true`; `settings` returns setting descriptors plus setting policy; `connected_host` returns the connected-host route families, allowed capabilities, blocked capabilities, and first-class tool availability; and `connected_host_status` performs a live read-only check of the connected-host status and Agent Knowledge status routes and reports endpoint bindings, token posture, SDK compatibility, route readiness, and findings without printing token values.
54
54
 
55
- `open_ui_surface` is a confirmation-gated visible navigation mode for the same shell surfaces the user can open: Agent workspace, settings, MCP workspace, model/provider pickers, TTS provider/voice pickers, session/profile pickers, the panel-picker compatibility route, security/knowledge/subscription operator surfaces, bookmarks, context inspector, runtime activity monitor, help, shortcuts, and onboarding. It does not perform hidden operations; use first-class model tools, settings modes, workspace actions, or confirmed slash-command mirrors for actual state changes.
55
+ `open_ui_surface` is a confirmation-gated visible navigation mode for the same shell surfaces the user can open: Agent workspace, settings, MCP workspace, model/provider pickers, TTS provider/voice pickers, session/profile pickers, the panel-picker compatibility route, security/knowledge/subscription operator surfaces, conversation search, prompt-history search, slash-command mode, file picker, block actions, bookmarks, context inspector, runtime activity monitor, help, shortcuts, and onboarding. It does not perform hidden operations; use first-class model tools, settings modes, workspace actions, or confirmed slash-command mirrors for actual state changes.
56
56
 
57
57
  `set_keybinding` and `reset_keybinding` are confirmation-gated control modes. They write the same Agent `keybindings.json` file exposed by `/keybindings`, reload the runtime keybinding manager, and leave fixed runtime/editor shortcuts read-only.
58
58
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
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",
@@ -93,6 +93,11 @@ export interface CommandShellUiOpeners {
93
93
  openContextInspector?: () => void;
94
94
  openBookmarkModal?: () => void;
95
95
  openProcessModal?: () => void;
96
+ openConversationSearch?: (query?: string) => void;
97
+ openPromptHistorySearch?: (query?: string) => void;
98
+ openSlashCommandMode?: (query?: string) => boolean;
99
+ openFilePicker?: (options?: { injectMode?: boolean; query?: string }) => boolean;
100
+ openBlockActions?: () => boolean;
96
101
  jumpToBookmark?: (key: string) => void;
97
102
  scrollToLine?: (line: number) => void;
98
103
  openHelpOverlay?: () => void;
@@ -255,6 +255,79 @@ export function wireShellUiOpeners(options: WireShellUiOpenersOptions): void {
255
255
  render();
256
256
  };
257
257
 
258
+ commandContext.openConversationSearch = (query?: string) => {
259
+ input.searchManager.open();
260
+ const searchQuery = query?.trim() ?? '';
261
+ if (searchQuery.length > 0) {
262
+ input.searchManager.search(searchQuery, input.getHistory());
263
+ }
264
+ render();
265
+ };
266
+
267
+ commandContext.openPromptHistorySearch = (query?: string) => {
268
+ input.historySearch.open(input.prompt);
269
+ const searchQuery = query?.trim() ?? '';
270
+ if (searchQuery.length > 0) {
271
+ input.historySearch.search(searchQuery);
272
+ }
273
+ render();
274
+ };
275
+
276
+ commandContext.openSlashCommandMode = (query?: string): boolean => {
277
+ const normalizedQuery = query?.trim().replace(/^\/+/, '') ?? '';
278
+ if (input.prompt.length > 0 && !input.prompt.startsWith('/')) {
279
+ return false;
280
+ }
281
+
282
+ input.modalOpened('command');
283
+ input.commandMode = true;
284
+ if (input.prompt.length === 0 || !input.prompt.startsWith('/') || normalizedQuery.length > 0) {
285
+ input.saveUndoState();
286
+ input.prompt = `/${normalizedQuery}`;
287
+ input.cursorPos = input.prompt.length;
288
+ }
289
+
290
+ const commandQuery = input.prompt.startsWith('/') ? input.prompt.slice(1) : '';
291
+ const hasArgs = commandQuery.includes(' ');
292
+ if (hasArgs) input.autocomplete?.reset();
293
+ else input.autocomplete?.update(commandQuery);
294
+ input.ensureInputCursorVisible();
295
+ input.syncFeedContextMutableFields();
296
+ render();
297
+ return true;
298
+ };
299
+
300
+ commandContext.openFilePicker = (options): boolean => {
301
+ const injectMode = Boolean(options?.injectMode);
302
+ const query = options?.query?.trim() ?? '';
303
+ const marker = `${injectMode ? '!@' : '@'}${query}`;
304
+ const insertPos = input.cursorPos;
305
+ input.saveUndoState();
306
+ input.prompt = input.prompt.slice(0, insertPos) + marker + input.prompt.slice(insertPos);
307
+ input.cursorPos = insertPos + marker.length;
308
+ input.modalOpened('filePicker');
309
+ input.filePicker.open(insertPos, injectMode);
310
+ if (query.length > 0) input.filePicker.setQuery(query);
311
+ input.ensureInputCursorVisible();
312
+ input.syncFeedContextMutableFields();
313
+ render();
314
+ return true;
315
+ };
316
+
317
+ commandContext.openBlockActions = (): boolean => {
318
+ if (input.prompt.trim().length > 0 || input.commandMode) {
319
+ return false;
320
+ }
321
+ const nearest = conversation.findNearestBlock(input.getScrollTop());
322
+ if (!nearest) {
323
+ return false;
324
+ }
325
+ input.modalOpened('blockActions');
326
+ input.blockActionsMenu.open(nearest);
327
+ render();
328
+ return true;
329
+ };
330
+
258
331
  commandContext.openHelpOverlay = () => {
259
332
  if (!input.helpOverlayActive) input.modalOpened('help');
260
333
  input.helpOverlayActive = !input.helpOverlayActive;
@@ -82,6 +82,19 @@ function optionalPane(args: AgentHarnessUiSurfaceArgs): 'top' | 'bottom' | undef
82
82
  return pane === 'top' || pane === 'bottom' ? pane : undefined;
83
83
  }
84
84
 
85
+ function surfaceInputText(args: AgentHarnessUiSurfaceArgs): string | undefined {
86
+ return readString(args.prefix || args.key || (args.surfaceId ? args.query : undefined) || args.target) || undefined;
87
+ }
88
+
89
+ function filePickerOptions(args: AgentHarnessUiSurfaceArgs): { injectMode: boolean; query?: string } {
90
+ const target = readString(args.target).toLowerCase();
91
+ const injectMode = target === 'inject' || target === 'inject-mode' || target === '!@';
92
+ return {
93
+ injectMode,
94
+ query: readString(args.prefix || args.key || (args.surfaceId ? args.query : undefined)) || undefined,
95
+ };
96
+ }
97
+
85
98
  function openAgentWorkspaceCategory(
86
99
  context: CommandContext,
87
100
  surface: UiSurfaceDefinition,
@@ -408,6 +421,106 @@ const UI_SURFACES: readonly UiSurfaceDefinition[] = [
408
421
  return opened(surface);
409
422
  },
410
423
  },
424
+ {
425
+ id: 'conversation-search',
426
+ label: 'Conversation Search',
427
+ kind: 'overlay',
428
+ summary: 'Visible transcript search overlay opened by the same shell route as Ctrl+F.',
429
+ command: 'Ctrl+F',
430
+ preferredModelRoute: 'Use conversation/session/content modes for model-readable inspection; use this surface for visible transcript search navigation.',
431
+ parameters: ['query', 'prefix', 'key'],
432
+ available: (context) => typeof context.openConversationSearch === 'function',
433
+ open: (context, args) => {
434
+ const surface = findSurfaceById('conversation-search')!;
435
+ if (!context.openConversationSearch) return routeUnavailable(surface);
436
+ const query = surfaceInputText(args);
437
+ context.openConversationSearch(query);
438
+ return opened(surface, { query: query ?? '' });
439
+ },
440
+ },
441
+ {
442
+ id: 'prompt-history-search',
443
+ label: 'Prompt History Search',
444
+ kind: 'overlay',
445
+ summary: 'Visible reverse prompt-history search opened by the same shell route as Ctrl+R.',
446
+ command: 'Ctrl+R',
447
+ preferredModelRoute: 'Use this only for visible prompt recall; accepting a result remains an explicit interactive shell action.',
448
+ parameters: ['query', 'prefix', 'key'],
449
+ available: (context) => typeof context.openPromptHistorySearch === 'function',
450
+ open: (context, args) => {
451
+ const surface = findSurfaceById('prompt-history-search')!;
452
+ if (!context.openPromptHistorySearch) return routeUnavailable(surface);
453
+ const query = surfaceInputText(args);
454
+ context.openPromptHistorySearch(query);
455
+ return opened(surface, { query: query ?? '' });
456
+ },
457
+ },
458
+ {
459
+ id: 'slash-command-mode',
460
+ label: 'Slash Command Mode',
461
+ kind: 'overlay',
462
+ summary: 'Slash-command autocomplete route opened by the same shell path as typing / in an empty prompt.',
463
+ command: '/',
464
+ preferredModelRoute: 'Use commands/command for model-readable command discovery and run_command for confirmed command execution.',
465
+ parameters: ['query', 'prefix', 'key'],
466
+ available: (context) => typeof context.openSlashCommandMode === 'function',
467
+ open: (context, args) => {
468
+ const surface = findSurfaceById('slash-command-mode')!;
469
+ if (!context.openSlashCommandMode) return routeUnavailable(surface);
470
+ const query = surfaceInputText(args);
471
+ const openedCommandMode = context.openSlashCommandMode(query);
472
+ return openedCommandMode
473
+ ? opened(surface, { query: query ?? '' })
474
+ : {
475
+ status: 'not_opened',
476
+ surface: surface.id,
477
+ kind: surface.kind,
478
+ query: query ?? '',
479
+ note: 'The current prompt contains a non-command draft, so the shell opener refused to replace it.',
480
+ };
481
+ },
482
+ },
483
+ {
484
+ id: 'file-picker',
485
+ label: 'File Picker',
486
+ kind: 'picker',
487
+ summary: 'Visible project file picker opened by the same prompt route as @ and !@ references.',
488
+ command: '@',
489
+ preferredModelRoute: 'Use first-class file, workspace, or artifact tools for model operation; use this for visible file reference navigation.',
490
+ parameters: ['target=reference|inject', 'query', 'prefix', 'key'],
491
+ available: (context) => typeof context.openFilePicker === 'function',
492
+ open: (context, args) => {
493
+ const surface = findSurfaceById('file-picker')!;
494
+ if (!context.openFilePicker) return routeUnavailable(surface);
495
+ const options = filePickerOptions(args);
496
+ const openedFilePicker = context.openFilePicker(options);
497
+ return openedFilePicker
498
+ ? opened(surface, { mode: options.injectMode ? 'inject' : 'reference', query: options.query ?? '' })
499
+ : routeUnavailable(surface);
500
+ },
501
+ },
502
+ {
503
+ id: 'block-actions',
504
+ label: 'Block Actions',
505
+ kind: 'overlay',
506
+ summary: 'Visible nearest-block action menu opened by the same shell route as pressing Enter on an empty prompt near transcript content.',
507
+ command: 'Enter on empty prompt',
508
+ preferredModelRoute: 'Use conversation/session/content modes or confirmed slash-command mirrors for concrete block operations; use this surface for visible block-action navigation.',
509
+ available: (context) => typeof context.openBlockActions === 'function',
510
+ open: (context) => {
511
+ const surface = findSurfaceById('block-actions')!;
512
+ if (!context.openBlockActions) return routeUnavailable(surface);
513
+ const openedBlockActions = context.openBlockActions();
514
+ return openedBlockActions
515
+ ? opened(surface)
516
+ : {
517
+ status: 'not_opened',
518
+ surface: surface.id,
519
+ kind: surface.kind,
520
+ note: 'The shell opener requires an empty prompt and a nearby rendered conversation block.',
521
+ };
522
+ },
523
+ },
411
524
  {
412
525
  id: 'help-overlay',
413
526
  label: 'Help Overlay',
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.10';
9
+ let _version = '1.0.11';
10
10
  let _sdkVersion = '0.33.35';
11
11
  try {
12
12
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {