@pellux/goodvibes-agent 1.0.1 → 1.0.2
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 +7 -0
- package/README.md +8 -4
- package/dist/package/main.js +13750 -12196
- package/docs/README.md +4 -2
- package/docs/channels-remote-and-api.md +4 -0
- package/docs/connected-host.md +2 -0
- package/docs/getting-started.md +6 -2
- package/docs/knowledge-artifacts-and-multimodal.md +5 -3
- package/docs/project-planning.md +3 -1
- package/docs/providers-and-routing.md +3 -0
- package/docs/release-and-publishing.md +7 -6
- package/docs/tools-and-commands.md +97 -2
- package/docs/voice-and-live-tts.md +2 -0
- package/package.json +1 -1
- package/src/agent/harness-control.ts +266 -0
- package/src/config/agent-settings-policy.ts +44 -0
- package/src/input/agent-workspace-activation.ts +14 -6
- package/src/input/commands/operator-runtime.ts +139 -3
- package/src/input/settings-modal-agent-policy.ts +5 -44
- package/src/runtime/bootstrap.ts +3 -0
- package/src/tools/agent-harness-local-operations.ts +233 -0
- package/src/tools/agent-harness-metadata.ts +300 -0
- package/src/tools/agent-harness-tool.ts +774 -0
- package/src/tools/agent-local-registry-requirements.ts +18 -0
- package/src/tools/agent-local-registry-tool.ts +88 -34
- package/src/version.ts +1 -1
package/docs/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GoodVibes Agent Docs
|
|
2
2
|
|
|
3
|
-
These are the package-facing docs for GoodVibes Agent, the personal operator assistant TUI for GoodVibes.
|
|
3
|
+
These are the package-facing docs for the GoodVibes Agent `1.0.x` release line, the personal operator assistant TUI for GoodVibes.
|
|
4
4
|
|
|
5
5
|
Current package docs:
|
|
6
6
|
|
|
@@ -17,10 +17,12 @@ Current package docs:
|
|
|
17
17
|
Important baseline constraints:
|
|
18
18
|
|
|
19
19
|
- Agent installs one executable: `goodvibes-agent`.
|
|
20
|
+
- Current package version is recorded in `package.json` and `CHANGELOG.md`; the latest completed `1.0.x` release in this tree is `1.0.1`.
|
|
20
21
|
- Agent uses Bun `1.3.10` or newer and TypeScript-authored source.
|
|
21
22
|
- Agent depends on `@pellux/goodvibes-sdk@0.33.35`.
|
|
22
23
|
- Agent connects to a GoodVibes host owned outside this product.
|
|
23
24
|
- Agent does not start, stop, restart, install, uninstall, or own the connected GoodVibes host.
|
|
25
|
+
- User-facing Agent workspace actions, slash commands, command policy metadata, model tools, settings, local registries, and connected-host capability boundaries are model-visible through Agent-owned tools. Mutations remain explicit and confirmation-gated.
|
|
24
26
|
- Agent Knowledge uses only `/api/goodvibes-agent/knowledge/*`; there is no default knowledge or non-Agent product fallback.
|
|
25
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>`.
|
|
26
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.
|
|
@@ -30,4 +32,4 @@ Important baseline constraints:
|
|
|
30
32
|
- Normal assistant chat is not coding-session delegation.
|
|
31
33
|
- Build/fix/review delegation to GoodVibes TUI must be explicit; delegated review is not the default Agent behavior.
|
|
32
34
|
|
|
33
|
-
The Agent docs above define
|
|
35
|
+
The Agent docs above define supported `1.0.x` behavior.
|
|
@@ -17,6 +17,8 @@ Agent channel UX should show:
|
|
|
17
17
|
|
|
18
18
|
Agent-local memory, routines, skills, and personas are not automatically broadcast to channels. External delivery is an effect and requires an exact command, an explicit routine promotion, or a user-approved connected-host request. Companion pairing uses `/pair` without printing the raw token; manual token display requires `/pair --show-token --yes`. One-off delivery uses Agent Workspace -> Channels -> Send channel message or `/channels send ... --yes`.
|
|
19
19
|
|
|
20
|
+
The model can inspect channel-facing workspace actions with `agent_harness`, and it can send one explicit configured delivery through `agent_channel_send` when the user asks for that exact effect. It must not create routes, authorize accounts, infer recipients, or expose new public surfaces from chat.
|
|
21
|
+
|
|
20
22
|
## Companion And Session Routes
|
|
21
23
|
|
|
22
24
|
Normal assistant chat uses companion chat routes. Build/fix/review delegation uses shared-session or task routes only when the user explicitly asks for implementation work.
|
|
@@ -43,6 +45,8 @@ Use public SDK/operator routes only. For Agent Knowledge, the only valid family
|
|
|
43
45
|
|
|
44
46
|
If an Agent-specific route is missing, fail closed or show guidance. Do not substitute the default knowledge, another product segment, or private connected-host files.
|
|
45
47
|
|
|
48
|
+
Harness and settings operations use the Agent-owned `agent_harness` tool. Generic settings/context mutators are not the model-facing Agent contract.
|
|
49
|
+
|
|
46
50
|
## Related Docs
|
|
47
51
|
|
|
48
52
|
- [Getting started](getting-started.md)
|
package/docs/connected-host.md
CHANGED
|
@@ -54,6 +54,8 @@ Agent owns the operator assistant TUI, local profiles, local memory/notes/routin
|
|
|
54
54
|
|
|
55
55
|
Agent does not own connected-host lifecycle. It does not provide commands to install, expose, start, stop, restart, or mutate the connected GoodVibes host.
|
|
56
56
|
|
|
57
|
+
The model can inspect this boundary with `agent_harness` mode `connected_host`. That report includes the configured base URL, token presence, token path, allowed route families, first-class Agent tool capabilities, tool availability, and blocked capabilities. Allowed capabilities are limited to read-only operator briefing, explicit allowlisted approval/automation/schedule actions, isolated Agent Knowledge read/ingest, confirmed channel or notification delivery, confirmed reminder schedules, and configured media generation. Blocked capabilities include connected-host lifecycle, listener mutation, default or non-Agent knowledge fallback, hidden background Agent jobs, implicit delegated review, route/account creation, and arbitrary connected-host mutations.
|
|
58
|
+
|
|
57
59
|
Agent Knowledge is its own product segment. Agent uses `/api/goodvibes-agent/knowledge/*` only and must not fall back to default knowledge or other product-specific knowledge routes.
|
|
58
60
|
|
|
59
61
|
Normal assistant chat uses companion chat. Build/fix/review work is delegated explicitly to GoodVibes TUI through public runtime/session contracts, and delegated review is requested only when explicitly asked for build/fix/review work.
|
package/docs/getting-started.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Getting Started
|
|
2
2
|
|
|
3
|
-
GoodVibes Agent is the installable
|
|
3
|
+
GoodVibes Agent is the installable `1.0.x` personal operator assistant built on the GoodVibes TUI foundation.
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
@@ -44,6 +44,8 @@ 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, slash-command discovery, command policy metadata, command execution with confirmation, model tool discovery, settings inspection/mutation, and connected-host posture. 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
|
+
|
|
47
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.
|
|
48
50
|
|
|
49
51
|
The setup workspace scans Agent-local behavior folders and shows importable persona, skill, and routine files before asking you to create blank records. It can also create one initial scratchpad note, local persona, skill, and routine from the setup form. Use the workspace action finder to search for local behavior discovery/import actions, preview files, then import reviewed records from the matching workspace.
|
|
@@ -120,6 +122,8 @@ Use `/channels` inside the TUI for channel readiness and exact confirmed sends.
|
|
|
120
122
|
|
|
121
123
|
The main assistant conversation can perform narrow confirmed operator actions when the user explicitly asks for a specific target: approve/deny/cancel one approval, run/pause/resume one automation job, cancel/retry one automation run, or run one schedule. Those calls use only public connected-host routes, require confirmation, and do not create, edit, or delete automation definitions.
|
|
122
124
|
|
|
125
|
+
When the main assistant conversation needs to change Agent settings or run a user-facing harness action, it should use `agent_harness` rather than generic SDK context/settings tools. Setting descriptors report writability, workspace visibility, and lock reasons; secret-backed settings store raw values through the secret manager; connected-host lifecycle settings stay read-only in Agent; and destructive local record deletion requires explicit confirmation.
|
|
126
|
+
|
|
123
127
|
## Connected GoodVibes Host
|
|
124
128
|
|
|
125
129
|
Start the owning GoodVibes host before using connected Agent features. Agent expects that host to expose the public operator/Agent routes, including:
|
|
@@ -134,7 +138,7 @@ If the GoodVibes API is not on `http://127.0.0.1:3421`, pass `--runtime-url http
|
|
|
134
138
|
|
|
135
139
|
Agent Knowledge is an Agent-owned product segment. Agent commands must not fall back to default knowledge or other product-specific knowledge spaces.
|
|
136
140
|
|
|
137
|
-
Host lifecycle commands are not part of GoodVibes Agent. Use Agent Workspace -> Home -> Host compatibility, Doctor diagnostics, and Review health for diagnostics. CLI status/doctor/compat commands are scriptable mirrors for install checks.
|
|
141
|
+
Host lifecycle commands are not part of GoodVibes Agent. Use Agent Workspace -> Home -> Host compatibility, Doctor diagnostics, and Review health for diagnostics. CLI status/doctor/compat commands are scriptable mirrors for install checks. The model-visible `connected_host` harness report lists usable Agent route families, first-class tool capabilities, and blocked lifecycle/non-Agent surfaces without exposing host start/stop/restart/install operations.
|
|
138
142
|
|
|
139
143
|
## Current Product Notes
|
|
140
144
|
|
|
@@ -41,7 +41,7 @@ Agent Knowledge writes are explicit-user-action paths. Slash commands that inges
|
|
|
41
41
|
|
|
42
42
|
## Ask And Search
|
|
43
43
|
|
|
44
|
-
Use Agent Workspace -> Knowledge -> Ask Agent
|
|
44
|
+
Use Agent Workspace -> Knowledge -> Ask Agent Knowledge for source-backed Agent Knowledge answers. `/knowledge ask <query>` and `goodvibes-agent ask <query>` are scriptable equivalents over the same route. Default output is concise:
|
|
45
45
|
|
|
46
46
|
- answer text or a clear no-match state;
|
|
47
47
|
- confidence when present;
|
|
@@ -52,7 +52,7 @@ Use Agent Workspace -> Knowledge -> Ask Agent knowledge for source-backed Agent
|
|
|
52
52
|
|
|
53
53
|
The command layer does not turn search results into an answer locally and does not apply client-side filters to hide contamination. Isolation must come from the Agent Knowledge route itself.
|
|
54
54
|
|
|
55
|
-
Use Agent Workspace -> Knowledge -> Search Agent
|
|
55
|
+
Use Agent Workspace -> Knowledge -> Search Agent Knowledge for interactive search. `/knowledge search <query>` and `goodvibes-agent search <query>` query the isolated Agent Knowledge search route and render bounded results with title, id, type, score, source, URL, and snippets when available. Empty Agent stores return an explicit empty state.
|
|
56
56
|
|
|
57
57
|
Read-only inspection is available from the TUI Knowledge workspace first, with CLI equivalents for scripts:
|
|
58
58
|
|
|
@@ -82,7 +82,9 @@ Artifacts are first-class runtime objects for files, images, audio, video, gener
|
|
|
82
82
|
|
|
83
83
|
Agent Workspace -> Voice & Media -> Generate media creates image/video artifacts through configured media providers after typed confirmation. The main conversation can perform the same confirmed action with the `agent_media_generate` tool when the user explicitly asks for generated media. Generated media output is summarized as artifact ids, MIME types, filenames, and source URLs when present; inline base64 is not printed into the transcript.
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
The model can discover the user-facing Knowledge, artifact, research, and media actions with `agent_harness` workspace action modes. When a workspace action maps to a concrete slash command, `agent_harness` can run that command with confirmation. For common product workflows, use the first-class tools first: `agent_knowledge`, `agent_knowledge_ingest`, and `agent_media_generate`.
|
|
86
|
+
|
|
87
|
+
Multimodal outputs should stay in the conversation, artifacts, local notes or memory, or explicit delegation results unless the user explicitly ingests a reviewed source through an Agent Knowledge route. They must not be inserted into default knowledge.
|
|
86
88
|
|
|
87
89
|
## Related Docs
|
|
88
90
|
|
package/docs/project-planning.md
CHANGED
|
@@ -39,7 +39,7 @@ The planning loop can be paused with natural language such as "stop planning" or
|
|
|
39
39
|
|
|
40
40
|
## Planning View
|
|
41
41
|
|
|
42
|
-
The planning view is transcript-first
|
|
42
|
+
The planning view is transcript-first. It shows:
|
|
43
43
|
|
|
44
44
|
- workspace project id and planning namespace;
|
|
45
45
|
- readiness and approval state;
|
|
@@ -70,6 +70,8 @@ The work-plan tracker is for concrete, durable task state after work becomes act
|
|
|
70
70
|
|
|
71
71
|
Use `/workplan` when the work already has tasks and needs status tracking. Use `/delegate` when explicit build/fix/review work should go to GoodVibes TUI.
|
|
72
72
|
|
|
73
|
+
The model can keep the same visible work plan current with `agent_work_plan`. It can also discover `/plan`, `/workplan`, and delegation workspace actions through `agent_harness`; destructive work-plan changes still require explicit user request and confirmation.
|
|
74
|
+
|
|
73
75
|
## Agent Knowledge Boundary
|
|
74
76
|
|
|
75
77
|
Planning may link to Agent Knowledge evidence, but it must not query or ingest through default knowledge. Source-backed facts for Agent belong under:
|
|
@@ -11,6 +11,7 @@ Provider and model state should be visible in:
|
|
|
11
11
|
- `/model` and `/provider`;
|
|
12
12
|
- the Agent operator workspace setup checklist;
|
|
13
13
|
- the TTS configuration workspace when spoken turns are used.
|
|
14
|
+
- `agent_harness` settings and workspace-action discovery when the model needs to inspect or change Agent-owned routing settings.
|
|
14
15
|
|
|
15
16
|
When a selected model is provider-qualified, Agent keeps the runtime provider row and raw model id separate. For example, `openai-subscriber` plus `openai:gpt-5.5` should route as provider `openai-subscriber` and model `gpt-5.5` where the public route expects provider/model fields.
|
|
16
17
|
|
|
@@ -39,6 +40,8 @@ Search, voice, media, and multimodal providers are valid Agent features when the
|
|
|
39
40
|
|
|
40
41
|
Outputs that should become durable knowledge must go through Agent Knowledge routes. No provider output should be inserted into default knowledge or another product segment by Agent.
|
|
41
42
|
|
|
43
|
+
Setting changes are available to the model through `agent_harness` only when the user explicitly asks. Secret-backed provider or channel values are stored through the secret manager and displayed as redacted references.
|
|
44
|
+
|
|
42
45
|
## Related Docs
|
|
43
46
|
|
|
44
47
|
- [Getting started](getting-started.md)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Release And Publishing
|
|
2
2
|
|
|
3
|
-
GoodVibes Agent's current installable
|
|
3
|
+
GoodVibes Agent's current installable `1.0.x` version is recorded in `package.json` and `CHANGELOG.md`.
|
|
4
4
|
|
|
5
5
|
## Package Identity
|
|
6
6
|
|
|
@@ -11,6 +11,7 @@ GoodVibes Agent's current installable public alpha version is recorded in `packa
|
|
|
11
11
|
- source language: TypeScript
|
|
12
12
|
- package docs: every Markdown file under `docs/*.md`
|
|
13
13
|
- connected host ownership: outside Agent
|
|
14
|
+
- current release line: `1.0.x`
|
|
14
15
|
|
|
15
16
|
End users install and run GoodVibes Agent with Bun:
|
|
16
17
|
|
|
@@ -23,7 +24,7 @@ Do not add non-Bun install instructions for this product. The package is hosted
|
|
|
23
24
|
|
|
24
25
|
## Required Gates
|
|
25
26
|
|
|
26
|
-
Before any release candidate:
|
|
27
|
+
Before any release candidate or patch release:
|
|
27
28
|
|
|
28
29
|
```sh
|
|
29
30
|
bun install
|
|
@@ -45,13 +46,13 @@ Shared release metadata verification requires the `prebuild` and `version` packa
|
|
|
45
46
|
|
|
46
47
|
`bun run publish:package` publishes from a staged package directory to the package registry. It re-runs the shared package policy checks against the source tree, filters forbidden package paths during staging, and verifies the staged package docs, required package paths, and metadata before invoking npm. If `NPM_CONFIG_USERCONFIG` is already set, the registry publish command uses it. Otherwise the script creates a temporary 0600 registry userconfig from `NODE_AUTH_TOKEN` or `NPM_TOKEN`, uses it for that publish command, and removes it with the staging directory. The publish script is idempotent for reruns: if the exact package version is already present on the registry, it reports that state and exits successfully instead of failing the release retry. Shared release metadata verification requires those staged source/staged policy checks, forbidden-path filtering, docs checks, auth handoff, idempotent lookup, dry-run pack, public publish, and cleanup markers to remain in the publish script.
|
|
47
48
|
|
|
48
|
-
`bun run release` requires product release notes instead of raw git-log output. Pass `--notes-file ./release-notes.md` or set `GOODVIBES_AGENT_RELEASE_NOTES` before a real release. The 1.0 release candidate
|
|
49
|
+
`bun run release` requires product release notes instead of raw git-log output. Pass `--notes-file ./release-notes.md` or set `GOODVIBES_AGENT_RELEASE_NOTES` before a real release. For current `1.0.x` patch releases, use product-facing notes that summarize the complete patch contents, not only the first fix in the batch. The original 1.0 release candidate used `--notes-file release/1.0-release-notes.md`, and release metadata verification keeps that artifact with the release readiness and live-verification evidence. Release notes should describe what changed for Agent users: TUI behavior, setup, Agent Knowledge, local behavior libraries, connected-host compatibility, package/install behavior, model-visible harness behavior, and safety policy. Do not use commit hashes as the shipped changelog content.
|
|
49
50
|
|
|
50
51
|
Before it mutates version metadata or creates a tag, `bun run release` checks the declared `release/1.0-*` evidence files for existence, non-empty content, final newlines, trailing whitespace, and space-before-tab indentation, then enforces the non-test release gates: typecheck, architecture check, performance check, build, publish check, packed install smoke, verification ledger, pack dry-run, and `git diff --check`. Dry-run previews run the same evidence text hygiene check without writing files, commits, or tags. After it writes the release version, `src/version.ts` fallback, and changelog section, it verifies release metadata and package-facing text policy again, then reruns evidence hygiene and diff hygiene before creating the commit and tag. That package policy check proves `package.json`, `CHANGELOG.md`, and the `src/version.ts` fallback literals agree on the Agent and SDK versions, that the package manifest keeps the required Agent runtime/docs files, exclusions, release/publish script entrypoints, and local CI gate entrypoints without explicitly including forbidden Agent/TUI boundary paths or leaving existing forbidden paths reachable through broad includes, that the local release script still requires product notes, real-release validation, post-mutation package policy, docs staging, and annotated tags, that the GitHub setup action uses the same Bun version as `packageManager`, and that package-facing text is present and still follows Agent docs, rendered CLI help, parser-backed CLI command snippets, parser/type/alias/help/handler/top-level help command coverage, exported package-text source coverage, autocomplete overlay text, context inspector text, in-app help overlays, file/bookmark picker text, live process output text, MCP workspace text, model picker/workspace text, profile/session picker text, process/runtime activity text, search overlays, shared selection/picker chrome, setup/onboarding wizard text, settings workspace text, slash-command registry text, Agent workspace catalog text, route boundaries, install policy, and version pins. The generated changelog heading uses the operator's local release date in `YYYY-MM-DD` form, not UTC rollover time. The prebuild version sync refuses missing, ranged, or otherwise non-exact Agent or SDK versions instead of writing placeholder fallbacks. The release commit stages those metadata files plus every package-facing `docs/*.md` page, so release docs cannot drift outside the tag. The full test suite remains a branch-CI responsibility and must already be green for the release SHA.
|
|
51
52
|
|
|
52
53
|
`--skip-validation` is only allowed with `--dry-run`. Real releases must run the validation gates above.
|
|
53
54
|
|
|
54
|
-
`--dry-run` is non-mutating and may be used from a dirty or non-main worktree to preview the next version and generated changelog section. For
|
|
55
|
+
`--dry-run` is non-mutating and may be used from a dirty or non-main worktree to preview the next version and generated changelog section. For current `1.0.x` patch previews, use `bun run scripts/release.ts --dry-run --patch --notes-file ./release-notes.md`. The historical 1.0 major cut used `bun run scripts/release.ts --dry-run --major --notes-file release/1.0-release-notes.md`. Real releases still require a clean worktree on `main`.
|
|
55
56
|
|
|
56
57
|
The GitHub release workflow publishes to npm only when the repository variable `PUBLISH_NPM` is `true` and the repository secret `NPM_TOKEN` is configured. Without those repository settings, the workflow still validates and creates the GitHub release, but npm publish must be run from a local environment with an exported token. After optional npm publish, the workflow installs the exact registry version into an isolated Bun home, seeds a connected-host token sentinel, captures stdout and stderr for `--version`, `--help`, and `status --json`, and fails without printing that sentinel. Shared release metadata verification requires those publish, exact-version registry lookup, install smoke, and token-sentinel markers to remain in the release workflow.
|
|
57
58
|
|
|
@@ -67,7 +68,7 @@ Shared release metadata verification requires `perf:check` to load `release/1.0-
|
|
|
67
68
|
|
|
68
69
|
Shared release metadata verification requires `verification:ledger` to keep JSON and Markdown evidence output plus inventory coverage for settings schema, feature flags, slash commands, built-in panels, top-level CLI commands, external surfaces, and onboarding capability bundles, including local-signal, local-behavior, and external-outcome accounting.
|
|
69
70
|
|
|
70
|
-
Shared release metadata verification requires `verification:live` to keep the external-outcome audit for release candidates: compiled CLI checks, connected-host token/URL discovery, connected-host status/health/model routes, isolated Agent Knowledge status/ask/search routes, SDK-version mismatch skip policy, JSON/Markdown report artifacts, strict mode, and Agent Knowledge contamination guards.
|
|
71
|
+
Shared release metadata verification requires `verification:live` to keep the external-outcome audit for release candidates and real releases: compiled CLI checks, connected-host token/URL discovery, connected-host status/health/model routes, isolated Agent Knowledge status/ask/search routes, SDK-version mismatch skip policy, JSON/Markdown report artifacts, strict mode, and Agent Knowledge contamination guards.
|
|
71
72
|
|
|
72
73
|
Do not add targeted `bun test` passes or separate release-only test gates to CI, release, or aggregate scripts. Tests that matter for release must be included in the single full branch-CI suite.
|
|
73
74
|
|
|
@@ -102,4 +103,4 @@ Do not ship connected-host binaries from this package. If Agent later gets compi
|
|
|
102
103
|
|
|
103
104
|
## Product Rule
|
|
104
105
|
|
|
105
|
-
The
|
|
106
|
+
The `1.0.x` line can include mature terminal foundation code, but package-facing behavior must follow Agent product policy. Follow-up patch releases should continue pruning or reshaping coding-first surfaces while preserving the renderer, input, fullscreen workspace, command registry, and release foundation.
|
|
@@ -7,7 +7,7 @@ GoodVibes Agent is an operator assistant TUI. Its command set is centered on mai
|
|
|
7
7
|
- Normal chat stays in the main Agent conversation.
|
|
8
8
|
- Agent Knowledge uses only `/api/goodvibes-agent/knowledge/*`.
|
|
9
9
|
- Agent never falls back to default knowledge or arbitrary non-Agent knowledge spaces.
|
|
10
|
-
- Local memory, notes, routines, skills, and personas remain Agent-local
|
|
10
|
+
- Local memory, notes, routines, skills, and personas remain Agent-local unless an explicit Agent workflow promotes reviewed material into another Agent-owned surface.
|
|
11
11
|
- Runtime hosting is external. Agent connects to it and reports health; it does not start, stop, restart, or install it.
|
|
12
12
|
- Delegated review is not a default reasoning path. It is requested only when the user explicitly asks for build, implementation, fix, or review work.
|
|
13
13
|
- Code-building work is delegated to GoodVibes TUI through public shared-session/task contracts.
|
|
@@ -28,7 +28,7 @@ High-signal Agent TUI paths:
|
|
|
28
28
|
- `/memory`, `/routines`, `/skills`, and `/personas` for Agent-local context and reusable operator behavior.
|
|
29
29
|
- `/plan` for Agent-owned workspace planning state in the main conversation.
|
|
30
30
|
- `/workplan` for durable task status over public work-plan routes.
|
|
31
|
-
- `/
|
|
31
|
+
- `/approval` for pending approval visibility and explicit approval actions.
|
|
32
32
|
- `/schedule` for schedule visibility plus narrow explicit-user-action flows.
|
|
33
33
|
- `/channels` for channel readiness and one-message confirmed channel delivery.
|
|
34
34
|
- `/media` for media provider readiness and confirmed image/video artifact generation.
|
|
@@ -39,12 +39,107 @@ The installed `goodvibes-agent` command launches the TUI by default. Subcommands
|
|
|
39
39
|
|
|
40
40
|
Host-management and coding-first commands that would imply connected-host lifecycle ownership, separate Agent job creation, execution-isolation ownership, worktree control, or implicit delegated review must remain blocked, read-only, or delegation-only unless they are intentionally adapted to Agent policy.
|
|
41
41
|
|
|
42
|
+
## Model-Visible Harness Surface
|
|
43
|
+
|
|
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
|
+
|
|
46
|
+
- `agent_harness`: inspect workspace categories/actions, inspect slash commands and command policy metadata, run concrete workspace or slash-command mirrors with confirmation, inspect model tools, inspect or change Agent settings, and inspect connected-host posture.
|
|
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
|
+
- `agent_knowledge` and `agent_knowledge_ingest`: ask/search and ingest into the isolated Agent Knowledge segment.
|
|
49
|
+
- `agent_operator_briefing` and `agent_operator_action`: inspect connected work/approval/automation posture, or run exact confirmed approval/automation actions.
|
|
50
|
+
- `agent_work_plan`: keep the visible Agent-local work plan current from the conversation.
|
|
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
|
+
|
|
53
|
+
`agent_harness` discovery modes are read-only. `summary` reports the model access map; `commands` and `command` return 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; and `connected_host` returns the connected-host route families, allowed capabilities, blocked capabilities, and first-class tool availability.
|
|
54
|
+
|
|
55
|
+
Setting writes, setting resets, slash-command invocation, workspace-action invocation, local record deletion, channel sends, notifications, reminders, media generation, and connected-host operator mutations require explicit user request and confirmation. Secret-backed settings are stored through the secret manager, and connected-host lifecycle/listener settings remain read-only in Agent.
|
|
56
|
+
|
|
57
|
+
Selection-based local workspace actions use the same bridge. `agent_harness` reports the required model tool for each local action; for actions that depend on the TUI selection, call `run_workspace_action` with the selected local `recordId`. Note promotion actions can prefill and create memory, personas, skills, routines, or isolated Agent Knowledge URL ingests through the matching first-class model tool. Profile creation schemas include the current runtime starter-template inventory, and routine schedule schemas prefill the selected routine when `recordId` or a `routineId` field matches a local routine.
|
|
58
|
+
|
|
59
|
+
Use first-class Agent tools before falling back to slash-command mirrors. Slash-command execution is for harness parity and scriptable mirrors, not for bypassing Agent product boundaries.
|
|
60
|
+
|
|
42
61
|
The main composer supports inline context references. Type `@path/to/file`, `@path/to/folder`, or `@https://example.test/page` in a normal prompt to add bounded context for that turn. `!@path/to/file` remains the raw file-injection form. These references do not ingest anything into Agent Knowledge unless the user explicitly runs a Knowledge ingest action.
|
|
43
62
|
|
|
44
63
|
The Research workspace submits web research and URL inspection forms to the normal main conversation. These requests are read-only by default, may use connected web tools when the user asks, and do not ingest sources. Use confirmed Agent Knowledge ingest actions only after a source should become durable Agent-owned knowledge.
|
|
45
64
|
|
|
46
65
|
Local memory capture/add commands are explicit Agent-local actions. Deletes, imports/exports, record linking, review-state changes, and promotion across memory scopes require `--yes`.
|
|
47
66
|
|
|
67
|
+
## Slash Command Catalog
|
|
68
|
+
|
|
69
|
+
Every registered slash-command root in the Agent TUI is listed here. Aliases resolve through the same command registry but are intentionally secondary to the canonical roots.
|
|
70
|
+
|
|
71
|
+
| Command | Purpose |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `/accounts` | Review provider auth routes, subscription windows, and billing-path safety. |
|
|
74
|
+
| `/agent` | Open the GoodVibes Agent operator workspace. |
|
|
75
|
+
| `/agent-profile` | Manage isolated Agent profiles and starter templates. |
|
|
76
|
+
| `/approval` | Review approval classes and run exact confirmed approval actions. |
|
|
77
|
+
| `/auth` | Review provider auth posture and export redacted auth review bundles. |
|
|
78
|
+
| `/automation` | Run confirmed connected-host automation actions from the Agent TUI. |
|
|
79
|
+
| `/bookmarks` | List bookmarked transcript blocks. |
|
|
80
|
+
| `/brief` | Show a concise Agent operator briefing and next actions. |
|
|
81
|
+
| `/bundle` | Export, inspect, or import redacted Agent support bundles from the TUI. |
|
|
82
|
+
| `/channels` | Inspect channel readiness or send one explicitly confirmed delivery message. |
|
|
83
|
+
| `/clear` | Clear the conversation display while keeping LLM context. |
|
|
84
|
+
| `/collapse` | Collapse rendered blocks by type. |
|
|
85
|
+
| `/commands` | Browse all commands in a scrollable list. |
|
|
86
|
+
| `/compact` | Summarize the conversation to free context window. |
|
|
87
|
+
| `/compat` | Inspect Agent SDK pin, connected-host version, and Agent Knowledge route readiness. |
|
|
88
|
+
| `/config` | Open the fullscreen configuration workspace. |
|
|
89
|
+
| `/context` | Inspect context-window usage and token breakdown. |
|
|
90
|
+
| `/conversation` | Review conversation structure, transcript hotspots, and composer posture. |
|
|
91
|
+
| `/delegate` | Explicitly delegate build/fix/review work to GoodVibes TUI. |
|
|
92
|
+
| `/effort` | Show or set reasoning effort level. |
|
|
93
|
+
| `/expand` | Expand rendered blocks by type. |
|
|
94
|
+
| `/export` | Export the current conversation to Markdown. |
|
|
95
|
+
| `/health` | Review startup posture, connected-host readiness, provider health, and Agent continuity. |
|
|
96
|
+
| `/help` | Show available commands and keyboard shortcuts. |
|
|
97
|
+
| `/image` | Attach an image file to the next message. |
|
|
98
|
+
| `/keybindings` | List keyboard bindings and the config file path. |
|
|
99
|
+
| `/knowledge` | Use isolated Agent Knowledge sources, graph, review queue, ask/search, ingest, and compact prompt packets. |
|
|
100
|
+
| `/load` | Load a saved Agent session. |
|
|
101
|
+
| `/mcp` | Manage MCP servers, trust posture, and tool inventory. |
|
|
102
|
+
| `/media` | Inspect media providers or generate media through configured providers. |
|
|
103
|
+
| `/memory` | Add, search, review, stale, or delete Agent-local memory records. |
|
|
104
|
+
| `/mode` | Manage Agent interaction mode and per-domain verbosity. |
|
|
105
|
+
| `/model` | Select or display the current LLM model. |
|
|
106
|
+
| `/next-error` | Jump to the next error message in the conversation. |
|
|
107
|
+
| `/notes` | Open Agent-local scratchpad notes in the operator workspace. |
|
|
108
|
+
| `/notify` | Manage and send configured Agent webhook notifications. |
|
|
109
|
+
| `/paste` | Insert clipboard text or image into the prompt. |
|
|
110
|
+
| `/personas` | Manage Agent-local personas. |
|
|
111
|
+
| `/pin` | Pin a model to the favorites list. |
|
|
112
|
+
| `/plan` | Inspect or seed Agent workspace planning state. |
|
|
113
|
+
| `/prev-error` | Jump to the previous error message in the conversation. |
|
|
114
|
+
| `/provider` | Switch provider or manage custom providers. |
|
|
115
|
+
| `/qrcode` | Print companion pairing details and a QR code. |
|
|
116
|
+
| `/quit` | Exit the application. |
|
|
117
|
+
| `/redo` | Redo the last undone conversation turn. |
|
|
118
|
+
| `/refresh-models` | Refresh model catalog, benchmarks, and token limits. |
|
|
119
|
+
| `/reset` | Clear display and conversation context. |
|
|
120
|
+
| `/retry` | Re-send the last user message, optionally with modified text. |
|
|
121
|
+
| `/routines` | Manage Agent-local routines and explicit routine schedule promotion. |
|
|
122
|
+
| `/save` | Save the current session. |
|
|
123
|
+
| `/schedule` | Inspect schedules, create confirmed reminders, and promote routines to connected schedules. |
|
|
124
|
+
| `/secrets` | Manage hierarchy-aware secrets, external secret refs, and secure/plaintext storage policy. |
|
|
125
|
+
| `/security` | Inspect security posture, attack paths, and review state. |
|
|
126
|
+
| `/session` | Inspect session continuity and cross-session graph state. |
|
|
127
|
+
| `/sessions` | List saved sessions. |
|
|
128
|
+
| `/settings` | Open, inspect, set, or reset Agent settings. |
|
|
129
|
+
| `/setup` | Open Agent setup with current settings preloaded. |
|
|
130
|
+
| `/shortcuts` | Show keyboard shortcuts. |
|
|
131
|
+
| `/skills` | Manage Agent-local skills and skill bundles. |
|
|
132
|
+
| `/subscription` | Manage provider subscription sessions. |
|
|
133
|
+
| `/tasks` | Inspect connected-host tasks without starting or mutating local background work. |
|
|
134
|
+
| `/title` | Show or set the conversation title. |
|
|
135
|
+
| `/trust` | Review trust posture and export portable trust bundles. |
|
|
136
|
+
| `/tts` | Submit a normal prompt and play the assistant response through live TTS. |
|
|
137
|
+
| `/undo` | Undo the last conversation turn. |
|
|
138
|
+
| `/unpin` | Unpin a model from the favorites list. |
|
|
139
|
+
| `/voice` | Review voice posture and package portable voice interaction metadata. |
|
|
140
|
+
| `/welcome` | Open or print the Agent setup guide. |
|
|
141
|
+
| `/workplan` | Track a persistent workspace-scoped work plan. |
|
|
142
|
+
|
|
48
143
|
## Agent Knowledge
|
|
49
144
|
|
|
50
145
|
`/knowledge ask <query>` asks the isolated Agent Knowledge environment for a source-backed answer through `/api/goodvibes-agent/knowledge/ask`.
|
|
@@ -20,6 +20,8 @@ GoodVibes Agent supports spoken turns as an Agent TUI feature. Text output remai
|
|
|
20
20
|
|
|
21
21
|
`/config tts` opens the fullscreen configuration workspace for streaming provider, voice, and spoken-turn model routing.
|
|
22
22
|
|
|
23
|
+
The model can inspect the same settings through `agent_harness` settings modes and can change Agent-owned TTS settings with explicit confirmation. Connected-host listener or lifecycle settings remain outside Agent ownership.
|
|
24
|
+
|
|
23
25
|
## Playback Requirements
|
|
24
26
|
|
|
25
27
|
Live playback streams audio to a local player. Install one of:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
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,266 @@
|
|
|
1
|
+
import type { ConfigKey, ConfigManager, ConfigSetting } from '@pellux/goodvibes-sdk/platform/config';
|
|
2
|
+
import { isValidConfigKey } from '@pellux/goodvibes-sdk/platform/config';
|
|
3
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
4
|
+
import type { SecretsManager } from '../config/secrets.ts';
|
|
5
|
+
import {
|
|
6
|
+
buildGoodVibesSecretKey,
|
|
7
|
+
isSecretConfigKey,
|
|
8
|
+
isSecretReferenceValue,
|
|
9
|
+
persistSecretBackedConfigValue,
|
|
10
|
+
} from '../config/secret-config.ts';
|
|
11
|
+
import {
|
|
12
|
+
AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON,
|
|
13
|
+
isAgentHiddenSettingKey,
|
|
14
|
+
isExternalHostOwnedSettingKey,
|
|
15
|
+
} from '../config/agent-settings-policy.ts';
|
|
16
|
+
|
|
17
|
+
export interface HarnessSettingFilters {
|
|
18
|
+
readonly key?: string;
|
|
19
|
+
readonly category?: string;
|
|
20
|
+
readonly prefix?: string;
|
|
21
|
+
readonly query?: string;
|
|
22
|
+
readonly includeHidden?: boolean;
|
|
23
|
+
readonly limit?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface HarnessSettingDescriptor {
|
|
27
|
+
readonly key: string;
|
|
28
|
+
readonly category: string;
|
|
29
|
+
readonly type: ConfigSetting['type'];
|
|
30
|
+
readonly value: unknown;
|
|
31
|
+
readonly default: unknown;
|
|
32
|
+
readonly configured: boolean;
|
|
33
|
+
readonly writable: boolean;
|
|
34
|
+
readonly visibleInWorkspace: boolean;
|
|
35
|
+
readonly lockReason?: string;
|
|
36
|
+
readonly description: string;
|
|
37
|
+
readonly enumValues?: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface HarnessSettingMutationResult {
|
|
41
|
+
readonly key: string;
|
|
42
|
+
readonly action: 'set' | 'reset';
|
|
43
|
+
readonly previous: unknown;
|
|
44
|
+
readonly current: unknown;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const DEFAULT_SETTING_LIMIT = 100;
|
|
48
|
+
const SENSITIVE_KEY_PATTERN = /(?:secret|token|password|api[-_.]?key|signing)/i;
|
|
49
|
+
|
|
50
|
+
function valuesEqual(left: unknown, right: unknown): boolean {
|
|
51
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function clampLimit(value: unknown, fallback = DEFAULT_SETTING_LIMIT): number {
|
|
55
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;
|
|
56
|
+
return Math.max(1, Math.min(500, Math.trunc(value)));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function findSetting(configManager: Pick<ConfigManager, 'getSchema'>, rawKey: string): ConfigSetting | null {
|
|
60
|
+
if (!rawKey || !isValidConfigKey(rawKey)) return null;
|
|
61
|
+
return configManager.getSchema().find((setting) => setting.key === rawKey) ?? null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function redactHarnessSettingValue(key: string, value: unknown): unknown {
|
|
65
|
+
if (typeof value !== 'string') return value;
|
|
66
|
+
if (!value) return value;
|
|
67
|
+
if (isSecretConfigKey(key) || SENSITIVE_KEY_PATTERN.test(key)) {
|
|
68
|
+
if (isSecretReferenceValue(value)) return '<secret-ref>';
|
|
69
|
+
return '<redacted>';
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function describeHarnessSetting(
|
|
75
|
+
configManager: Pick<ConfigManager, 'get'>,
|
|
76
|
+
setting: ConfigSetting,
|
|
77
|
+
): HarnessSettingDescriptor {
|
|
78
|
+
const value = configManager.get(setting.key as ConfigKey);
|
|
79
|
+
const hostOwned = isExternalHostOwnedSettingKey(setting.key);
|
|
80
|
+
return {
|
|
81
|
+
key: setting.key,
|
|
82
|
+
category: setting.key.split('.')[0] ?? '',
|
|
83
|
+
type: setting.type,
|
|
84
|
+
value: redactHarnessSettingValue(setting.key, value),
|
|
85
|
+
default: redactHarnessSettingValue(setting.key, setting.default),
|
|
86
|
+
configured: !valuesEqual(value, setting.default),
|
|
87
|
+
writable: !hostOwned,
|
|
88
|
+
visibleInWorkspace: !isAgentHiddenSettingKey(setting.key),
|
|
89
|
+
...(hostOwned ? { lockReason: AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON } : {}),
|
|
90
|
+
description: setting.description,
|
|
91
|
+
...(setting.enumValues ? { enumValues: setting.enumValues } : {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function listHarnessSettings(
|
|
96
|
+
configManager: Pick<ConfigManager, 'get' | 'getSchema'>,
|
|
97
|
+
filters: HarnessSettingFilters = {},
|
|
98
|
+
): readonly HarnessSettingDescriptor[] {
|
|
99
|
+
const key = filters.key?.trim();
|
|
100
|
+
const category = filters.category?.trim();
|
|
101
|
+
const prefix = filters.prefix?.trim();
|
|
102
|
+
const query = filters.query?.trim().toLowerCase();
|
|
103
|
+
const limit = clampLimit(filters.limit);
|
|
104
|
+
|
|
105
|
+
return configManager.getSchema()
|
|
106
|
+
.filter((setting) => {
|
|
107
|
+
if (key && setting.key !== key) return false;
|
|
108
|
+
if (category && setting.key.split('.')[0] !== category) return false;
|
|
109
|
+
if (prefix && !setting.key.startsWith(prefix)) return false;
|
|
110
|
+
if (!filters.includeHidden && isAgentHiddenSettingKey(setting.key)) return false;
|
|
111
|
+
if (query) {
|
|
112
|
+
const text = [setting.key, setting.description, setting.type, ...(setting.enumValues ?? [])].join('\n').toLowerCase();
|
|
113
|
+
if (!text.includes(query)) return false;
|
|
114
|
+
}
|
|
115
|
+
return true;
|
|
116
|
+
})
|
|
117
|
+
.map((setting) => describeHarnessSetting(configManager, setting))
|
|
118
|
+
.slice(0, limit);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function getHarnessSetting(
|
|
122
|
+
configManager: Pick<ConfigManager, 'get' | 'getSchema'>,
|
|
123
|
+
key: string,
|
|
124
|
+
): HarnessSettingDescriptor | null {
|
|
125
|
+
const setting = findSetting(configManager, key);
|
|
126
|
+
return setting ? describeHarnessSetting(configManager, setting) : null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function coerceBoolean(value: unknown): boolean {
|
|
130
|
+
if (typeof value === 'boolean') return value;
|
|
131
|
+
if (typeof value === 'number') {
|
|
132
|
+
if (value === 1) return true;
|
|
133
|
+
if (value === 0) return false;
|
|
134
|
+
}
|
|
135
|
+
if (typeof value === 'string') {
|
|
136
|
+
const normalized = value.trim().toLowerCase();
|
|
137
|
+
if (['true', '1', 'yes', 'on', 'enabled'].includes(normalized)) return true;
|
|
138
|
+
if (['false', '0', 'no', 'off', 'disabled'].includes(normalized)) return false;
|
|
139
|
+
}
|
|
140
|
+
throw new Error(`Expected boolean value, got ${String(value)}.`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function coerceHarnessSettingValue(setting: ConfigSetting, value: unknown): unknown {
|
|
144
|
+
if (setting.type === 'boolean') return coerceBoolean(value);
|
|
145
|
+
if (setting.type === 'number') {
|
|
146
|
+
const parsed = typeof value === 'number' ? value : Number(String(value).trim());
|
|
147
|
+
if (!Number.isFinite(parsed)) throw new Error(`Expected numeric value for ${setting.key}.`);
|
|
148
|
+
return parsed;
|
|
149
|
+
}
|
|
150
|
+
if (setting.type === 'enum') {
|
|
151
|
+
const parsed = String(value).trim();
|
|
152
|
+
if (!setting.enumValues?.includes(parsed)) {
|
|
153
|
+
throw new Error(`Invalid value for ${setting.key}. Allowed: ${(setting.enumValues ?? []).join(', ')}.`);
|
|
154
|
+
}
|
|
155
|
+
return parsed;
|
|
156
|
+
}
|
|
157
|
+
return typeof value === 'string' ? value : String(value);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export async function setHarnessSetting(
|
|
161
|
+
configManager: ConfigManager,
|
|
162
|
+
secretsManager: Pick<SecretsManager, 'set' | 'delete'> | null | undefined,
|
|
163
|
+
key: string,
|
|
164
|
+
value: unknown,
|
|
165
|
+
): Promise<HarnessSettingMutationResult> {
|
|
166
|
+
const setting = findSetting(configManager, key);
|
|
167
|
+
if (!setting) throw new Error(`Unknown setting ${key || '<missing>'}.`);
|
|
168
|
+
if (isExternalHostOwnedSettingKey(setting.key)) throw new Error(AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON);
|
|
169
|
+
|
|
170
|
+
const previous = configManager.get(setting.key as ConfigKey);
|
|
171
|
+
const coerced = coerceHarnessSettingValue(setting, value);
|
|
172
|
+
if (setting.type === 'string' && isSecretConfigKey(setting.key)) {
|
|
173
|
+
const secretValue = String(coerced);
|
|
174
|
+
if (secretValue.trim() && !isSecretReferenceValue(secretValue) && !secretsManager?.set) {
|
|
175
|
+
throw new Error(`Cannot store raw secret value for ${setting.key}: secrets manager is unavailable.`);
|
|
176
|
+
}
|
|
177
|
+
const current = await persistSecretBackedConfigValue(
|
|
178
|
+
configManager,
|
|
179
|
+
secretsManager,
|
|
180
|
+
setting.key as ConfigKey,
|
|
181
|
+
secretValue,
|
|
182
|
+
{ scope: 'user' },
|
|
183
|
+
);
|
|
184
|
+
return {
|
|
185
|
+
key: setting.key,
|
|
186
|
+
action: 'set',
|
|
187
|
+
previous: redactHarnessSettingValue(setting.key, previous),
|
|
188
|
+
current: redactHarnessSettingValue(setting.key, current),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
configManager.setDynamic(setting.key as ConfigKey, coerced);
|
|
193
|
+
return {
|
|
194
|
+
key: setting.key,
|
|
195
|
+
action: 'set',
|
|
196
|
+
previous: redactHarnessSettingValue(setting.key, previous),
|
|
197
|
+
current: redactHarnessSettingValue(setting.key, configManager.get(setting.key as ConfigKey)),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export async function resetHarnessSetting(
|
|
202
|
+
configManager: ConfigManager,
|
|
203
|
+
secretsManager: Pick<SecretsManager, 'delete'> | null | undefined,
|
|
204
|
+
key: string,
|
|
205
|
+
): Promise<HarnessSettingMutationResult> {
|
|
206
|
+
const setting = findSetting(configManager, key);
|
|
207
|
+
if (!setting) throw new Error(`Unknown setting ${key || '<missing>'}.`);
|
|
208
|
+
if (isExternalHostOwnedSettingKey(setting.key)) throw new Error(AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON);
|
|
209
|
+
|
|
210
|
+
const previous = configManager.get(setting.key as ConfigKey);
|
|
211
|
+
if (isSecretConfigKey(setting.key)) {
|
|
212
|
+
if (typeof previous === 'string' && isSecretReferenceValue(previous) && !secretsManager?.delete) {
|
|
213
|
+
throw new Error(`Cannot reset ${setting.key}: secrets manager is unavailable to delete the stored secret.`);
|
|
214
|
+
}
|
|
215
|
+
await secretsManager?.delete?.(buildGoodVibesSecretKey(setting.key), { scope: 'user' });
|
|
216
|
+
}
|
|
217
|
+
configManager.reset(setting.key as ConfigKey);
|
|
218
|
+
return {
|
|
219
|
+
key: setting.key,
|
|
220
|
+
action: 'reset',
|
|
221
|
+
previous: redactHarnessSettingValue(setting.key, previous),
|
|
222
|
+
current: redactHarnessSettingValue(setting.key, configManager.get(setting.key as ConfigKey)),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function formatHarnessSettingList(settings: readonly HarnessSettingDescriptor[]): string {
|
|
227
|
+
if (settings.length === 0) return 'No settings matched.';
|
|
228
|
+
return [
|
|
229
|
+
`Settings (${settings.length})`,
|
|
230
|
+
...settings.map((setting) => {
|
|
231
|
+
const status = setting.writable ? 'writable' : 'read-only';
|
|
232
|
+
const visible = setting.visibleInWorkspace ? 'workspace' : 'scriptable';
|
|
233
|
+
return ` ${setting.key} ${setting.type} ${status}/${visible} current=${String(setting.value)}`;
|
|
234
|
+
}),
|
|
235
|
+
].join('\n');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function formatHarnessSetting(setting: HarnessSettingDescriptor | null): string {
|
|
239
|
+
if (!setting) return 'Unknown setting.';
|
|
240
|
+
return [
|
|
241
|
+
`Setting ${setting.key}`,
|
|
242
|
+
` category ${setting.category}`,
|
|
243
|
+
` type ${setting.type}`,
|
|
244
|
+
` current ${String(setting.value)}`,
|
|
245
|
+
` default ${String(setting.default)}`,
|
|
246
|
+
` configured ${setting.configured ? 'yes' : 'no'}`,
|
|
247
|
+
` writable ${setting.writable ? 'yes' : 'no'}`,
|
|
248
|
+
` workspace visible ${setting.visibleInWorkspace ? 'yes' : 'no'}`,
|
|
249
|
+
...(setting.enumValues ? [` values ${setting.enumValues.join(', ')}`] : []),
|
|
250
|
+
...(setting.lockReason ? [` lock ${setting.lockReason}`] : []),
|
|
251
|
+
` ${setting.description}`,
|
|
252
|
+
].join('\n');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function formatHarnessMutation(result: HarnessSettingMutationResult): string {
|
|
256
|
+
return [
|
|
257
|
+
`Setting ${result.action}`,
|
|
258
|
+
` key ${result.key}`,
|
|
259
|
+
` previous ${String(result.previous)}`,
|
|
260
|
+
` current ${String(result.current)}`,
|
|
261
|
+
].join('\n');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function formatHarnessError(error: unknown): string {
|
|
265
|
+
return summarizeError(error);
|
|
266
|
+
}
|