@pellux/goodvibes-agent 1.0.14 → 1.0.15
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 +6 -0
- package/README.md +2 -2
- package/dist/package/main.js +210 -119
- package/docs/README.md +1 -1
- package/docs/getting-started.md +1 -1
- package/docs/tools-and-commands.md +2 -2
- package/package.json +1 -1
- package/src/tools/agent-harness-command-catalog.ts +149 -0
- package/src/tools/agent-harness-tool-schema.ts +3 -3
- package/src/tools/agent-harness-tool.ts +9 -41
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Product-facing release notes for GoodVibes Agent.
|
|
4
4
|
|
|
5
|
+
## 1.0.15 - 2026-06-03
|
|
6
|
+
|
|
7
|
+
- Add forgiving agent_harness slash-command detail lookup by command, commandName, target, or query with parsed invocation metadata.
|
|
8
|
+
- Keep slash-command catalogs lightweight while making one-command inspection work from typed user-style invocations, aliases, case-insensitive roots, and unique description matches.
|
|
9
|
+
- Refresh package-facing docs and focused harness coverage for the updated model-visible slash-command inspection path.
|
|
10
|
+
|
|
5
11
|
## 1.0.14 - 2026-06-03
|
|
6
12
|
|
|
7
13
|
- Add agent_harness mode tool to inspect one first-class model tool schema by toolName, target, or query.
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ GoodVibes Agent is the personal operator assistant TUI for GoodVibes. It is buil
|
|
|
7
7
|
|
|
8
8
|
The Agent product connects to a GoodVibes host owned outside this package. It does not install, start, stop, restart, or own that host.
|
|
9
9
|
|
|
10
|
-
Most work happens in the interactive TUI. The installed CLI exists to launch that TUI and provide scriptable mirrors for workflows that are already reachable from the workspace. The main Agent model can inspect the same harness surface through Agent-owned tools: workspace actions, built-in panels, modal/overlay/picker UI surfaces, named operator surfaces, top-level CLI mirrors, fixed shortcuts, configurable keybindings, slash commands, command policy metadata, settings, model tools and individual model tool schemas, local registries, connected-host capability boundaries, and live connected-host readiness are all discoverable from the conversation without exposing connected-host lifecycle control.
|
|
10
|
+
Most work happens in the interactive TUI. The installed CLI exists to launch that TUI and provide scriptable mirrors for workflows that are already reachable from the workspace. The main Agent model can inspect the same harness surface through Agent-owned tools: workspace actions, built-in panels, modal/overlay/picker UI surfaces, named operator surfaces, top-level CLI mirrors, fixed shortcuts, configurable keybindings, slash commands, single-command lookup with policy metadata, settings, model tools and individual model tool schemas, local registries, connected-host capability boundaries, and live connected-host readiness are all discoverable from the conversation without exposing connected-host lifecycle control.
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
@@ -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 or one model tool schema, 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, command browser, conversation search, prompt-history search, slash-command mode, file picker, block actions, context, runtime activity, live process output, bookmarks, model/provider/reasoning-effort 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. Direct local create editors for memory, notes, personas, skills, and routines can execute from submitted fields through `run_workspace_action` and `agent_local_registry` with confirmation. The `connected_host` report includes route families, allowed capabilities, blocked lifecycle/non-Agent surfaces, and availability for the first-class Agent tools; `connected_host_capability` inspects one allowed or blocked capability by id, target, or query with its route families and boundary. 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 one slash command by `command`, `commandName`, `target`, or `query` with parsed arguments and policy metadata, inspect model tool definitions or one model tool schema, 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, command browser, conversation search, prompt-history search, slash-command mode, file picker, block actions, context, runtime activity, live process output, bookmarks, model/provider/reasoning-effort 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. Direct local create editors for memory, notes, personas, skills, and routines can execute from submitted fields through `run_workspace_action` and `agent_local_registry` with confirmation. The `connected_host` report includes route families, allowed capabilities, blocked lifecycle/non-Agent surfaces, and availability for the first-class Agent tools; `connected_host_capability` inspects one allowed or blocked capability by id, target, or query with its route families and boundary. 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
|
|
package/dist/package/main.js
CHANGED
|
@@ -816566,7 +816566,7 @@ var createStyledCell = (char, overrides = {}) => ({
|
|
|
816566
816566
|
// src/version.ts
|
|
816567
816567
|
import { readFileSync } from "fs";
|
|
816568
816568
|
import { join } from "path";
|
|
816569
|
-
var _version = "1.0.
|
|
816569
|
+
var _version = "1.0.15";
|
|
816570
816570
|
var _sdkVersion = "0.33.35";
|
|
816571
816571
|
try {
|
|
816572
816572
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf-8"));
|
|
@@ -847775,13 +847775,13 @@ init_state3();
|
|
|
847775
847775
|
|
|
847776
847776
|
// src/input/commands/recall-shared.ts
|
|
847777
847777
|
var VALID_CLASSES = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
|
|
847778
|
-
var
|
|
847778
|
+
var VALID_SCOPES2 = ["session", "project", "team"];
|
|
847779
847779
|
var VALID_REVIEW_STATES = ["fresh", "reviewed", "stale", "contradicted"];
|
|
847780
847780
|
function isValidClass(s4) {
|
|
847781
847781
|
return VALID_CLASSES.includes(s4);
|
|
847782
847782
|
}
|
|
847783
847783
|
function isValidScope(s4) {
|
|
847784
|
-
return
|
|
847784
|
+
return VALID_SCOPES2.includes(s4);
|
|
847785
847785
|
}
|
|
847786
847786
|
function isValidReviewState(s4) {
|
|
847787
847787
|
return VALID_REVIEW_STATES.includes(s4);
|
|
@@ -847824,7 +847824,7 @@ function handleRecallSearch(args2, context) {
|
|
|
847824
847824
|
if (isValidScope(scope))
|
|
847825
847825
|
filter.scope = scope;
|
|
847826
847826
|
else {
|
|
847827
|
-
context.print(`[memory] Unknown scope "${scope}". Valid values ${
|
|
847827
|
+
context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
|
|
847828
847828
|
return;
|
|
847829
847829
|
}
|
|
847830
847830
|
}
|
|
@@ -847999,7 +847999,7 @@ function handleRecallList(args2, context) {
|
|
|
847999
847999
|
if (scopeIdx !== -1 && args2[scopeIdx + 1]) {
|
|
848000
848000
|
const scope = args2[scopeIdx + 1];
|
|
848001
848001
|
if (!isValidScope(scope)) {
|
|
848002
|
-
context.print(`[memory] Unknown scope "${scope}". Valid values ${
|
|
848002
|
+
context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
|
|
848003
848003
|
return;
|
|
848004
848004
|
}
|
|
848005
848005
|
filter.scope = scope;
|
|
@@ -848049,7 +848049,7 @@ async function handleRecallAdd(args2, context) {
|
|
|
848049
848049
|
const tags = tagsRaw ? tagsRaw.split(",").map((token) => token.trim()).filter(Boolean) : [];
|
|
848050
848050
|
const scope = scopeRaw && isValidScope(scopeRaw) ? scopeRaw : "project";
|
|
848051
848051
|
if (scopeRaw && !isValidScope(scopeRaw)) {
|
|
848052
|
-
context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${
|
|
848052
|
+
context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES2.join(", ")}.`);
|
|
848053
848053
|
return;
|
|
848054
848054
|
}
|
|
848055
848055
|
const provenance = [];
|
|
@@ -848183,7 +848183,7 @@ function handleRecallExport(args2, context) {
|
|
|
848183
848183
|
if (scopeIdx !== -1 && commandArgs[scopeIdx + 1]) {
|
|
848184
848184
|
const scope = commandArgs[scopeIdx + 1];
|
|
848185
848185
|
if (!isValidScope(scope)) {
|
|
848186
|
-
context.print(`[memory] Unknown scope "${scope}". Valid values ${
|
|
848186
|
+
context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
|
|
848187
848187
|
return;
|
|
848188
848188
|
}
|
|
848189
848189
|
filter.scope = scope;
|
|
@@ -848262,7 +848262,7 @@ function handleRecallHandoffExport(args2, context) {
|
|
|
848262
848262
|
const scopeIdx = commandArgs.indexOf("--scope");
|
|
848263
848263
|
const scopeRaw = scopeIdx !== -1 ? commandArgs[scopeIdx + 1] : "team";
|
|
848264
848264
|
if (!scopeRaw || !isValidScope(scopeRaw)) {
|
|
848265
|
-
context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${
|
|
848265
|
+
context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES2.join(", ")}.`);
|
|
848266
848266
|
return;
|
|
848267
848267
|
}
|
|
848268
848268
|
const bundle = memory.exportBundle({ scope: scopeRaw });
|
|
@@ -848378,7 +848378,7 @@ function handleRecallPromote(args2, context) {
|
|
|
848378
848378
|
const id = parsed.rest[0];
|
|
848379
848379
|
const scope = parsed.rest[1];
|
|
848380
848380
|
if (!id || !scope || !isValidScope(scope)) {
|
|
848381
|
-
context.print(`[memory] Usage: /memory promote <id> <${
|
|
848381
|
+
context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES2.join("|")}> --yes`);
|
|
848382
848382
|
return;
|
|
848383
848383
|
}
|
|
848384
848384
|
if (!parsed.yes) {
|
|
@@ -862223,7 +862223,7 @@ import { mkdirSync as mkdirSync64, readFileSync as readFileSync86, writeFileSync
|
|
|
862223
862223
|
import { dirname as dirname63, resolve as resolve39 } from "path";
|
|
862224
862224
|
init_state3();
|
|
862225
862225
|
var VALID_CLASSES2 = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
|
|
862226
|
-
var
|
|
862226
|
+
var VALID_SCOPES4 = ["session", "project", "team"];
|
|
862227
862227
|
var VALID_REVIEW_STATES3 = ["fresh", "reviewed", "stale", "contradicted"];
|
|
862228
862228
|
var VALID_PROVENANCE_KINDS = ["session", "turn", "task", "event", "file"];
|
|
862229
862229
|
var VALUE_OPTIONS = new Set([
|
|
@@ -862323,7 +862323,7 @@ function isMemoryClass2(value) {
|
|
|
862323
862323
|
return VALID_CLASSES2.includes(value);
|
|
862324
862324
|
}
|
|
862325
862325
|
function isMemoryScope2(value) {
|
|
862326
|
-
return
|
|
862326
|
+
return VALID_SCOPES4.includes(value);
|
|
862327
862327
|
}
|
|
862328
862328
|
function isReviewState(value) {
|
|
862329
862329
|
return VALID_REVIEW_STATES3.includes(value);
|
|
@@ -862338,7 +862338,7 @@ function requireClass(value) {
|
|
|
862338
862338
|
}
|
|
862339
862339
|
function requireScope(value) {
|
|
862340
862340
|
if (!value || !isMemoryScope2(value))
|
|
862341
|
-
throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${
|
|
862341
|
+
throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES4.join(", ")}`);
|
|
862342
862342
|
return value;
|
|
862343
862343
|
}
|
|
862344
862344
|
function optionalScope(value) {
|
|
@@ -879834,6 +879834,126 @@ function describeHarnessCliCommand(args2) {
|
|
|
879834
879834
|
};
|
|
879835
879835
|
}
|
|
879836
879836
|
|
|
879837
|
+
// src/tools/agent-harness-command-catalog.ts
|
|
879838
|
+
function readString51(value) {
|
|
879839
|
+
return typeof value === "string" ? value.trim() : "";
|
|
879840
|
+
}
|
|
879841
|
+
function readLimit6(value, fallback) {
|
|
879842
|
+
const parsed = typeof value === "string" && value.trim() ? Number(value) : value;
|
|
879843
|
+
if (typeof parsed !== "number" || !Number.isFinite(parsed))
|
|
879844
|
+
return fallback;
|
|
879845
|
+
return Math.max(1, Math.min(500, Math.trunc(parsed)));
|
|
879846
|
+
}
|
|
879847
|
+
function readStringArray12(value) {
|
|
879848
|
+
if (!Array.isArray(value))
|
|
879849
|
+
return [];
|
|
879850
|
+
return value.map((entry) => typeof entry === "string" ? entry : String(entry));
|
|
879851
|
+
}
|
|
879852
|
+
function commandMatches(command8, query2) {
|
|
879853
|
+
if (!query2)
|
|
879854
|
+
return true;
|
|
879855
|
+
const haystack = [
|
|
879856
|
+
command8.name,
|
|
879857
|
+
...command8.aliases ?? [],
|
|
879858
|
+
command8.description,
|
|
879859
|
+
command8.usage ?? "",
|
|
879860
|
+
command8.argsHint ?? ""
|
|
879861
|
+
].join(`
|
|
879862
|
+
`).toLowerCase();
|
|
879863
|
+
return haystack.includes(query2.toLowerCase());
|
|
879864
|
+
}
|
|
879865
|
+
function describeCommand(command8, lookup) {
|
|
879866
|
+
return {
|
|
879867
|
+
name: command8.name,
|
|
879868
|
+
slash: `/${command8.name}`,
|
|
879869
|
+
aliases: command8.aliases ?? [],
|
|
879870
|
+
description: command8.description,
|
|
879871
|
+
usage: command8.usage ?? "",
|
|
879872
|
+
argsHint: command8.argsHint ?? command8.usage ?? "",
|
|
879873
|
+
...lookup ? {
|
|
879874
|
+
lookup: {
|
|
879875
|
+
source: lookup.source,
|
|
879876
|
+
input: lookup.input,
|
|
879877
|
+
parsedName: lookup.parsedName,
|
|
879878
|
+
parsedArgs: lookup.parsedArgs,
|
|
879879
|
+
resolvedBy: lookup.resolvedBy
|
|
879880
|
+
}
|
|
879881
|
+
} : {},
|
|
879882
|
+
policy: describeCommandPolicy(command8.name)
|
|
879883
|
+
};
|
|
879884
|
+
}
|
|
879885
|
+
function commandDetailLookupFromArgs(args2) {
|
|
879886
|
+
const rawCommand = readString51(args2.command);
|
|
879887
|
+
if (rawCommand) {
|
|
879888
|
+
const parsed = parseSlashCommand(rawCommand);
|
|
879889
|
+
return { source: "command", input: rawCommand, parsedName: parsed.name, parsedArgs: parsed.args };
|
|
879890
|
+
}
|
|
879891
|
+
const rawCommandName = readString51(args2.commandName);
|
|
879892
|
+
if (rawCommandName) {
|
|
879893
|
+
const parsed = parseSlashCommand(rawCommandName);
|
|
879894
|
+
const explicitArgs = readStringArray12(args2.args);
|
|
879895
|
+
return {
|
|
879896
|
+
source: "commandName",
|
|
879897
|
+
input: rawCommandName,
|
|
879898
|
+
parsedName: parsed.name,
|
|
879899
|
+
parsedArgs: explicitArgs.length > 0 ? explicitArgs : parsed.args
|
|
879900
|
+
};
|
|
879901
|
+
}
|
|
879902
|
+
const rawTarget = readString51(args2.target);
|
|
879903
|
+
if (rawTarget) {
|
|
879904
|
+
const parsed = parseSlashCommand(rawTarget);
|
|
879905
|
+
return { source: "target", input: rawTarget, parsedName: parsed.name, parsedArgs: parsed.args };
|
|
879906
|
+
}
|
|
879907
|
+
const rawQuery = readString51(args2.query);
|
|
879908
|
+
if (rawQuery) {
|
|
879909
|
+
const parsed = parseSlashCommand(rawQuery);
|
|
879910
|
+
return { source: "query", input: rawQuery, parsedName: parsed.name, parsedArgs: parsed.args };
|
|
879911
|
+
}
|
|
879912
|
+
return null;
|
|
879913
|
+
}
|
|
879914
|
+
function resolveCommandDetail(commandRegistry, args2) {
|
|
879915
|
+
const lookup = commandDetailLookupFromArgs(args2);
|
|
879916
|
+
if (!lookup?.parsedName)
|
|
879917
|
+
return null;
|
|
879918
|
+
const direct = commandRegistry.get(lookup.parsedName);
|
|
879919
|
+
if (direct) {
|
|
879920
|
+
return {
|
|
879921
|
+
command: direct,
|
|
879922
|
+
lookup: {
|
|
879923
|
+
...lookup,
|
|
879924
|
+
resolvedBy: direct.name === lookup.parsedName ? "name" : "alias"
|
|
879925
|
+
}
|
|
879926
|
+
};
|
|
879927
|
+
}
|
|
879928
|
+
const normalized = lookup.parsedName.toLowerCase();
|
|
879929
|
+
for (const command8 of commandRegistry.list()) {
|
|
879930
|
+
if (command8.name.toLowerCase() === normalized) {
|
|
879931
|
+
return { command: command8, lookup: { ...lookup, resolvedBy: "case-insensitive-name" } };
|
|
879932
|
+
}
|
|
879933
|
+
if ((command8.aliases ?? []).some((alias) => alias.toLowerCase() === normalized)) {
|
|
879934
|
+
return { command: command8, lookup: { ...lookup, resolvedBy: "case-insensitive-alias" } };
|
|
879935
|
+
}
|
|
879936
|
+
}
|
|
879937
|
+
const descriptionMatches = commandRegistry.list().filter((command8) => commandMatches(command8, lookup.input));
|
|
879938
|
+
if (descriptionMatches.length === 1) {
|
|
879939
|
+
return { command: descriptionMatches[0], lookup: { ...lookup, resolvedBy: "description" } };
|
|
879940
|
+
}
|
|
879941
|
+
const prefixMatches = commandRegistry.fuzzyMatch(lookup.parsedName).filter((entry) => entry.score >= 80);
|
|
879942
|
+
if (prefixMatches.length === 1) {
|
|
879943
|
+
return { command: prefixMatches[0].command, lookup: { ...lookup, resolvedBy: "prefix" } };
|
|
879944
|
+
}
|
|
879945
|
+
return null;
|
|
879946
|
+
}
|
|
879947
|
+
function listHarnessCommands(commandRegistry, args2) {
|
|
879948
|
+
const query2 = readString51(args2.query);
|
|
879949
|
+
const limit3 = readLimit6(args2.limit, 200);
|
|
879950
|
+
return commandRegistry.list().filter((command8) => commandMatches(command8, query2)).sort((a4, b3) => a4.name.localeCompare(b3.name)).slice(0, limit3).map((command8) => describeCommand(command8));
|
|
879951
|
+
}
|
|
879952
|
+
function describeHarnessCommand(commandRegistry, args2) {
|
|
879953
|
+
const detail = resolveCommandDetail(commandRegistry, args2);
|
|
879954
|
+
return detail ? describeCommand(detail.command, detail.lookup) : null;
|
|
879955
|
+
}
|
|
879956
|
+
|
|
879837
879957
|
// src/tools/agent-harness-keybinding-metadata.ts
|
|
879838
879958
|
import { existsSync as existsSync82, mkdirSync as mkdirSync67, readFileSync as readFileSync89, writeFileSync as writeFileSync58 } from "fs";
|
|
879839
879959
|
import { dirname as dirname66 } from "path";
|
|
@@ -879847,10 +879967,10 @@ var FIXED_SHORTCUTS = [
|
|
|
879847
879967
|
{ key: "F2 / /shortcuts", description: "Open keyboard shortcut reference" },
|
|
879848
879968
|
{ key: "/keybindings", description: "List configurable keybindings and config path" }
|
|
879849
879969
|
];
|
|
879850
|
-
function
|
|
879970
|
+
function readString52(value) {
|
|
879851
879971
|
return typeof value === "string" ? value.trim() : "";
|
|
879852
879972
|
}
|
|
879853
|
-
function
|
|
879973
|
+
function readLimit7(value, fallback) {
|
|
879854
879974
|
const parsed = typeof value === "string" && value.trim() ? Number(value) : value;
|
|
879855
879975
|
if (typeof parsed !== "number" || !Number.isFinite(parsed))
|
|
879856
879976
|
return fallback;
|
|
@@ -879871,7 +879991,7 @@ function isKeyAction2(action2) {
|
|
|
879871
879991
|
return Object.hasOwn(ACTION_DESCRIPTIONS, action2);
|
|
879872
879992
|
}
|
|
879873
879993
|
function actionFromArgs(args2) {
|
|
879874
|
-
const action2 =
|
|
879994
|
+
const action2 = readString52(args2.actionId || args2.key || args2.query);
|
|
879875
879995
|
return action2 && isKeyAction2(action2) ? action2 : null;
|
|
879876
879996
|
}
|
|
879877
879997
|
function readBoolean15(value) {
|
|
@@ -879890,7 +880010,7 @@ function normalizeCombo(value) {
|
|
|
879890
880010
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
879891
880011
|
return null;
|
|
879892
880012
|
const raw = value;
|
|
879893
|
-
const key =
|
|
880013
|
+
const key = readString52(raw.key);
|
|
879894
880014
|
if (!key)
|
|
879895
880015
|
return null;
|
|
879896
880016
|
const combo = { key };
|
|
@@ -879940,7 +880060,7 @@ function combosFromArgs(args2) {
|
|
|
879940
880060
|
const fieldCombo = normalizeCombo(fields);
|
|
879941
880061
|
if (fieldCombo)
|
|
879942
880062
|
return [fieldCombo];
|
|
879943
|
-
const labelCombo = parseComboLabel(
|
|
880063
|
+
const labelCombo = parseComboLabel(readString52(args2.value));
|
|
879944
880064
|
if (labelCombo)
|
|
879945
880065
|
return [labelCombo];
|
|
879946
880066
|
throw new Error('set_keybinding requires combo, combos, fields.key, or a value such as "Ctrl+G".');
|
|
@@ -880008,9 +880128,9 @@ function totalHarnessShortcuts(context) {
|
|
|
880008
880128
|
}
|
|
880009
880129
|
function listHarnessShortcuts(context, args2) {
|
|
880010
880130
|
const keybindings = listHarnessKeybindings(context, args2);
|
|
880011
|
-
const query2 =
|
|
880131
|
+
const query2 = readString52(args2.query).toLowerCase();
|
|
880012
880132
|
const fixed = FIXED_SHORTCUTS.filter((shortcut) => !query2 || `${shortcut.key}
|
|
880013
|
-
${shortcut.description}`.toLowerCase().includes(query2)).slice(0,
|
|
880133
|
+
${shortcut.description}`.toLowerCase().includes(query2)).slice(0, readLimit7(args2.limit, 200)).map((shortcut) => ({ ...shortcut, source: "fixed", userEditable: false }));
|
|
880014
880134
|
return {
|
|
880015
880135
|
configPath: keybindings.configPath,
|
|
880016
880136
|
fixedShortcuts: fixed,
|
|
@@ -880022,8 +880142,8 @@ ${shortcut.description}`.toLowerCase().includes(query2)).slice(0, readLimit6(arg
|
|
|
880022
880142
|
}
|
|
880023
880143
|
function listHarnessKeybindings(context, args2) {
|
|
880024
880144
|
const manager5 = requireKeybindingsManager2(context);
|
|
880025
|
-
const query2 =
|
|
880026
|
-
const entries = manager5.getAll().filter((entry) => bindingMatches(entry, query2)).slice(0,
|
|
880145
|
+
const query2 = readString52(args2.query);
|
|
880146
|
+
const entries = manager5.getAll().filter((entry) => bindingMatches(entry, query2)).slice(0, readLimit7(args2.limit, 200)).map((entry) => describeBinding(manager5, entry.action, entry.combos));
|
|
880027
880147
|
return {
|
|
880028
880148
|
configPath: manager5.getConfigPath(),
|
|
880029
880149
|
keybindings: entries,
|
|
@@ -880078,10 +880198,10 @@ function resetHarnessKeybinding(context, args2) {
|
|
|
880078
880198
|
}
|
|
880079
880199
|
|
|
880080
880200
|
// src/tools/agent-harness-panel-metadata.ts
|
|
880081
|
-
function
|
|
880201
|
+
function readString53(value) {
|
|
880082
880202
|
return typeof value === "string" ? value.trim() : "";
|
|
880083
880203
|
}
|
|
880084
|
-
function
|
|
880204
|
+
function readLimit8(value, fallback) {
|
|
880085
880205
|
const parsed = typeof value === "string" && value.trim() ? Number(value) : value;
|
|
880086
880206
|
if (typeof parsed !== "number" || !Number.isFinite(parsed))
|
|
880087
880207
|
return fallback;
|
|
@@ -880136,16 +880256,16 @@ function listHarnessPanels(context, args2) {
|
|
|
880136
880256
|
const manager5 = panelManager(context);
|
|
880137
880257
|
if (!manager5)
|
|
880138
880258
|
return [];
|
|
880139
|
-
const query2 =
|
|
880140
|
-
const category =
|
|
880141
|
-
const limit3 =
|
|
880259
|
+
const query2 = readString53(args2.query);
|
|
880260
|
+
const category = readString53(args2.category);
|
|
880261
|
+
const limit3 = readLimit8(args2.limit, 200);
|
|
880142
880262
|
return manager5.getRegisteredTypes().map((registration) => describePanelRegistration(context, registration)).filter((panel) => !category || panel.category === category).filter((panel) => panelMatches(panel, query2)).sort((a4, b3) => String(a4.id).localeCompare(String(b3.id))).slice(0, limit3);
|
|
880143
880263
|
}
|
|
880144
880264
|
function describeHarnessPanel(context, args2) {
|
|
880145
880265
|
const manager5 = panelManager(context);
|
|
880146
880266
|
if (!manager5)
|
|
880147
880267
|
return null;
|
|
880148
|
-
const panelId =
|
|
880268
|
+
const panelId = readString53(args2.panelId || args2.query);
|
|
880149
880269
|
if (!panelId)
|
|
880150
880270
|
return null;
|
|
880151
880271
|
const registration = manager5.getRegisteredTypes().find((panel) => panel.id === panelId || panel.name.toLowerCase() === panelId.toLowerCase());
|
|
@@ -880156,11 +880276,11 @@ function openHarnessPanel(context, args2) {
|
|
|
880156
880276
|
if (!panel) {
|
|
880157
880277
|
return {
|
|
880158
880278
|
status: "unknown_panel",
|
|
880159
|
-
panelId:
|
|
880279
|
+
panelId: readString53(args2.panelId || args2.query) || "<missing>",
|
|
880160
880280
|
availablePanels: listHarnessPanels(context, { limit: 50 }).map((entry) => entry.id)
|
|
880161
880281
|
};
|
|
880162
880282
|
}
|
|
880163
|
-
const requestedPane =
|
|
880283
|
+
const requestedPane = readString53(args2.pane);
|
|
880164
880284
|
const pane = requestedPane === "bottom" || requestedPane === "top" ? requestedPane : undefined;
|
|
880165
880285
|
if (!context.showPanel) {
|
|
880166
880286
|
return {
|
|
@@ -880184,7 +880304,7 @@ import { join as join98 } from "path";
|
|
|
880184
880304
|
function isRecord42(value) {
|
|
880185
880305
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
880186
880306
|
}
|
|
880187
|
-
function
|
|
880307
|
+
function readString54(record2, key) {
|
|
880188
880308
|
const value = record2?.[key];
|
|
880189
880309
|
return typeof value === "string" ? value : null;
|
|
880190
880310
|
}
|
|
@@ -880235,7 +880355,7 @@ async function inspectCliExternalRuntime(options) {
|
|
|
880235
880355
|
try {
|
|
880236
880356
|
const status = await fetchJson2(`${baseUrl}/status`, token.token, timeoutMs);
|
|
880237
880357
|
const statusRecord = isRecord42(status.body) ? status.body : {};
|
|
880238
|
-
const version6 =
|
|
880358
|
+
const version6 = readString54(statusRecord, "version") ?? "unknown";
|
|
880239
880359
|
const compatible = status.ok && version6 === SDK_VERSION;
|
|
880240
880360
|
if (!status.ok) {
|
|
880241
880361
|
return {
|
|
@@ -880453,7 +880573,7 @@ function output6(value) {
|
|
|
880453
880573
|
function error51(message) {
|
|
880454
880574
|
return { success: false, error: message };
|
|
880455
880575
|
}
|
|
880456
|
-
function
|
|
880576
|
+
function readString55(value) {
|
|
880457
880577
|
return typeof value === "string" ? value.trim() : "";
|
|
880458
880578
|
}
|
|
880459
880579
|
function readFieldMap2(value) {
|
|
@@ -880480,10 +880600,10 @@ function describeEditor(editor) {
|
|
|
880480
880600
|
}
|
|
880481
880601
|
function readRecordId(args2) {
|
|
880482
880602
|
const fields = readFieldMap2(args2.fields);
|
|
880483
|
-
return
|
|
880603
|
+
return readString55(args2.recordId ?? args2.id ?? fields.recordId ?? fields.id);
|
|
880484
880604
|
}
|
|
880485
880605
|
function requireConfirmed(args2, label) {
|
|
880486
|
-
if (!
|
|
880606
|
+
if (!readString55(args2.explicitUserRequest))
|
|
880487
880607
|
return `${label} requires explicitUserRequest with the user's exact request or a short faithful summary.`;
|
|
880488
880608
|
if (args2.confirm !== true)
|
|
880489
880609
|
return `${label} requires confirm:true after an explicit user request.`;
|
|
@@ -880611,7 +880731,7 @@ function localRegistryArgsForTarget(target, args2, recordId) {
|
|
|
880611
880731
|
...base2,
|
|
880612
880732
|
...edit,
|
|
880613
880733
|
...target.action === "stale" && fields.reason ? { reason: fields.reason } : {},
|
|
880614
|
-
...target.action === "delete" ? { confirm: args2.confirm, explicitUserRequest:
|
|
880734
|
+
...target.action === "delete" ? { confirm: args2.confirm, explicitUserRequest: readString55(args2.explicitUserRequest) } : {}
|
|
880615
880735
|
};
|
|
880616
880736
|
}
|
|
880617
880737
|
async function executeTool(toolRegistry, name51, toolArgs) {
|
|
@@ -880677,7 +880797,7 @@ async function runLocalWorkspaceAction(deps, action2, args2) {
|
|
|
880677
880797
|
if (missing.length > 0)
|
|
880678
880798
|
return output6({ status: "missing_required_fields", missing, action: action2.id, editor: describeEditor(editor) });
|
|
880679
880799
|
if (editor.kind === "knowledge-url")
|
|
880680
|
-
return executeTool(deps.toolRegistry, "agent_knowledge_ingest", { sourceKind: "url", url: fieldReader(editor, fields)("url"), tags: splitList5(fieldReader(editor, fields)("tags")), folderPath: fieldReader(editor, fields)("folder"), confirm: args2.confirm, explicitUserRequest:
|
|
880800
|
+
return executeTool(deps.toolRegistry, "agent_knowledge_ingest", { sourceKind: "url", url: fieldReader(editor, fields)("url"), tags: splitList5(fieldReader(editor, fields)("tags")), folderPath: fieldReader(editor, fields)("folder"), confirm: args2.confirm, explicitUserRequest: readString55(args2.explicitUserRequest) });
|
|
880681
880801
|
return executeTool(deps.toolRegistry, "agent_local_registry", localRegistryArgsFromEditor(editor, fields, recordId));
|
|
880682
880802
|
}
|
|
880683
880803
|
if (!target)
|
|
@@ -880686,19 +880806,19 @@ async function runLocalWorkspaceAction(deps, action2, args2) {
|
|
|
880686
880806
|
}
|
|
880687
880807
|
|
|
880688
880808
|
// src/tools/agent-harness-model-tool-catalog.ts
|
|
880689
|
-
function
|
|
880809
|
+
function readString56(value) {
|
|
880690
880810
|
return typeof value === "string" ? value.trim() : "";
|
|
880691
880811
|
}
|
|
880692
|
-
function
|
|
880812
|
+
function readLimit9(value, fallback) {
|
|
880693
880813
|
const parsed = typeof value === "string" && value.trim() ? Number(value) : value;
|
|
880694
880814
|
if (typeof parsed !== "number" || !Number.isFinite(parsed))
|
|
880695
880815
|
return fallback;
|
|
880696
880816
|
return Math.max(1, Math.min(500, Math.trunc(parsed)));
|
|
880697
880817
|
}
|
|
880698
880818
|
function listHarnessModelTools(toolRegistry, args2) {
|
|
880699
|
-
const query2 =
|
|
880819
|
+
const query2 = readString56(args2.query).toLowerCase();
|
|
880700
880820
|
const includeParameters = args2.includeParameters === true;
|
|
880701
|
-
const limit3 =
|
|
880821
|
+
const limit3 = readLimit9(args2.limit, 200);
|
|
880702
880822
|
return toolRegistry.getToolDefinitions().filter((tool2) => !query2 || [tool2.name, tool2.description, ...tool2.sideEffects ?? []].join(`
|
|
880703
880823
|
`).toLowerCase().includes(query2)).sort((a4, b3) => a4.name.localeCompare(b3.name)).slice(0, limit3).map((tool2) => ({
|
|
880704
880824
|
name: tool2.name,
|
|
@@ -880711,7 +880831,7 @@ function listHarnessModelTools(toolRegistry, args2) {
|
|
|
880711
880831
|
}));
|
|
880712
880832
|
}
|
|
880713
880833
|
function describeHarnessModelTool(toolRegistry, args2) {
|
|
880714
|
-
const query2 =
|
|
880834
|
+
const query2 = readString56(args2.toolName || args2.target || args2.query).toLowerCase();
|
|
880715
880835
|
if (!query2)
|
|
880716
880836
|
return null;
|
|
880717
880837
|
const tool2 = toolRegistry.getToolDefinitions().find((candidate) => candidate.name.toLowerCase() === query2 || candidate.name.toLowerCase().includes(query2));
|
|
@@ -880777,11 +880897,11 @@ var AGENT_HARNESS_PARAMETER_PROPERTIES = {
|
|
|
880777
880897
|
},
|
|
880778
880898
|
query: {
|
|
880779
880899
|
type: "string",
|
|
880780
|
-
description: "Search text for command, setting, tool, or UI surface catalogs."
|
|
880900
|
+
description: "Search text for command, setting, tool, or UI surface catalogs, or a slash-command lookup for mode command."
|
|
880781
880901
|
},
|
|
880782
880902
|
command: {
|
|
880783
880903
|
type: "string",
|
|
880784
|
-
description: 'Full slash command string for mode run_command, for example "/settings get provider.model". In cli_command mode this may also hold a top-level CLI string such as "goodvibes-agent status --json".'
|
|
880904
|
+
description: 'Full slash command string for mode command or run_command, for example "/settings get provider.model". In cli_command mode this may also hold a top-level CLI string such as "goodvibes-agent status --json".'
|
|
880785
880905
|
},
|
|
880786
880906
|
cliCommand: {
|
|
880787
880907
|
type: "string",
|
|
@@ -880844,7 +880964,7 @@ var AGENT_HARNESS_PARAMETER_PROPERTIES = {
|
|
|
880844
880964
|
},
|
|
880845
880965
|
target: {
|
|
880846
880966
|
type: "string",
|
|
880847
|
-
description: "Optional lookup target, such as a model-picker target, settings key, model tool name, or connected-host capability id."
|
|
880967
|
+
description: "Optional lookup target, such as a model-picker target, slash command root or invocation, settings key, model tool name, or connected-host capability id."
|
|
880848
880968
|
},
|
|
880849
880969
|
capabilityId: {
|
|
880850
880970
|
type: "string",
|
|
@@ -880985,10 +881105,10 @@ async function openTtsVoicePicker(ctx, providerArg) {
|
|
|
880985
881105
|
}
|
|
880986
881106
|
|
|
880987
881107
|
// src/tools/agent-harness-ui-surface-metadata.ts
|
|
880988
|
-
function
|
|
881108
|
+
function readString57(value) {
|
|
880989
881109
|
return typeof value === "string" ? value.trim() : "";
|
|
880990
881110
|
}
|
|
880991
|
-
function
|
|
881111
|
+
function readLimit10(value, fallback) {
|
|
880992
881112
|
const parsed = typeof value === "string" && value.trim() ? Number(value) : value;
|
|
880993
881113
|
if (typeof parsed !== "number" || !Number.isFinite(parsed))
|
|
880994
881114
|
return fallback;
|
|
@@ -881011,35 +881131,35 @@ function opened(surface, extra = {}) {
|
|
|
881011
881131
|
};
|
|
881012
881132
|
}
|
|
881013
881133
|
function optionalModelTarget(args2) {
|
|
881014
|
-
const target =
|
|
881134
|
+
const target = readString57(args2.target);
|
|
881015
881135
|
return target === "main" || target === "helper" || target === "tool" || target === "tts" ? target : undefined;
|
|
881016
881136
|
}
|
|
881017
881137
|
function optionalOnboardingMode(args2) {
|
|
881018
|
-
const target =
|
|
881138
|
+
const target = readString57(args2.target);
|
|
881019
881139
|
return target === "new" || target === "edit" || target === "reopen" ? target : undefined;
|
|
881020
881140
|
}
|
|
881021
881141
|
function workspaceCategory(args2) {
|
|
881022
|
-
return
|
|
881142
|
+
return readString57(args2.categoryId || args2.category || args2.target) || undefined;
|
|
881023
881143
|
}
|
|
881024
881144
|
function settingsTarget(args2) {
|
|
881025
|
-
return
|
|
881145
|
+
return readString57(args2.target || args2.key || args2.prefix) || undefined;
|
|
881026
881146
|
}
|
|
881027
881147
|
function providerTarget(args2) {
|
|
881028
|
-
return
|
|
881148
|
+
return readString57(args2.target || args2.key || args2.prefix) || undefined;
|
|
881029
881149
|
}
|
|
881030
881150
|
function optionalPane(args2) {
|
|
881031
|
-
const pane =
|
|
881151
|
+
const pane = readString57(args2.pane);
|
|
881032
881152
|
return pane === "top" || pane === "bottom" ? pane : undefined;
|
|
881033
881153
|
}
|
|
881034
881154
|
function surfaceInputText(args2) {
|
|
881035
|
-
return
|
|
881155
|
+
return readString57(args2.prefix || args2.key || (args2.surfaceId ? args2.query : undefined) || args2.target) || undefined;
|
|
881036
881156
|
}
|
|
881037
881157
|
function filePickerOptions(args2) {
|
|
881038
|
-
const target =
|
|
881158
|
+
const target = readString57(args2.target).toLowerCase();
|
|
881039
881159
|
const injectMode = target === "inject" || target === "inject-mode" || target === "!@";
|
|
881040
881160
|
return {
|
|
881041
881161
|
injectMode,
|
|
881042
|
-
query:
|
|
881162
|
+
query: readString57(args2.prefix || args2.key || (args2.surfaceId ? args2.query : undefined)) || undefined
|
|
881043
881163
|
};
|
|
881044
881164
|
}
|
|
881045
881165
|
function openAgentWorkspaceCategory(context, surface, categoryId, extra = {}) {
|
|
@@ -881615,19 +881735,19 @@ function totalHarnessUiSurfaces() {
|
|
|
881615
881735
|
return UI_SURFACES.length;
|
|
881616
881736
|
}
|
|
881617
881737
|
function listHarnessUiSurfaces(context, args2) {
|
|
881618
|
-
const query2 =
|
|
881619
|
-
const limit3 =
|
|
881738
|
+
const query2 = readString57(args2.query);
|
|
881739
|
+
const limit3 = readLimit10(args2.limit, 200);
|
|
881620
881740
|
return UI_SURFACES.map((surface) => describeSurface(context, surface)).filter((surface) => surfaceMatches(surface, query2)).slice(0, limit3);
|
|
881621
881741
|
}
|
|
881622
881742
|
function describeHarnessUiSurface(context, args2) {
|
|
881623
|
-
const surfaceId =
|
|
881743
|
+
const surfaceId = readString57(args2.surfaceId || args2.query);
|
|
881624
881744
|
if (!surfaceId)
|
|
881625
881745
|
return null;
|
|
881626
881746
|
const surface = UI_SURFACES.find((entry) => entry.id === surfaceId || entry.label.toLowerCase() === surfaceId.toLowerCase());
|
|
881627
881747
|
return surface ? describeSurface(context, surface) : null;
|
|
881628
881748
|
}
|
|
881629
881749
|
async function openHarnessUiSurface(context, args2) {
|
|
881630
|
-
const surfaceId =
|
|
881750
|
+
const surfaceId = readString57(args2.surfaceId || args2.query);
|
|
881631
881751
|
const surface = UI_SURFACES.find((entry) => entry.id === surfaceId || entry.label.toLowerCase() === surfaceId.toLowerCase());
|
|
881632
881752
|
if (!surface) {
|
|
881633
881753
|
return {
|
|
@@ -881647,16 +881767,16 @@ async function openHarnessUiSurface(context, args2) {
|
|
|
881647
881767
|
function isMode(value) {
|
|
881648
881768
|
return typeof value === "string" && AGENT_HARNESS_MODES.includes(value);
|
|
881649
881769
|
}
|
|
881650
|
-
function
|
|
881770
|
+
function readString58(value) {
|
|
881651
881771
|
return typeof value === "string" ? value.trim() : "";
|
|
881652
881772
|
}
|
|
881653
|
-
function
|
|
881773
|
+
function readLimit11(value, fallback) {
|
|
881654
881774
|
const parsed = typeof value === "string" && value.trim() ? Number(value) : value;
|
|
881655
881775
|
if (typeof parsed !== "number" || !Number.isFinite(parsed))
|
|
881656
881776
|
return fallback;
|
|
881657
881777
|
return Math.max(1, Math.min(500, Math.trunc(parsed)));
|
|
881658
881778
|
}
|
|
881659
|
-
function
|
|
881779
|
+
function readStringArray13(value) {
|
|
881660
881780
|
if (!Array.isArray(value))
|
|
881661
881781
|
return [];
|
|
881662
881782
|
return value.map((entry) => typeof entry === "string" ? entry : String(entry));
|
|
@@ -881675,30 +881795,6 @@ function output7(value) {
|
|
|
881675
881795
|
function error52(message) {
|
|
881676
881796
|
return { success: false, error: message };
|
|
881677
881797
|
}
|
|
881678
|
-
function commandMatches(command8, query2) {
|
|
881679
|
-
if (!query2)
|
|
881680
|
-
return true;
|
|
881681
|
-
const haystack = [
|
|
881682
|
-
command8.name,
|
|
881683
|
-
...command8.aliases ?? [],
|
|
881684
|
-
command8.description,
|
|
881685
|
-
command8.usage ?? "",
|
|
881686
|
-
command8.argsHint ?? ""
|
|
881687
|
-
].join(`
|
|
881688
|
-
`).toLowerCase();
|
|
881689
|
-
return haystack.includes(query2.toLowerCase());
|
|
881690
|
-
}
|
|
881691
|
-
function describeCommand(command8) {
|
|
881692
|
-
return {
|
|
881693
|
-
name: command8.name,
|
|
881694
|
-
slash: `/${command8.name}`,
|
|
881695
|
-
aliases: command8.aliases ?? [],
|
|
881696
|
-
description: command8.description,
|
|
881697
|
-
usage: command8.usage ?? "",
|
|
881698
|
-
argsHint: command8.argsHint ?? command8.usage ?? "",
|
|
881699
|
-
policy: describeCommandPolicy(command8.name)
|
|
881700
|
-
};
|
|
881701
|
-
}
|
|
881702
881798
|
function allWorkspaceActions() {
|
|
881703
881799
|
return AGENT_WORKSPACE_CATEGORIES.flatMap((category) => category.actions.map((action2) => ({ category, action: action2 })));
|
|
881704
881800
|
}
|
|
@@ -881731,7 +881827,7 @@ function describeWorkspaceEditor(editor) {
|
|
|
881731
881827
|
}
|
|
881732
881828
|
function selectedRoutineFromArgs(snapshot, args2) {
|
|
881733
881829
|
const fields = readFieldMap3(args2.fields);
|
|
881734
|
-
const routineId =
|
|
881830
|
+
const routineId = readString58(args2.recordId) || readString58(fields.routineId) || readString58(fields.id);
|
|
881735
881831
|
if (!routineId)
|
|
881736
881832
|
return null;
|
|
881737
881833
|
return snapshot.localRoutines.find((routine) => routine.id === routineId || routine.name.toLowerCase() === routineId.toLowerCase()) ?? null;
|
|
@@ -881799,17 +881895,17 @@ function localEditorModelExecution(editorKind) {
|
|
|
881799
881895
|
return "Use the command field, editor schema, or a first-class Agent model tool when available.";
|
|
881800
881896
|
}
|
|
881801
881897
|
function listWorkspaceActions(deps, args2) {
|
|
881802
|
-
const query2 =
|
|
881803
|
-
const categoryId =
|
|
881804
|
-
const limit3 =
|
|
881898
|
+
const query2 = readString58(args2.query);
|
|
881899
|
+
const categoryId = readString58(args2.categoryId || args2.category);
|
|
881900
|
+
const limit3 = readLimit11(args2.limit, 200);
|
|
881805
881901
|
const includeEditor = args2.includeParameters === true;
|
|
881806
881902
|
const editorContext = includeEditor ? buildWorkspaceEditorContext(deps.commandContext, args2) : null;
|
|
881807
881903
|
const source = query2 ? searchAgentWorkspaceActions(AGENT_WORKSPACE_CATEGORIES, query2).map((result2) => ({ category: result2.category, action: result2.action })) : allWorkspaceActions();
|
|
881808
881904
|
return source.filter((entry) => !categoryId || entry.category.id === categoryId).slice(0, limit3).map((entry) => describeWorkspaceAction(entry.category, entry.action, { includeEditor, editorContext }));
|
|
881809
881905
|
}
|
|
881810
881906
|
function findWorkspaceAction(args2) {
|
|
881811
|
-
const actionId =
|
|
881812
|
-
const categoryId =
|
|
881907
|
+
const actionId = readString58(args2.actionId || args2.query);
|
|
881908
|
+
const categoryId = readString58(args2.categoryId || args2.category);
|
|
881813
881909
|
if (!actionId)
|
|
881814
881910
|
return null;
|
|
881815
881911
|
return allWorkspaceActions().find((entry) => {
|
|
@@ -881818,13 +881914,8 @@ function findWorkspaceAction(args2) {
|
|
|
881818
881914
|
return entry.action.id === actionId || entry.action.label.toLowerCase() === actionId.toLowerCase();
|
|
881819
881915
|
}) ?? null;
|
|
881820
881916
|
}
|
|
881821
|
-
function listCommands(commandRegistry, args2) {
|
|
881822
|
-
const query2 = readString57(args2.query);
|
|
881823
|
-
const limit3 = readLimit10(args2.limit, 200);
|
|
881824
|
-
return commandRegistry.list().filter((command8) => commandMatches(command8, query2)).sort((a4, b3) => a4.name.localeCompare(b3.name)).slice(0, limit3).map(describeCommand);
|
|
881825
|
-
}
|
|
881826
881917
|
function requireConfirmedAction(args2, action2) {
|
|
881827
|
-
const explicitUserRequest =
|
|
881918
|
+
const explicitUserRequest = readString58(args2.explicitUserRequest);
|
|
881828
881919
|
if (!explicitUserRequest)
|
|
881829
881920
|
return `${action2} requires explicitUserRequest with the user's exact request or a short faithful summary.`;
|
|
881830
881921
|
if (args2.confirm !== true)
|
|
@@ -881832,7 +881923,7 @@ function requireConfirmedAction(args2, action2) {
|
|
|
881832
881923
|
return null;
|
|
881833
881924
|
}
|
|
881834
881925
|
function commandFromArgs(args2) {
|
|
881835
|
-
const rawCommand =
|
|
881926
|
+
const rawCommand = readString58(args2.command);
|
|
881836
881927
|
if (rawCommand) {
|
|
881837
881928
|
const parsed = parseSlashCommand(rawCommand);
|
|
881838
881929
|
if (!parsed.name)
|
|
@@ -881842,10 +881933,10 @@ function commandFromArgs(args2) {
|
|
|
881842
881933
|
args: parsed.args
|
|
881843
881934
|
};
|
|
881844
881935
|
}
|
|
881845
|
-
const commandName =
|
|
881936
|
+
const commandName = readString58(args2.commandName).replace(/^\//, "");
|
|
881846
881937
|
if (!commandName)
|
|
881847
881938
|
return null;
|
|
881848
|
-
const commandArgs =
|
|
881939
|
+
const commandArgs = readStringArray13(args2.args);
|
|
881849
881940
|
return {
|
|
881850
881941
|
name: commandName,
|
|
881851
881942
|
args: commandArgs
|
|
@@ -882069,7 +882160,7 @@ function createAgentHarnessTool(deps) {
|
|
|
882069
882160
|
panels: 'Use mode:"panels" and mode:"panel" to inspect built-in panel catalog/open state; use mode:"open_panel" with confirm:true plus explicitUserRequest to route a visible panel/workspace change.',
|
|
882070
882161
|
uiSurfaces: 'Use mode:"ui_surfaces" and mode:"ui_surface" to inspect modal/overlay/picker/workspace surfaces; use mode:"open_ui_surface" with confirm:true plus explicitUserRequest to route visible UI navigation.',
|
|
882071
882162
|
shortcuts: 'Use mode:"shortcuts" to inspect fixed shortcuts plus configurable keybindings. Use mode:"set_keybinding" and mode:"reset_keybinding" with confirm:true plus explicitUserRequest to edit the same config file the user edits.',
|
|
882072
|
-
slashCommands: 'Use mode:"commands" and mode:"command" to inspect; use mode:"run_command" with confirm:true plus explicitUserRequest to execute.',
|
|
882163
|
+
slashCommands: 'Use mode:"commands" to list slash commands and mode:"command" with command, commandName, target, or query to inspect one command; use mode:"run_command" with confirm:true plus explicitUserRequest to execute.',
|
|
882073
882164
|
workspace: 'Use mode:"workspace_actions" to list and mode:"workspace_action" for editor schemas; set includeParameters:true on workspace_actions to inline editor schemas.',
|
|
882074
882165
|
settings: 'Use mode:"settings", mode:"get_setting", mode:"set_setting", and mode:"reset_setting".',
|
|
882075
882166
|
tools: 'Use mode:"tools" to list first-class model tools, or mode:"tool" with toolName, target, or query to inspect one schema.',
|
|
@@ -882104,7 +882195,7 @@ function createAgentHarnessTool(deps) {
|
|
|
882104
882195
|
}
|
|
882105
882196
|
if (args2.mode === "panel") {
|
|
882106
882197
|
const panel = describeHarnessPanel(deps.commandContext, args2);
|
|
882107
|
-
return panel ? output7(panel) : error52(`Unknown panel ${
|
|
882198
|
+
return panel ? output7(panel) : error52(`Unknown panel ${readString58(args2.panelId || args2.query) || "<missing>"}.`);
|
|
882108
882199
|
}
|
|
882109
882200
|
if (args2.mode === "open_panel") {
|
|
882110
882201
|
const confirmationError2 = requireConfirmedAction(args2, "Panel routing");
|
|
@@ -882118,7 +882209,7 @@ function createAgentHarnessTool(deps) {
|
|
|
882118
882209
|
}
|
|
882119
882210
|
if (args2.mode === "ui_surface") {
|
|
882120
882211
|
const surface = describeHarnessUiSurface(deps.commandContext, args2);
|
|
882121
|
-
return surface ? output7(surface) : error52(`Unknown UI surface ${
|
|
882212
|
+
return surface ? output7(surface) : error52(`Unknown UI surface ${readString58(args2.surfaceId || args2.query) || "<missing>"}.`);
|
|
882122
882213
|
}
|
|
882123
882214
|
if (args2.mode === "open_ui_surface") {
|
|
882124
882215
|
const confirmationError2 = requireConfirmedAction(args2, "UI surface routing");
|
|
@@ -882132,7 +882223,7 @@ function createAgentHarnessTool(deps) {
|
|
|
882132
882223
|
return output7(listHarnessKeybindings(deps.commandContext, args2));
|
|
882133
882224
|
if (args2.mode === "keybinding") {
|
|
882134
882225
|
const binding = describeHarnessKeybinding(deps.commandContext, args2);
|
|
882135
|
-
return binding ? output7(binding) : error52(`Unknown keybinding action ${
|
|
882226
|
+
return binding ? output7(binding) : error52(`Unknown keybinding action ${readString58(args2.actionId || args2.key || args2.query) || "<missing>"}.`);
|
|
882136
882227
|
}
|
|
882137
882228
|
if (args2.mode === "set_keybinding") {
|
|
882138
882229
|
const confirmationError2 = requireConfirmedAction(args2, "Keybinding mutation");
|
|
@@ -882147,28 +882238,28 @@ function createAgentHarnessTool(deps) {
|
|
|
882147
882238
|
return output7(resetHarnessKeybinding(deps.commandContext, args2));
|
|
882148
882239
|
}
|
|
882149
882240
|
if (args2.mode === "commands") {
|
|
882150
|
-
const commands3 =
|
|
882241
|
+
const commands3 = listHarnessCommands(deps.commandRegistry, args2);
|
|
882151
882242
|
return output7({ commands: commands3, returned: commands3.length, total: deps.commandRegistry.list().length });
|
|
882152
882243
|
}
|
|
882153
882244
|
if (args2.mode === "command") {
|
|
882154
|
-
const
|
|
882155
|
-
const
|
|
882156
|
-
return
|
|
882245
|
+
const detail = describeHarnessCommand(deps.commandRegistry, args2);
|
|
882246
|
+
const query2 = readString58(args2.command || args2.commandName || args2.target || args2.query);
|
|
882247
|
+
return detail ? output7(detail) : error52(`Unknown slash command ${query2 || "<missing>"}. Use mode:"commands" to inspect available commands.`);
|
|
882157
882248
|
}
|
|
882158
882249
|
if (args2.mode === "run_command")
|
|
882159
882250
|
return runCommand2(deps, args2);
|
|
882160
882251
|
if (args2.mode === "settings") {
|
|
882161
882252
|
const settings = listHarnessSettings(deps.commandContext.platform.configManager, {
|
|
882162
|
-
category:
|
|
882163
|
-
prefix:
|
|
882164
|
-
query:
|
|
882253
|
+
category: readString58(args2.category) || undefined,
|
|
882254
|
+
prefix: readString58(args2.prefix) || undefined,
|
|
882255
|
+
query: readString58(args2.query) || undefined,
|
|
882165
882256
|
includeHidden: args2.includeHidden === true,
|
|
882166
|
-
limit:
|
|
882257
|
+
limit: readLimit11(args2.limit, 100)
|
|
882167
882258
|
});
|
|
882168
882259
|
return output7({ settings, returned: settings.length, policy: settingsPolicySummary() });
|
|
882169
882260
|
}
|
|
882170
882261
|
if (args2.mode === "get_setting") {
|
|
882171
|
-
const key =
|
|
882262
|
+
const key = readString58(args2.key);
|
|
882172
882263
|
const setting = getHarnessSetting(deps.commandContext.platform.configManager, key);
|
|
882173
882264
|
return setting ? output7(setting) : error52(`Unknown setting ${key || "<missing>"}.`);
|
|
882174
882265
|
}
|
|
@@ -882178,7 +882269,7 @@ function createAgentHarnessTool(deps) {
|
|
|
882178
882269
|
return error52(confirmationError2);
|
|
882179
882270
|
if (args2.value === undefined)
|
|
882180
882271
|
return error52("set_setting requires value.");
|
|
882181
|
-
const key =
|
|
882272
|
+
const key = readString58(args2.key);
|
|
882182
882273
|
const result2 = await setHarnessSetting(deps.commandContext.platform.configManager, deps.commandContext.platform.secretsManager, key, args2.value);
|
|
882183
882274
|
return output7(result2);
|
|
882184
882275
|
}
|
|
@@ -882186,7 +882277,7 @@ function createAgentHarnessTool(deps) {
|
|
|
882186
882277
|
const confirmationError2 = requireConfirmedAction(args2, "Setting reset");
|
|
882187
882278
|
if (confirmationError2)
|
|
882188
882279
|
return error52(confirmationError2);
|
|
882189
|
-
const key =
|
|
882280
|
+
const key = readString58(args2.key);
|
|
882190
882281
|
const result2 = await resetHarnessSetting(deps.commandContext.platform.configManager, deps.commandContext.platform.secretsManager, key);
|
|
882191
882282
|
return output7(result2);
|
|
882192
882283
|
}
|
|
@@ -882203,7 +882294,7 @@ function createAgentHarnessTool(deps) {
|
|
|
882203
882294
|
if (args2.mode === "workspace_action") {
|
|
882204
882295
|
const found = findWorkspaceAction(args2);
|
|
882205
882296
|
const editorContext = buildWorkspaceEditorContext(deps.commandContext, args2);
|
|
882206
|
-
return found ? output7(describeWorkspaceAction(found.category, found.action, { includeEditor: true, editorContext })) : error52(`Unknown Agent workspace action ${
|
|
882297
|
+
return found ? output7(describeWorkspaceAction(found.category, found.action, { includeEditor: true, editorContext })) : error52(`Unknown Agent workspace action ${readString58(args2.actionId || args2.query) || "<missing>"}.`);
|
|
882207
882298
|
}
|
|
882208
882299
|
if (args2.mode === "run_workspace_action")
|
|
882209
882300
|
return runWorkspaceAction(deps, args2);
|
|
@@ -882212,14 +882303,14 @@ function createAgentHarnessTool(deps) {
|
|
|
882212
882303
|
return output7({ tools: tools3, returned: tools3.length, total: deps.toolRegistry.getToolDefinitions().length });
|
|
882213
882304
|
}
|
|
882214
882305
|
if (args2.mode === "tool") {
|
|
882215
|
-
const query2 =
|
|
882306
|
+
const query2 = readString58(args2.toolName || args2.target || args2.query);
|
|
882216
882307
|
const tool2 = describeHarnessModelTool(deps.toolRegistry, args2);
|
|
882217
882308
|
return tool2 ? output7(tool2) : error52(`Unknown model tool ${query2 || "<missing>"}. Use mode:"tools" to inspect available model tools.`);
|
|
882218
882309
|
}
|
|
882219
882310
|
if (args2.mode === "connected_host")
|
|
882220
882311
|
return output7(connectedHostSummary(deps.commandContext, deps.toolRegistry));
|
|
882221
882312
|
if (args2.mode === "connected_host_capability") {
|
|
882222
|
-
const query2 =
|
|
882313
|
+
const query2 = readString58(args2.capabilityId || args2.target || args2.query);
|
|
882223
882314
|
const capability = describeConnectedHostCapability(deps.toolRegistry, query2);
|
|
882224
882315
|
return capability ? output7(capability) : error52(`Unknown connected-host capability ${query2 || "<missing>"}. Use mode:"connected_host" to inspect allowed and blocked capability ids.`);
|
|
882225
882316
|
}
|
package/docs/README.md
CHANGED
|
@@ -22,7 +22,7 @@ Important baseline constraints:
|
|
|
22
22
|
- Agent depends on `@pellux/goodvibes-sdk@0.33.35`.
|
|
23
23
|
- Agent connects to a GoodVibes host owned outside this product.
|
|
24
24
|
- Agent does not start, stop, restart, install, uninstall, or own the connected GoodVibes host.
|
|
25
|
-
- User-facing Agent workspace actions, built-in panels, modal/overlay/picker UI surfaces, named operator surfaces, top-level CLI mirrors, fixed shortcuts, configurable keybindings, slash commands, command policy metadata, model tools and individual model tool schemas, settings, local registries, connected-host capability boundaries, single connected-host capability inspection, and live connected-host readiness are model-visible through Agent-owned tools. Visible UI routing includes the command browser, reasoning-effort picker, live process output, runtime activity, settings, workspaces, and pickers the user can open. Local memory, note, persona, skill, and routine create editors can also run through confirmed workspace actions. Mutations and visible UI routing remain explicit and confirmation-gated.
|
|
25
|
+
- User-facing Agent workspace actions, built-in panels, modal/overlay/picker UI surfaces, named operator surfaces, top-level CLI mirrors, fixed shortcuts, configurable keybindings, slash commands, single-command lookup with policy metadata, model tools and individual model tool schemas, settings, local registries, connected-host capability boundaries, single connected-host capability inspection, and live connected-host readiness are model-visible through Agent-owned tools. Visible UI routing includes the command browser, reasoning-effort picker, live process output, runtime activity, settings, workspaces, and pickers the user can open. Local memory, note, persona, skill, and routine create editors can also run through confirmed workspace actions. Mutations and visible UI routing remain explicit and confirmation-gated.
|
|
26
26
|
- Agent Knowledge uses only `/api/goodvibes-agent/knowledge/*`; there is no default knowledge or non-Agent product fallback.
|
|
27
27
|
- Agent supports isolated Agent homes with `GOODVIBES_AGENT_HOME=<path>` and named profile homes with `goodvibes-agent profiles create <name> --template <starter> --yes` plus `--agent-profile <name>`.
|
|
28
28
|
- Agent supports connected-host URL overrides with `--runtime-url http://host:port` or `GOODVIBES_AGENT_RUNTIME_URL=http://host:port`; these only change the Agent connection target.
|
package/docs/getting-started.md
CHANGED
|
@@ -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 and single-tool schema inspection, settings inspection/mutation, connected-host capability inventory, single connected-host capability inspection, 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, command browser, conversation search, prompt-history search, slash-command mode, file picker, block actions, context, runtime activity, live process output, bookmarks, model/provider/reasoning-effort 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. Direct local create editors for memory, notes, personas, skills, and routines can execute from submitted fields through `run_workspace_action` and `agent_local_registry` with confirmation. 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, single slash-command inspection by typed command or lookup text, command policy metadata, command execution with confirmation, model tool discovery and single-tool schema inspection, settings inspection/mutation, connected-host capability inventory, single connected-host capability inspection, 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, command browser, conversation search, prompt-history search, slash-command mode, file picker, block actions, context, runtime activity, live process output, bookmarks, model/provider/reasoning-effort 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. Direct local create editors for memory, notes, personas, skills, and routines can execute from submitted fields through `run_workspace_action` and `agent_local_registry` with confirmation. 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
|
|
|
@@ -43,14 +43,14 @@ Host-management and coding-first commands that would imply connected-host lifecy
|
|
|
43
43
|
|
|
44
44
|
The main Agent model has an Agent-owned harness bridge rather than generic SDK settings/context control. Use these model tools as the supported parity layer:
|
|
45
45
|
|
|
46
|
-
- `agent_harness`: inspect workspace categories/actions, inspect built-in panels, inspect modal/overlay/picker UI surfaces and named operator surfaces, inspect top-level CLI mirrors, inspect fixed shortcuts and configurable keybindings, inspect slash commands and command policy metadata, run concrete workspace or slash-command mirrors with confirmation, inspect model tools or one model tool schema, inspect or change Agent settings/keybindings, inspect connected-host capability boundaries or one connected-host capability, and inspect live connected-host readiness.
|
|
46
|
+
- `agent_harness`: inspect workspace categories/actions, inspect built-in panels, inspect modal/overlay/picker UI surfaces and named operator surfaces, inspect top-level CLI mirrors, inspect fixed shortcuts and configurable keybindings, inspect slash commands and one slash command by typed command or lookup text with policy metadata, run concrete workspace or slash-command mirrors with confirmation, inspect model tools or one model tool schema, inspect or change Agent settings/keybindings, inspect connected-host capability boundaries or one connected-host capability, and inspect live connected-host readiness.
|
|
47
47
|
- `agent_local_registry`: inspect and maintain Agent-local memory, notes, personas, skills, skill bundles, and routines. Deleting local records requires `confirm:true` and `explicitUserRequest`.
|
|
48
48
|
- `agent_knowledge` and `agent_knowledge_ingest`: ask/search and ingest into the isolated Agent Knowledge segment.
|
|
49
49
|
- `agent_operator_briefing` and `agent_operator_action`: inspect connected work/approval/automation posture, or run exact confirmed approval/automation actions.
|
|
50
50
|
- `agent_work_plan`: keep the visible Agent-local work plan current from the conversation.
|
|
51
51
|
- `agent_channel_send`, `agent_notify`, `agent_reminder_schedule`, and `agent_media_generate`: perform confirmed external delivery, notification, reminder, or media actions when the user explicitly asks.
|
|
52
52
|
|
|
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`
|
|
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` lists slash-command descriptions; `command` returns one slash-command detail by `command`, `commandName`, `target`, or `query`, including parsed arguments 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` lists model tool definitions and can inline JSON schemas with `includeParameters:true`; `tool` returns one model tool schema by `toolName`, `target`, or `query`; `settings` returns setting descriptors plus setting policy; `connected_host` returns the connected-host route families, allowed capabilities, blocked capabilities, and first-class tool availability; `connected_host_capability` returns one allowed or blocked connected-host capability by `capabilityId`, `target`, or `query` with related route families and boundary text; 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
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/reasoning-effort 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, command browser, file picker, block actions, bookmarks, context inspector, runtime activity monitor, live process output, 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
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
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",
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { CommandRegistry, SlashCommand } from '../input/command-registry.ts';
|
|
2
|
+
import { parseSlashCommand } from '../input/slash-command-parser.ts';
|
|
3
|
+
import { describeCommandPolicy } from './agent-harness-metadata.ts';
|
|
4
|
+
|
|
5
|
+
export interface AgentHarnessCommandCatalogArgs {
|
|
6
|
+
readonly query?: unknown;
|
|
7
|
+
readonly command?: unknown;
|
|
8
|
+
readonly commandName?: unknown;
|
|
9
|
+
readonly args?: unknown;
|
|
10
|
+
readonly target?: unknown;
|
|
11
|
+
readonly limit?: unknown;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface CommandDetailLookup {
|
|
15
|
+
readonly source: 'command' | 'commandName' | 'target' | 'query';
|
|
16
|
+
readonly input: string;
|
|
17
|
+
readonly parsedName: string;
|
|
18
|
+
readonly parsedArgs: readonly string[];
|
|
19
|
+
readonly resolvedBy: 'name' | 'alias' | 'case-insensitive-name' | 'case-insensitive-alias' | 'description' | 'prefix';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function readString(value: unknown): string {
|
|
23
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readLimit(value: unknown, fallback: number): number {
|
|
27
|
+
const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
|
|
28
|
+
if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
|
|
29
|
+
return Math.max(1, Math.min(500, Math.trunc(parsed)));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readStringArray(value: unknown): readonly string[] {
|
|
33
|
+
if (!Array.isArray(value)) return [];
|
|
34
|
+
return value.map((entry) => typeof entry === 'string' ? entry : String(entry));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function commandMatches(command: SlashCommand, query: string): boolean {
|
|
38
|
+
if (!query) return true;
|
|
39
|
+
const haystack = [
|
|
40
|
+
command.name,
|
|
41
|
+
...(command.aliases ?? []),
|
|
42
|
+
command.description,
|
|
43
|
+
command.usage ?? '',
|
|
44
|
+
command.argsHint ?? '',
|
|
45
|
+
].join('\n').toLowerCase();
|
|
46
|
+
return haystack.includes(query.toLowerCase());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function describeCommand(command: SlashCommand, lookup?: CommandDetailLookup): Record<string, unknown> {
|
|
50
|
+
return {
|
|
51
|
+
name: command.name,
|
|
52
|
+
slash: `/${command.name}`,
|
|
53
|
+
aliases: command.aliases ?? [],
|
|
54
|
+
description: command.description,
|
|
55
|
+
usage: command.usage ?? '',
|
|
56
|
+
argsHint: command.argsHint ?? command.usage ?? '',
|
|
57
|
+
...(lookup ? {
|
|
58
|
+
lookup: {
|
|
59
|
+
source: lookup.source,
|
|
60
|
+
input: lookup.input,
|
|
61
|
+
parsedName: lookup.parsedName,
|
|
62
|
+
parsedArgs: lookup.parsedArgs,
|
|
63
|
+
resolvedBy: lookup.resolvedBy,
|
|
64
|
+
},
|
|
65
|
+
} : {}),
|
|
66
|
+
policy: describeCommandPolicy(command.name),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function commandDetailLookupFromArgs(args: AgentHarnessCommandCatalogArgs): Omit<CommandDetailLookup, 'resolvedBy'> | null {
|
|
71
|
+
const rawCommand = readString(args.command);
|
|
72
|
+
if (rawCommand) {
|
|
73
|
+
const parsed = parseSlashCommand(rawCommand);
|
|
74
|
+
return { source: 'command', input: rawCommand, parsedName: parsed.name, parsedArgs: parsed.args };
|
|
75
|
+
}
|
|
76
|
+
const rawCommandName = readString(args.commandName);
|
|
77
|
+
if (rawCommandName) {
|
|
78
|
+
const parsed = parseSlashCommand(rawCommandName);
|
|
79
|
+
const explicitArgs = readStringArray(args.args);
|
|
80
|
+
return {
|
|
81
|
+
source: 'commandName',
|
|
82
|
+
input: rawCommandName,
|
|
83
|
+
parsedName: parsed.name,
|
|
84
|
+
parsedArgs: explicitArgs.length > 0 ? explicitArgs : parsed.args,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const rawTarget = readString(args.target);
|
|
88
|
+
if (rawTarget) {
|
|
89
|
+
const parsed = parseSlashCommand(rawTarget);
|
|
90
|
+
return { source: 'target', input: rawTarget, parsedName: parsed.name, parsedArgs: parsed.args };
|
|
91
|
+
}
|
|
92
|
+
const rawQuery = readString(args.query);
|
|
93
|
+
if (rawQuery) {
|
|
94
|
+
const parsed = parseSlashCommand(rawQuery);
|
|
95
|
+
return { source: 'query', input: rawQuery, parsedName: parsed.name, parsedArgs: parsed.args };
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function resolveCommandDetail(commandRegistry: CommandRegistry, args: AgentHarnessCommandCatalogArgs): { readonly command: SlashCommand; readonly lookup: CommandDetailLookup } | null {
|
|
101
|
+
const lookup = commandDetailLookupFromArgs(args);
|
|
102
|
+
if (!lookup?.parsedName) return null;
|
|
103
|
+
const direct = commandRegistry.get(lookup.parsedName);
|
|
104
|
+
if (direct) {
|
|
105
|
+
return {
|
|
106
|
+
command: direct,
|
|
107
|
+
lookup: {
|
|
108
|
+
...lookup,
|
|
109
|
+
resolvedBy: direct.name === lookup.parsedName ? 'name' : 'alias',
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const normalized = lookup.parsedName.toLowerCase();
|
|
115
|
+
for (const command of commandRegistry.list()) {
|
|
116
|
+
if (command.name.toLowerCase() === normalized) {
|
|
117
|
+
return { command, lookup: { ...lookup, resolvedBy: 'case-insensitive-name' } };
|
|
118
|
+
}
|
|
119
|
+
if ((command.aliases ?? []).some((alias) => alias.toLowerCase() === normalized)) {
|
|
120
|
+
return { command, lookup: { ...lookup, resolvedBy: 'case-insensitive-alias' } };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const descriptionMatches = commandRegistry.list().filter((command) => commandMatches(command, lookup.input));
|
|
125
|
+
if (descriptionMatches.length === 1) {
|
|
126
|
+
return { command: descriptionMatches[0]!, lookup: { ...lookup, resolvedBy: 'description' } };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const prefixMatches = commandRegistry.fuzzyMatch(lookup.parsedName).filter((entry) => entry.score >= 80);
|
|
130
|
+
if (prefixMatches.length === 1) {
|
|
131
|
+
return { command: prefixMatches[0]!.command, lookup: { ...lookup, resolvedBy: 'prefix' } };
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function listHarnessCommands(commandRegistry: CommandRegistry, args: AgentHarnessCommandCatalogArgs): readonly Record<string, unknown>[] {
|
|
137
|
+
const query = readString(args.query);
|
|
138
|
+
const limit = readLimit(args.limit, 200);
|
|
139
|
+
return commandRegistry.list()
|
|
140
|
+
.filter((command) => commandMatches(command, query))
|
|
141
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
142
|
+
.slice(0, limit)
|
|
143
|
+
.map((command) => describeCommand(command));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function describeHarnessCommand(commandRegistry: CommandRegistry, args: AgentHarnessCommandCatalogArgs): Record<string, unknown> | null {
|
|
147
|
+
const detail = resolveCommandDetail(commandRegistry, args);
|
|
148
|
+
return detail ? describeCommand(detail.command, detail.lookup) : null;
|
|
149
|
+
}
|
|
@@ -23,11 +23,11 @@ export const AGENT_HARNESS_PARAMETER_PROPERTIES = {
|
|
|
23
23
|
},
|
|
24
24
|
query: {
|
|
25
25
|
type: 'string',
|
|
26
|
-
description: 'Search text for command, setting, tool, or UI surface catalogs.',
|
|
26
|
+
description: 'Search text for command, setting, tool, or UI surface catalogs, or a slash-command lookup for mode command.',
|
|
27
27
|
},
|
|
28
28
|
command: {
|
|
29
29
|
type: 'string',
|
|
30
|
-
description: 'Full slash command string for mode run_command, for example "/settings get provider.model". In cli_command mode this may also hold a top-level CLI string such as "goodvibes-agent status --json".',
|
|
30
|
+
description: 'Full slash command string for mode command or run_command, for example "/settings get provider.model". In cli_command mode this may also hold a top-level CLI string such as "goodvibes-agent status --json".',
|
|
31
31
|
},
|
|
32
32
|
cliCommand: {
|
|
33
33
|
type: 'string',
|
|
@@ -90,7 +90,7 @@ export const AGENT_HARNESS_PARAMETER_PROPERTIES = {
|
|
|
90
90
|
},
|
|
91
91
|
target: {
|
|
92
92
|
type: 'string',
|
|
93
|
-
description: 'Optional lookup target, such as a model-picker target, settings key, model tool name, or connected-host capability id.',
|
|
93
|
+
description: 'Optional lookup target, such as a model-picker target, slash command root or invocation, settings key, model tool name, or connected-host capability id.',
|
|
94
94
|
},
|
|
95
95
|
capabilityId: {
|
|
96
96
|
type: 'string',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
2
|
import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
3
|
-
import type { CommandContext, CommandRegistry
|
|
3
|
+
import type { CommandContext, CommandRegistry } from '../input/command-registry.ts';
|
|
4
4
|
import { buildAgentWorkspaceCommandEditorSubmission, isAgentWorkspaceCommandEditorKind } from '../input/agent-workspace-command-editor.ts';
|
|
5
5
|
import { createAgentWorkspaceEditor } from '../input/agent-workspace-activation.ts';
|
|
6
6
|
import { AGENT_WORKSPACE_CATEGORIES } from '../input/agent-workspace-categories.ts';
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
} from '../input/agent-workspace-types.ts';
|
|
19
19
|
import { parseSlashCommand } from '../input/slash-command-parser.ts';
|
|
20
20
|
import { blockedHarnessCliCommandTokens, describeHarnessCliCommand, listHarnessCliCommands, totalHarnessCliCommands } from './agent-harness-cli-metadata.ts';
|
|
21
|
+
import { describeHarnessCommand, listHarnessCommands } from './agent-harness-command-catalog.ts';
|
|
21
22
|
import { describeHarnessKeybinding, listHarnessKeybindings, listHarnessShortcuts, resetHarnessKeybinding, setHarnessKeybinding, totalHarnessKeybindings, totalHarnessShortcuts } from './agent-harness-keybinding-metadata.ts';
|
|
22
23
|
import { describeHarnessPanel, listHarnessPanels, openHarnessPanel, totalHarnessPanels } from './agent-harness-panel-metadata.ts';
|
|
23
24
|
import { connectedHostStatusSummary } from './agent-harness-connected-host-status.ts';
|
|
@@ -28,7 +29,6 @@ import { describeHarnessUiSurface, listHarnessUiSurfaces, openHarnessUiSurface,
|
|
|
28
29
|
import {
|
|
29
30
|
connectedHostSummary,
|
|
30
31
|
describeConnectedHostCapability,
|
|
31
|
-
describeCommandPolicy,
|
|
32
32
|
settingsPolicySummary,
|
|
33
33
|
} from './agent-harness-metadata.ts';
|
|
34
34
|
import {
|
|
@@ -115,30 +115,6 @@ function output(value: unknown): { readonly success: true; readonly output: stri
|
|
|
115
115
|
|
|
116
116
|
function error(message: string): { readonly success: false; readonly error: string } { return { success: false, error: message }; }
|
|
117
117
|
|
|
118
|
-
function commandMatches(command: SlashCommand, query: string): boolean {
|
|
119
|
-
if (!query) return true;
|
|
120
|
-
const haystack = [
|
|
121
|
-
command.name,
|
|
122
|
-
...(command.aliases ?? []),
|
|
123
|
-
command.description,
|
|
124
|
-
command.usage ?? '',
|
|
125
|
-
command.argsHint ?? '',
|
|
126
|
-
].join('\n').toLowerCase();
|
|
127
|
-
return haystack.includes(query.toLowerCase());
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function describeCommand(command: SlashCommand): Record<string, unknown> {
|
|
131
|
-
return {
|
|
132
|
-
name: command.name,
|
|
133
|
-
slash: `/${command.name}`,
|
|
134
|
-
aliases: command.aliases ?? [],
|
|
135
|
-
description: command.description,
|
|
136
|
-
usage: command.usage ?? '',
|
|
137
|
-
argsHint: command.argsHint ?? command.usage ?? '',
|
|
138
|
-
policy: describeCommandPolicy(command.name),
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
118
|
function allWorkspaceActions(): ReadonlyArray<{
|
|
143
119
|
readonly category: AgentWorkspaceCategory;
|
|
144
120
|
readonly action: AgentWorkspaceAction;
|
|
@@ -276,16 +252,6 @@ function findWorkspaceAction(args: AgentHarnessToolArgs): { readonly category: A
|
|
|
276
252
|
}) ?? null;
|
|
277
253
|
}
|
|
278
254
|
|
|
279
|
-
function listCommands(commandRegistry: CommandRegistry, args: AgentHarnessToolArgs): readonly Record<string, unknown>[] {
|
|
280
|
-
const query = readString(args.query);
|
|
281
|
-
const limit = readLimit(args.limit, 200);
|
|
282
|
-
return commandRegistry.list()
|
|
283
|
-
.filter((command) => commandMatches(command, query))
|
|
284
|
-
.sort((a, b) => a.name.localeCompare(b.name))
|
|
285
|
-
.slice(0, limit)
|
|
286
|
-
.map(describeCommand);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
255
|
function requireConfirmedAction(args: AgentHarnessToolArgs, action: string): string | null {
|
|
290
256
|
const explicitUserRequest = readString(args.explicitUserRequest);
|
|
291
257
|
if (!explicitUserRequest) return `${action} requires explicitUserRequest with the user's exact request or a short faithful summary.`;
|
|
@@ -551,7 +517,7 @@ export function createAgentHarnessTool(deps: AgentHarnessToolDeps): Tool {
|
|
|
551
517
|
panels: 'Use mode:"panels" and mode:"panel" to inspect built-in panel catalog/open state; use mode:"open_panel" with confirm:true plus explicitUserRequest to route a visible panel/workspace change.',
|
|
552
518
|
uiSurfaces: 'Use mode:"ui_surfaces" and mode:"ui_surface" to inspect modal/overlay/picker/workspace surfaces; use mode:"open_ui_surface" with confirm:true plus explicitUserRequest to route visible UI navigation.',
|
|
553
519
|
shortcuts: 'Use mode:"shortcuts" to inspect fixed shortcuts plus configurable keybindings. Use mode:"set_keybinding" and mode:"reset_keybinding" with confirm:true plus explicitUserRequest to edit the same config file the user edits.',
|
|
554
|
-
slashCommands: 'Use mode:"commands" and mode:"command" to inspect; use mode:"run_command" with confirm:true plus explicitUserRequest to execute.',
|
|
520
|
+
slashCommands: 'Use mode:"commands" to list slash commands and mode:"command" with command, commandName, target, or query to inspect one command; use mode:"run_command" with confirm:true plus explicitUserRequest to execute.',
|
|
555
521
|
workspace: 'Use mode:"workspace_actions" to list and mode:"workspace_action" for editor schemas; set includeParameters:true on workspace_actions to inline editor schemas.',
|
|
556
522
|
settings: 'Use mode:"settings", mode:"get_setting", mode:"set_setting", and mode:"reset_setting".',
|
|
557
523
|
tools: 'Use mode:"tools" to list first-class model tools, or mode:"tool" with toolName, target, or query to inspect one schema.',
|
|
@@ -623,13 +589,15 @@ export function createAgentHarnessTool(deps: AgentHarnessToolDeps): Tool {
|
|
|
623
589
|
return output(resetHarnessKeybinding(deps.commandContext, args));
|
|
624
590
|
}
|
|
625
591
|
if (args.mode === 'commands') {
|
|
626
|
-
const commands =
|
|
592
|
+
const commands = listHarnessCommands(deps.commandRegistry, args);
|
|
627
593
|
return output({ commands, returned: commands.length, total: deps.commandRegistry.list().length });
|
|
628
594
|
}
|
|
629
595
|
if (args.mode === 'command') {
|
|
630
|
-
const
|
|
631
|
-
const
|
|
632
|
-
return
|
|
596
|
+
const detail = describeHarnessCommand(deps.commandRegistry, args);
|
|
597
|
+
const query = readString(args.command || args.commandName || args.target || args.query);
|
|
598
|
+
return detail
|
|
599
|
+
? output(detail)
|
|
600
|
+
: error(`Unknown slash command ${query || '<missing>'}. Use mode:"commands" to inspect available commands.`);
|
|
633
601
|
}
|
|
634
602
|
if (args.mode === 'run_command') return runCommand(deps, args);
|
|
635
603
|
if (args.mode === 'settings') {
|
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.
|
|
9
|
+
let _version = '1.0.15';
|
|
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 {
|