@pellux/goodvibes-agent 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +47 -2
- package/dist/package/main.js +68 -13
- package/package.json +1 -1
- package/release/live-verification/live-verification.json +13 -13
- package/release/live-verification/live-verification.md +15 -15
- package/release/release-notes.md +4 -10
- package/src/input/shell-passthrough.ts +58 -0
- package/src/main.ts +18 -1
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Product-facing release notes for GoodVibes Agent.
|
|
4
4
|
|
|
5
|
+
## 1.5.1 - 2026-06-14
|
|
6
|
+
|
|
7
|
+
- v1.5.1 is a patch on the 1.5 line. The fullscreen Agent workspace, Agent-local behavior, isolated Agent Knowledge, connected-host operator integration, and explicit side-effect boundaries all stay in force; this release restores the inline shell escape and refreshes release verification.
|
|
8
|
+
- Restored the inline shell escape in the prompt: type an exclamation mark followed by a command (for example, exclamation-mark git status) to run it in your working directory without leaving Agent. The command output appears inline, and the result is carried into your next message as context so you can run something and immediately ask about it. The composer already showed this as shell mode, but the command never actually ran since the workspace fork; it executes again now.
|
|
9
|
+
- The exclamation-hash memory pin is unchanged and still takes precedence, so pinning a note keeps working exactly as before.
|
|
10
|
+
- Release hygiene: regenerated the strict live-verification attestation against the running connected host so the published package carries current evidence.
|
|
11
|
+
- Test suite: 7931 pass / 0 fail / 2 skip across 554 files.
|
|
12
|
+
|
|
5
13
|
## 1.5.0 - 2026-06-11
|
|
6
14
|
|
|
7
15
|
- v1.5.0 opens the 1.5 minor line: the fullscreen Agent workspace remains the primary user surface, Agent-local behavior, isolated Agent Knowledge, connected-host operator integration, explicit side-effect boundaries, and release hardening from 1.3.x and 1.4.x all stay in force. This release replaces the split-pane panel system with the Activity sidebar, rebuilds first-run onboarding around readiness, and adds local calendar, direct email, hardware-aware model recommendations, and skill import/export.
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# GoodVibes Agent
|
|
2
2
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
|
-
[](#install)
|
|
5
5
|
|
|
6
6
|
GoodVibes Agent is the installable autonomous operator assistant for GoodVibes. It keeps the existing terminal renderer and workspace bones, but the product goal is different from a vibecoding harness: the user should experience one assistant that can chat, plan, remember, research, schedule, send, generate, run visible agents, and operate the GoodVibes daemon contract with clear confirmation gates.
|
|
7
7
|
|
|
@@ -69,7 +69,52 @@ Press `/` inside the workspace to search actions by name, category, command, or
|
|
|
69
69
|
|
|
70
70
|
The main Agent model can inspect and operate the Agent-controlled harness through Agent-owned tools. The important first-run entrypoint is `setup`; the detailed catalog entrypoint is `agent_harness`.
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
### Route planning
|
|
73
|
+
|
|
74
|
+
`route action:"plan" query:"..."` is the first stop when a plain user task could map to several GoodVibes surfaces. It returns the preferred visible route, alternatives, missing fields, confirmation boundary, workspace matches, and harness mode matches without running any tools.
|
|
75
|
+
|
|
76
|
+
The planner maps task wording to a preferred route:
|
|
77
|
+
|
|
78
|
+
| When the task sounds like… | Preferred route |
|
|
79
|
+
| --- | --- |
|
|
80
|
+
| Host/daemon health or doctor | `host action:"status"` |
|
|
81
|
+
| Normal settings/configuration | `settings action:"list"` |
|
|
82
|
+
| Model provider, local cookbook, smoke, or route-fit | `models action:"provider\|local\|smoke\|route"` |
|
|
83
|
+
| Personal Ops briefing, queue, fresh-read, or connector | `personal_ops action:"briefing\|queue\|intake\|lane"` |
|
|
84
|
+
| Direct reminders or schedule lifecycle | `schedule action:"list"` + confirmed schedule actions |
|
|
85
|
+
| Command-shaped background work | `execution action:"processes"` + first-class `terminal`/`process` UX |
|
|
86
|
+
| Interactive PTY/stdin/sudo | `execution action:"process_capabilities"` before any start or credential effect |
|
|
87
|
+
| External memory provider, backend, sync, import, or export | `memory action:"provider"` or the provider contract checklist |
|
|
88
|
+
| Browser-backed research runner | `research action:"runner"` |
|
|
89
|
+
| Visual research report rendering | `research action:"plan"` + report artifacts |
|
|
90
|
+
| Voice workflow or TTS provider | `device action:"voice\|provider"` |
|
|
91
|
+
| Browser cockpit/PWA | `computer action:"browser"` before any visible open handoff |
|
|
92
|
+
| Channel setup, triage, delivery receipt, or send | `channels action:"setup\|triage\|deliveries\|channel"` before confirmed external delivery |
|
|
93
|
+
| Security permission, status, finding, or blocked action | `security action:"status\|finding\|explain"` before policy changes or risky work |
|
|
94
|
+
| Support bundle | `support action:"status\|bundle"` before bundle export/import/share effects |
|
|
95
|
+
| Saved session, bookmark, or continuity | `sessions action:"list\|get"` before session lifecycle effects |
|
|
96
|
+
| Release readiness, evidence, or audit | `audit action:"readiness\|evidence\|item\|artifact"` |
|
|
97
|
+
| File undo/redo/recovery | `execution action:"recovery"` |
|
|
98
|
+
| Media generation | provider readiness + confirmed `agent_media_generate` artifacts |
|
|
99
|
+
| Screenshot, browser navigation/control, screen observation, or desktop control | `computer action:"plan"` before any live UI tool is considered |
|
|
100
|
+
|
|
101
|
+
`setup action:"repair"` is the first stop for setup or host fix requests. It chooses the safest next route — token repair, connected-host status, services.status receipt, user-run bootstrap, or no action — without executing it.
|
|
102
|
+
|
|
103
|
+
### Inspecting the harness
|
|
104
|
+
|
|
105
|
+
- `agent_harness mode:"summary"` — compact by default; returns counts, status, and a short mode guide.
|
|
106
|
+
- `mode:"modes"` — searches every harness mode by task, family, effect type, id, alias, or parameter name.
|
|
107
|
+
- `mode:"mode"` — inspects one mode contract.
|
|
108
|
+
- `mode:"route_decision"` — lower-level compatibility route for the same user-task planner.
|
|
109
|
+
- Plural catalog modes are compact by default: they return ids, labels, counts, safe state, effect class, and short route hints.
|
|
110
|
+
|
|
111
|
+
For everyday discovery and diagnostics, prefer the first-class tools over raw harness modes:
|
|
112
|
+
|
|
113
|
+
- Workspace, command, UI, shortcut, and keybinding discovery: `workspace action:"status|actions|action|run|surfaces|surface|open|commands|command|run_command|shortcuts|keybindings|keybinding"`.
|
|
114
|
+
- Normal configuration: `settings action:"list|get|set|reset|import"`.
|
|
115
|
+
- Connected-host/daemon diagnostics: `host action:"status|capabilities|capability|services|service|methods|method"`.
|
|
116
|
+
|
|
117
|
+
Connected-host posture/status/capability and operator/audit rows include compact `modelRoute` or `modelAccess` hints, so the model can pick the right first-class tool or confirmed harness route without expanding every row. Pass `includeParameters:true` or use a singular inspect mode when you need schemas, detailed route hints, full policy blocks, a redacted log tail, operator/audit artifact data, or editor field definitions.
|
|
73
118
|
|
|
74
119
|
High-value `agent_harness` mode groups:
|
|
75
120
|
|
package/dist/package/main.js
CHANGED
|
@@ -817034,7 +817034,7 @@ var createStyledCell = (char, overrides = {}) => ({
|
|
|
817034
817034
|
// src/version.ts
|
|
817035
817035
|
import { readFileSync } from "fs";
|
|
817036
817036
|
import { join } from "path";
|
|
817037
|
-
var _version = "1.5.
|
|
817037
|
+
var _version = "1.5.1";
|
|
817038
817038
|
try {
|
|
817039
817039
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf-8"));
|
|
817040
817040
|
_version = typeof pkg.version === "string" ? pkg.version : _version;
|
|
@@ -869763,13 +869763,13 @@ init_state3();
|
|
|
869763
869763
|
|
|
869764
869764
|
// src/input/commands/recall-shared.ts
|
|
869765
869765
|
var VALID_CLASSES = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
|
|
869766
|
-
var
|
|
869766
|
+
var VALID_SCOPES = ["session", "project", "team"];
|
|
869767
869767
|
var VALID_REVIEW_STATES = ["fresh", "reviewed", "stale", "contradicted"];
|
|
869768
869768
|
function isValidClass(s4) {
|
|
869769
869769
|
return VALID_CLASSES.includes(s4);
|
|
869770
869770
|
}
|
|
869771
869771
|
function isValidScope(s4) {
|
|
869772
|
-
return
|
|
869772
|
+
return VALID_SCOPES.includes(s4);
|
|
869773
869773
|
}
|
|
869774
869774
|
function isValidReviewState(s4) {
|
|
869775
869775
|
return VALID_REVIEW_STATES.includes(s4);
|
|
@@ -869812,7 +869812,7 @@ function handleRecallSearch(args2, context) {
|
|
|
869812
869812
|
if (isValidScope(scope))
|
|
869813
869813
|
filter.scope = scope;
|
|
869814
869814
|
else {
|
|
869815
|
-
context.print(`[memory] Unknown scope "${scope}". Valid values ${
|
|
869815
|
+
context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
|
|
869816
869816
|
return;
|
|
869817
869817
|
}
|
|
869818
869818
|
}
|
|
@@ -869987,7 +869987,7 @@ function handleRecallList(args2, context) {
|
|
|
869987
869987
|
if (scopeIdx !== -1 && args2[scopeIdx + 1]) {
|
|
869988
869988
|
const scope = args2[scopeIdx + 1];
|
|
869989
869989
|
if (!isValidScope(scope)) {
|
|
869990
|
-
context.print(`[memory] Unknown scope "${scope}". Valid values ${
|
|
869990
|
+
context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
|
|
869991
869991
|
return;
|
|
869992
869992
|
}
|
|
869993
869993
|
filter.scope = scope;
|
|
@@ -870037,7 +870037,7 @@ async function handleRecallAdd(args2, context) {
|
|
|
870037
870037
|
const tags = tagsRaw ? tagsRaw.split(",").map((token) => token.trim()).filter(Boolean) : [];
|
|
870038
870038
|
const scope = scopeRaw && isValidScope(scopeRaw) ? scopeRaw : "project";
|
|
870039
870039
|
if (scopeRaw && !isValidScope(scopeRaw)) {
|
|
870040
|
-
context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${
|
|
870040
|
+
context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES.join(", ")}.`);
|
|
870041
870041
|
return;
|
|
870042
870042
|
}
|
|
870043
870043
|
const provenance = [];
|
|
@@ -870171,7 +870171,7 @@ function handleRecallExport(args2, context) {
|
|
|
870171
870171
|
if (scopeIdx !== -1 && commandArgs[scopeIdx + 1]) {
|
|
870172
870172
|
const scope = commandArgs[scopeIdx + 1];
|
|
870173
870173
|
if (!isValidScope(scope)) {
|
|
870174
|
-
context.print(`[memory] Unknown scope "${scope}". Valid values ${
|
|
870174
|
+
context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
|
|
870175
870175
|
return;
|
|
870176
870176
|
}
|
|
870177
870177
|
filter.scope = scope;
|
|
@@ -870250,7 +870250,7 @@ function handleRecallHandoffExport(args2, context) {
|
|
|
870250
870250
|
const scopeIdx = commandArgs.indexOf("--scope");
|
|
870251
870251
|
const scopeRaw = scopeIdx !== -1 ? commandArgs[scopeIdx + 1] : "team";
|
|
870252
870252
|
if (!scopeRaw || !isValidScope(scopeRaw)) {
|
|
870253
|
-
context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${
|
|
870253
|
+
context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES.join(", ")}.`);
|
|
870254
870254
|
return;
|
|
870255
870255
|
}
|
|
870256
870256
|
const bundle = memory.exportBundle({ scope: scopeRaw });
|
|
@@ -870366,7 +870366,7 @@ function handleRecallPromote(args2, context) {
|
|
|
870366
870366
|
const id = parsed.rest[0];
|
|
870367
870367
|
const scope = parsed.rest[1];
|
|
870368
870368
|
if (!id || !scope || !isValidScope(scope)) {
|
|
870369
|
-
context.print(`[memory] Usage: /memory promote <id> <${
|
|
870369
|
+
context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES.join("|")}> --yes`);
|
|
870370
870370
|
return;
|
|
870371
870371
|
}
|
|
870372
870372
|
if (!parsed.yes) {
|
|
@@ -883582,7 +883582,7 @@ import { mkdirSync as mkdirSync75, readFileSync as readFileSync98, writeFileSync
|
|
|
883582
883582
|
import { dirname as dirname74, resolve as resolve42 } from "path";
|
|
883583
883583
|
init_state3();
|
|
883584
883584
|
var VALID_CLASSES2 = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
|
|
883585
|
-
var
|
|
883585
|
+
var VALID_SCOPES3 = ["session", "project", "team"];
|
|
883586
883586
|
var VALID_REVIEW_STATES3 = ["fresh", "reviewed", "stale", "contradicted"];
|
|
883587
883587
|
var VALID_PROVENANCE_KINDS = ["session", "turn", "task", "event", "file"];
|
|
883588
883588
|
var VALUE_OPTIONS = new Set([
|
|
@@ -883682,7 +883682,7 @@ function isMemoryClass2(value) {
|
|
|
883682
883682
|
return VALID_CLASSES2.includes(value);
|
|
883683
883683
|
}
|
|
883684
883684
|
function isMemoryScope2(value) {
|
|
883685
|
-
return
|
|
883685
|
+
return VALID_SCOPES3.includes(value);
|
|
883686
883686
|
}
|
|
883687
883687
|
function isReviewState(value) {
|
|
883688
883688
|
return VALID_REVIEW_STATES3.includes(value);
|
|
@@ -883697,7 +883697,7 @@ function requireClass(value) {
|
|
|
883697
883697
|
}
|
|
883698
883698
|
function requireScope(value) {
|
|
883699
883699
|
if (!value || !isMemoryScope2(value))
|
|
883700
|
-
throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${
|
|
883700
|
+
throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES3.join(", ")}`);
|
|
883701
883701
|
return value;
|
|
883702
883702
|
}
|
|
883703
883703
|
function optionalScope(value) {
|
|
@@ -944101,6 +944101,48 @@ function renderSettingsModal(modal, width, viewportHeight = 24) {
|
|
|
944101
944101
|
});
|
|
944102
944102
|
}
|
|
944103
944103
|
|
|
944104
|
+
// src/input/shell-passthrough.ts
|
|
944105
|
+
var MAX_SHELL_OUTPUT = 16000;
|
|
944106
|
+
var SHELL_USAGE_HINT = "[Shell] Usage: !<command> \u2014 runs a shell command; its output is shown and added as context for your next message.";
|
|
944107
|
+
|
|
944108
|
+
class ShellPassthrough {
|
|
944109
|
+
pending = [];
|
|
944110
|
+
async run(command8, cwd) {
|
|
944111
|
+
const proc = Bun.spawn(["bash", "-c", command8], { cwd, stdout: "pipe", stderr: "pipe" });
|
|
944112
|
+
const [out2, err2] = await Promise.all([
|
|
944113
|
+
new Response(proc.stdout).text(),
|
|
944114
|
+
new Response(proc.stderr).text()
|
|
944115
|
+
]);
|
|
944116
|
+
const exitCode2 = await proc.exited;
|
|
944117
|
+
const combined = [out2, err2].filter((s4) => s4.trim().length > 0).join(`
|
|
944118
|
+
`).trimEnd();
|
|
944119
|
+
const truncated = combined.length > MAX_SHELL_OUTPUT ? `${combined.slice(0, MAX_SHELL_OUTPUT)}
|
|
944120
|
+
\u2026 [truncated ${combined.length - MAX_SHELL_OUTPUT} chars]` : combined;
|
|
944121
|
+
const body2 = truncated.length > 0 ? truncated : "(no output)";
|
|
944122
|
+
const result2 = {
|
|
944123
|
+
display: `[Shell] ${body2}
|
|
944124
|
+
(exit ${exitCode2})`,
|
|
944125
|
+
context: `The user ran a shell command via the \`!\` prefix:
|
|
944126
|
+
$ ${command8}
|
|
944127
|
+
--- output (exit ${exitCode2}) ---
|
|
944128
|
+
${body2}`
|
|
944129
|
+
};
|
|
944130
|
+
this.pending.push(result2.context);
|
|
944131
|
+
return result2;
|
|
944132
|
+
}
|
|
944133
|
+
consumeContext(text) {
|
|
944134
|
+
if (this.pending.length === 0)
|
|
944135
|
+
return text;
|
|
944136
|
+
const context = this.pending.join(`
|
|
944137
|
+
|
|
944138
|
+
`);
|
|
944139
|
+
this.pending = [];
|
|
944140
|
+
return text ? `${context}
|
|
944141
|
+
|
|
944142
|
+
${text}` : context;
|
|
944143
|
+
}
|
|
944144
|
+
}
|
|
944145
|
+
|
|
944104
944146
|
// src/renderer/layout-engine.ts
|
|
944105
944147
|
function clamp7(value, min2, max2) {
|
|
944106
944148
|
return Math.max(min2, Math.min(max2, value));
|
|
@@ -948713,6 +948755,7 @@ async function main() {
|
|
|
948713
948755
|
let streamTokenSpeed = 0;
|
|
948714
948756
|
let scrollTop = 0;
|
|
948715
948757
|
let scrollLocked = true;
|
|
948758
|
+
const shellPassthrough = new ShellPassthrough;
|
|
948716
948759
|
const autonomy = createAutonomySurfacing({
|
|
948717
948760
|
shellPaths: ctx.services.shellPaths,
|
|
948718
948761
|
listAutomationJobs: () => ctx.services.automationManager.listJobs(),
|
|
@@ -948866,14 +948909,26 @@ async function main() {
|
|
|
948866
948909
|
systemMessageRouter.high(`[Memory] Pinned: "${memoryText}" (${memId})`);
|
|
948867
948910
|
processedText = memoryText;
|
|
948868
948911
|
}
|
|
948912
|
+
} else if (processedText.startsWith("!")) {
|
|
948913
|
+
const command8 = processedText.slice(1).trim();
|
|
948914
|
+
if (!command8) {
|
|
948915
|
+
systemMessageRouter.high(SHELL_USAGE_HINT);
|
|
948916
|
+
render();
|
|
948917
|
+
return;
|
|
948918
|
+
}
|
|
948919
|
+
systemMessageRouter.high(`[Shell] $ ${command8}`);
|
|
948920
|
+
render();
|
|
948921
|
+
shellPassthrough.run(command8, workingDir).then((result2) => systemMessageRouter.high(result2.display)).catch((shellErr) => systemMessageRouter.high(`[Shell] Failed to run: ${summarizeError(shellErr)}`)).finally(() => render());
|
|
948922
|
+
return;
|
|
948869
948923
|
}
|
|
948870
948924
|
if (processedText || content) {
|
|
948871
948925
|
(async () => {
|
|
948872
948926
|
const inputOptions = options.spokenOutput ? createSpokenTurnInputOptions() : undefined;
|
|
948927
|
+
const outgoing = shellPassthrough.consumeContext(processedText);
|
|
948873
948928
|
if (options.spokenOutput && processedText) {
|
|
948874
948929
|
spokenTurns.submitNextTurn(processedText);
|
|
948875
948930
|
}
|
|
948876
|
-
orchestrator.handleUserInput(
|
|
948931
|
+
orchestrator.handleUserInput(outgoing, content, inputOptions).catch((err2) => {
|
|
948877
948932
|
logger.debug("handleUserInput safety catch (already handled by runTurn)", { error: summarizeError(err2) });
|
|
948878
948933
|
});
|
|
948879
948934
|
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "GoodVibes personal operator assistant TUI with a proactive Agent product brain, isolated Agent Knowledge, local profiles, routines, skills, personas, and explicit build delegation.",
|
|
6
6
|
"type": "module",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-06-
|
|
2
|
+
"generatedAt": "2026-06-14T21:34:04.442Z",
|
|
3
3
|
"homeDir": "[goodvibes-home]",
|
|
4
4
|
"binaryPath": "[agent-binary]",
|
|
5
5
|
"connectedHostBaseUrl": "http://127.0.0.1:3421",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"id": "verification-ledger",
|
|
10
10
|
"title": "Verification inventory ledger",
|
|
11
11
|
"status": "pass",
|
|
12
|
-
"summary": "
|
|
13
|
-
"detail": "
|
|
12
|
+
"summary": "99.5% local verification signal across 806 inventory items.",
|
|
13
|
+
"detail": "83.9% local behavior verified; 96 item(s) require external outcomes."
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"id": "compiled-cli-present",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"title": "Agent CLI version command",
|
|
24
24
|
"status": "pass",
|
|
25
25
|
"summary": "Agent CLI version returned successfully.",
|
|
26
|
-
"detail": "goodvibes-agent 1.0
|
|
26
|
+
"detail": "goodvibes-agent 1.5.0"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"id": "cli-status-json",
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
"title": "Agent CLI compatibility JSON command",
|
|
38
38
|
"status": "pass",
|
|
39
39
|
"summary": "Agent CLI compatibility returned parseable JSON.",
|
|
40
|
-
"detail": "{\n \"ok\": true,\n \"packageVersion\": \"1.0
|
|
40
|
+
"detail": "{\n \"ok\": true,\n \"packageVersion\": \"1.5.0\",\n \"connectedHost\": {\n \"baseUrl\": \"http://127.0.0.1:3421\",\n \"status\": 200,\n \"reachable\": true,\n \"compatible\": true\n },\n \"auth\": {\n \"tokenPresent\": true,\n \"tokenPath\": \"env:GOODVIBES_CONNECTED_HOST_TOKEN\"\n },\n \"agentKnowledge\": {\n \"route\": \"/api/goodvibes-agent/knowledge/status\",\n \"ready\": true,\n \"kind\": \"ok\"\n }\n}"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"id": "cli-agent-knowledge-status",
|
|
44
44
|
"title": "Agent Knowledge CLI status command",
|
|
45
45
|
"status": "pass",
|
|
46
46
|
"summary": "Agent Knowledge status returned parseable JSON.",
|
|
47
|
-
"detail": "{\n \"ok\": true,\n \"kind\": \"agentKnowledge.status\",\n \"route\": \"/api/goodvibes-agent/knowledge/status\",\n \"data\": {\n \"ready\": true,\n \"storagePath\": \"[goodvibes-home]/tui/knowledge-agent.sqlite\",\n \"sourceCount\": 0,\n \"nodeCount\":
|
|
47
|
+
"detail": "{\n \"ok\": true,\n \"kind\": \"agentKnowledge.status\",\n \"route\": \"/api/goodvibes-agent/knowledge/status\",\n \"data\": {\n \"ready\": true,\n \"storagePath\": \"[goodvibes-home]/tui/knowledge-agent.sqlite\",\n \"sourceCount\": 0,\n \"nodeCount\": 0,\n \"edgeCount\": 0,\n \"issueCount\": 0,\n \"extractionCount\": 0,\n \"jobRunCount\": 0,\n \"refinementTaskCount\": 0,\n \"usageCount\": 0,\n \"candidateCount\": 0,\n \"reportCount\": 0,\n \"scheduleCount\": 3,\n \"note\": \"Structured knowledge uses SQL-backed sources, nodes, edges, issues, extractions, and job runs. Markdown is an optional projection, not the source of truth.\"\n }\n}"
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"id": "cli-providers",
|
|
@@ -65,28 +65,28 @@
|
|
|
65
65
|
"title": "Authenticated connected-host /status",
|
|
66
66
|
"status": "pass",
|
|
67
67
|
"summary": "/status returned 200 with parseable JSON.",
|
|
68
|
-
"detail": "{\"status\":\"running\"}"
|
|
68
|
+
"detail": "{\"status\":\"running\",\"version\":\"0.33.36\"}"
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
"id": "connected-host-health",
|
|
72
72
|
"title": "Authenticated connected-host /api/health",
|
|
73
73
|
"status": "pass",
|
|
74
74
|
"summary": "Health overall=healthy.",
|
|
75
|
-
"detail": "{\"overall\":\"healthy\",\"degradedDomains\":[],\"providerProblems\":[],\"mcpProblems\":{\"degraded\":[],\"quarantined\":[]},\"integrationProblems\":[],\"network\":{\"controlPlane\":{\"surface\":\"controlPlane\",\"host\":\"
|
|
75
|
+
"detail": "{\"overall\":\"healthy\",\"degradedDomains\":[],\"providerProblems\":[],\"mcpProblems\":{\"degraded\":[],\"quarantined\":[]},\"integrationProblems\":[],\"network\":{\"controlPlane\":{\"surface\":\"controlPlane\",\"host\":\"127.0.0.1\",\"port\":3421,\"mode\":\"off\",\"scheme\":\"http\",\"trustProxy\":false,\"usingDefaultPaths\":false,\"ready\":true,\"errors\":[]},\"httpListener\":{\"surface\":\"httpListener\",\"host\":\"127.0.0.1\",\"port\":3422,\"mode\":\"off\",\"scheme\":\"http\",\"trustProxy\":false,\"usingDefaultPaths\":false,\"ready\":true,\"errors\":[]},\"outbound\":{\"mode\":\"bundled\",\"allowInsecureLocalhost\":false,\"customCaEntryCount\":0,\"effectiveCaStrategy\":\"bun-default\",\"errors\":[]}}}"
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
"id": "openai-compatible-models",
|
|
79
79
|
"title": "OpenAI-compatible /v1/models route",
|
|
80
80
|
"status": "pass",
|
|
81
|
-
"summary": "/v1/models returned
|
|
82
|
-
"detail": "/v1/models returned
|
|
81
|
+
"summary": "/v1/models returned 175 model(s).",
|
|
82
|
+
"detail": "/v1/models returned 175 model(s); model identifiers omitted from release artifact."
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
85
|
"id": "agent-knowledge-status",
|
|
86
86
|
"title": "Agent Knowledge isolated /status",
|
|
87
87
|
"status": "pass",
|
|
88
88
|
"summary": "Agent Knowledge status route returned parseable isolated JSON.",
|
|
89
|
-
"detail": "{\"ready\":true,\"storagePath\":\"[goodvibes-home]/tui/knowledge-agent.sqlite\",\"sourceCount\":0,\"nodeCount\":
|
|
89
|
+
"detail": "{\"ready\":true,\"storagePath\":\"[goodvibes-home]/tui/knowledge-agent.sqlite\",\"sourceCount\":0,\"nodeCount\":0,\"edgeCount\":0,\"issueCount\":0,\"extractionCount\":0,\"jobRunCount\":0,\"refinementTaskCount\":0,\"usageCount\":0,\"candidateCount\":0,\"reportCount\":0,\"scheduleCount\":3,\"note\":\"Structured knowledge uses SQL-backed sources, nodes, edges, issues, extractions, and job runs. Markdown is an optional projection, not the source of truth.\"}"
|
|
90
90
|
},
|
|
91
91
|
{
|
|
92
92
|
"id": "agent-knowledge-ask-isolated",
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"title": "Agent Knowledge isolated nodes list",
|
|
115
115
|
"status": "pass",
|
|
116
116
|
"summary": "Agent Knowledge isolated nodes list stayed on the isolated Agent route.",
|
|
117
|
-
"detail": "{\"nodes\":[
|
|
117
|
+
"detail": "{\"nodes\":[]}"
|
|
118
118
|
},
|
|
119
119
|
{
|
|
120
120
|
"id": "agent-knowledge-issues-isolated",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"title": "Agent Knowledge isolated map",
|
|
129
129
|
"status": "pass",
|
|
130
130
|
"summary": "Agent Knowledge isolated map stayed on the isolated Agent route.",
|
|
131
|
-
"detail": "{\"ok\":true,\"title\":\"Knowledge Map\",\"generatedAt\":
|
|
131
|
+
"detail": "{\"ok\":true,\"title\":\"Knowledge Map\",\"generatedAt\":1781472844439,\"width\":1280,\"height\":920,\"nodeCount\":0,\"edgeCount\":0,\"totalNodeCount\":0,\"totalEdgeCount\":0,\"facets\":{\"recordKinds\":[],\"nodeKinds\":[],\"sourceTypes\":[],\"sourceStatuses\":[],\"nodeStatuses\":[],\"issueCodes\":[],\"issueStatuses\":[],\"issueSeverities\":[],\"edgeRelations\":[],\"tags\":[]},\"nodes\":[],\"edges\":[],\"svg\":\"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" width=\\\"1280\\\" height=\\\"920\\\" viewBox=\\\"0 0 1280 920\\\" role=\\\"img\\\" aria-label=\\\"Knowledge Map\\\">\\n<defs>\\n <radialGradient id=\\\"knowledgeMapBg\\\" cx=\\\"50%\\\" cy=\\\"46%\\\" r=\\\"70%\\\">\\n <stop offset=\\\"0%\\\" stop-color=\\\"#f7f4ec\\\" />\\n <stop offset=\\\"60%\\\" stop-color=\\\"#e9eef0\\\" />\\n <stop offset=\\\"100%\\\" stop-color=\\\"#dde6df\\\" />\\n </radialGradient>\\n <filter id=\\\"softShadow\\\" x=\\\"-20%\\\" y=\\\"-20%\\\" width=\\\"140%\\\" height=\\\"140%\\\">\\n <feDropShadow dx=\\\"0\\\" dy=\\\"6\\... [truncated]"
|
|
132
132
|
},
|
|
133
133
|
{
|
|
134
134
|
"id": "agent-knowledge-connectors-isolated",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GoodVibes Agent Live Verification
|
|
2
2
|
|
|
3
|
-
Generated: 2026-06-
|
|
3
|
+
Generated: 2026-06-14T21:34:04.442Z
|
|
4
4
|
Home: `[goodvibes-home]`
|
|
5
5
|
Binary: `[agent-binary]`
|
|
6
6
|
Connected host: `http://127.0.0.1:3421`
|
|
@@ -14,7 +14,7 @@ Connected host: `http://127.0.0.1:3421`
|
|
|
14
14
|
|
|
15
15
|
| Check | Status | Summary |
|
|
16
16
|
|---|---|---|
|
|
17
|
-
| Verification inventory ledger | pass |
|
|
17
|
+
| Verification inventory ledger | pass | 99.5% local verification signal across 806 inventory items. |
|
|
18
18
|
| Compiled GoodVibes Agent CLI binary | pass | Found [agent-binary]. |
|
|
19
19
|
| Agent CLI version command | pass | Agent CLI version returned successfully. |
|
|
20
20
|
| Agent CLI status JSON command | pass | Agent CLI status returned parseable JSON. |
|
|
@@ -24,7 +24,7 @@ Connected host: `http://127.0.0.1:3421`
|
|
|
24
24
|
| CLI doctor command | pass | Doctor completed without findings. |
|
|
25
25
|
| Authenticated connected-host /status | pass | /status returned 200 with parseable JSON. |
|
|
26
26
|
| Authenticated connected-host /api/health | pass | Health overall=healthy. |
|
|
27
|
-
| OpenAI-compatible /v1/models route | pass | /v1/models returned
|
|
27
|
+
| OpenAI-compatible /v1/models route | pass | /v1/models returned 175 model(s). |
|
|
28
28
|
| Agent Knowledge isolated /status | pass | Agent Knowledge status route returned parseable isolated JSON. |
|
|
29
29
|
| Agent Knowledge isolated ask | pass | Agent Knowledge ask stayed on the isolated Agent route. |
|
|
30
30
|
| Agent Knowledge isolated search | pass | Agent Knowledge search stayed on the isolated Agent route. |
|
|
@@ -39,13 +39,13 @@ Connected host: `http://127.0.0.1:3421`
|
|
|
39
39
|
### Verification inventory ledger
|
|
40
40
|
|
|
41
41
|
```text
|
|
42
|
-
|
|
42
|
+
83.9% local behavior verified; 96 item(s) require external outcomes.
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### Agent CLI version command
|
|
46
46
|
|
|
47
47
|
```text
|
|
48
|
-
goodvibes-agent 1.0
|
|
48
|
+
goodvibes-agent 1.5.0
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
### Agent CLI status JSON command
|
|
@@ -59,7 +59,7 @@ Status JSON command completed; provider/model identifiers omitted from release a
|
|
|
59
59
|
```text
|
|
60
60
|
{
|
|
61
61
|
"ok": true,
|
|
62
|
-
"packageVersion": "1.0
|
|
62
|
+
"packageVersion": "1.5.0",
|
|
63
63
|
"connectedHost": {
|
|
64
64
|
"baseUrl": "http://127.0.0.1:3421",
|
|
65
65
|
"status": 200,
|
|
@@ -89,15 +89,15 @@ Status JSON command completed; provider/model identifiers omitted from release a
|
|
|
89
89
|
"ready": true,
|
|
90
90
|
"storagePath": "[goodvibes-home]/tui/knowledge-agent.sqlite",
|
|
91
91
|
"sourceCount": 0,
|
|
92
|
-
"nodeCount":
|
|
92
|
+
"nodeCount": 0,
|
|
93
93
|
"edgeCount": 0,
|
|
94
94
|
"issueCount": 0,
|
|
95
95
|
"extractionCount": 0,
|
|
96
|
-
"jobRunCount":
|
|
96
|
+
"jobRunCount": 0,
|
|
97
97
|
"refinementTaskCount": 0,
|
|
98
98
|
"usageCount": 0,
|
|
99
99
|
"candidateCount": 0,
|
|
100
|
-
"reportCount":
|
|
100
|
+
"reportCount": 0,
|
|
101
101
|
"scheduleCount": 3,
|
|
102
102
|
"note": "Structured knowledge uses SQL-backed sources, nodes, edges, issues, extractions, and job runs. Markdown is an optional projection, not the source of truth."
|
|
103
103
|
}
|
|
@@ -119,25 +119,25 @@ Doctor command completed without findings; provider/model identifiers and creden
|
|
|
119
119
|
### Authenticated connected-host /status
|
|
120
120
|
|
|
121
121
|
```text
|
|
122
|
-
{"status":"running"}
|
|
122
|
+
{"status":"running","version":"0.33.36"}
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
### Authenticated connected-host /api/health
|
|
126
126
|
|
|
127
127
|
```text
|
|
128
|
-
{"overall":"healthy","degradedDomains":[],"providerProblems":[],"mcpProblems":{"degraded":[],"quarantined":[]},"integrationProblems":[],"network":{"controlPlane":{"surface":"controlPlane","host":"
|
|
128
|
+
{"overall":"healthy","degradedDomains":[],"providerProblems":[],"mcpProblems":{"degraded":[],"quarantined":[]},"integrationProblems":[],"network":{"controlPlane":{"surface":"controlPlane","host":"127.0.0.1","port":3421,"mode":"off","scheme":"http","trustProxy":false,"usingDefaultPaths":false,"ready":true,"errors":[]},"httpListener":{"surface":"httpListener","host":"127.0.0.1","port":3422,"mode":"off","scheme":"http","trustProxy":false,"usingDefaultPaths":false,"ready":true,"errors":[]},"outbound":{"mode":"bundled","allowInsecureLocalhost":false,"customCaEntryCount":0,"effectiveCaStrategy":"bun-default","errors":[]}}}
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
### OpenAI-compatible /v1/models route
|
|
132
132
|
|
|
133
133
|
```text
|
|
134
|
-
/v1/models returned
|
|
134
|
+
/v1/models returned 175 model(s); model identifiers omitted from release artifact.
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
### Agent Knowledge isolated /status
|
|
138
138
|
|
|
139
139
|
```text
|
|
140
|
-
{"ready":true,"storagePath":"[goodvibes-home]/tui/knowledge-agent.sqlite","sourceCount":0,"nodeCount":
|
|
140
|
+
{"ready":true,"storagePath":"[goodvibes-home]/tui/knowledge-agent.sqlite","sourceCount":0,"nodeCount":0,"edgeCount":0,"issueCount":0,"extractionCount":0,"jobRunCount":0,"refinementTaskCount":0,"usageCount":0,"candidateCount":0,"reportCount":0,"scheduleCount":3,"note":"Structured knowledge uses SQL-backed sources, nodes, edges, issues, extractions, and job runs. Markdown is an optional projection, not the source of truth."}
|
|
141
141
|
```
|
|
142
142
|
|
|
143
143
|
### Agent Knowledge isolated ask
|
|
@@ -161,7 +161,7 @@ Doctor command completed without findings; provider/model identifiers and creden
|
|
|
161
161
|
### Agent Knowledge isolated nodes list
|
|
162
162
|
|
|
163
163
|
```text
|
|
164
|
-
{"nodes":[
|
|
164
|
+
{"nodes":[]}
|
|
165
165
|
```
|
|
166
166
|
|
|
167
167
|
### Agent Knowledge isolated issues list
|
|
@@ -173,7 +173,7 @@ Doctor command completed without findings; provider/model identifiers and creden
|
|
|
173
173
|
### Agent Knowledge isolated map
|
|
174
174
|
|
|
175
175
|
```text
|
|
176
|
-
{"ok":true,"title":"Knowledge Map","generatedAt":
|
|
176
|
+
{"ok":true,"title":"Knowledge Map","generatedAt":1781472844439,"width":1280,"height":920,"nodeCount":0,"edgeCount":0,"totalNodeCount":0,"totalEdgeCount":0,"facets":{"recordKinds":[],"nodeKinds":[],"sourceTypes":[],"sourceStatuses":[],"nodeStatuses":[],"issueCodes":[],"issueStatuses":[],"issueSeverities":[],"edgeRelations":[],"tags":[]},"nodes":[],"edges":[],"svg":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1280\" height=\"920\" viewBox=\"0 0 1280 920\" role=\"img\" aria-label=\"Knowledge Map\">\n<defs>\n <radialGradient id=\"knowledgeMapBg\" cx=\"50%\" cy=\"46%\" r=\"70%\">\n <stop offset=\"0%\" stop-color=\"#f7f4ec\" />\n <stop offset=\"60%\" stop-color=\"#e9eef0\" />\n <stop offset=\"100%\" stop-color=\"#dde6df\" />\n </radialGradient>\n <filter id=\"softShadow\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\">\n <feDropShadow dx=\"0\" dy=\"6\... [truncated]
|
|
177
177
|
```
|
|
178
178
|
|
|
179
179
|
### Agent Knowledge isolated connectors list
|
package/release/release-notes.md
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
- v1.5.
|
|
2
|
-
-
|
|
3
|
-
-
|
|
4
|
-
-
|
|
5
|
-
- Rebuilt first-run onboarding around a readiness model: setup steps sequence themselves by what is actually configured, the flow can be resumed midway, and a completion recap shows what was set up. The first screen leads with a working path, the first-run model picker opens with a hardware-fit recommendation, and a plain-language hint appears in conversation while setup is incomplete.
|
|
6
|
-
- Competitive parity wave: local calendar support, direct email send and read over SMTP and IMAP with TLS or STARTTLS, hardware-aware model recommendations, and automatic skill drafts.
|
|
7
|
-
- Skills now import and export in the open skill standard. Exports are lossless, and skills discovered from imports stay disabled until explicitly enabled.
|
|
8
|
-
- Hardened the email and calendar surfaces: SMTP and IMAP commands validate addresses and reject control characters, STARTTLS upgrades verify no data arrives before negotiation completes, and calendar parsing is stricter about malformed input.
|
|
9
|
-
- Reliability fixes across the TUI: closed a text-wrap hang, made wide-character rendering consistent, fixed webhook notifier reuse, routed the benchmark editor to its real action, and made command failures surface user-visible errors everywhere.
|
|
10
|
-
- Release and verification hygiene: the operator token is redacted from release artifacts, the coverage ledger reports honest numbers, release evidence is checked for existence, and operator-facing copy passes a plain-language gate.
|
|
1
|
+
- v1.5.1 is a patch on the 1.5 line. The fullscreen Agent workspace, Agent-local behavior, isolated Agent Knowledge, connected-host operator integration, and explicit side-effect boundaries all stay in force; this release restores the inline shell escape and refreshes release verification.
|
|
2
|
+
- Restored the inline shell escape in the prompt: type an exclamation mark followed by a command (for example, exclamation-mark git status) to run it in your working directory without leaving Agent. The command output appears inline, and the result is carried into your next message as context so you can run something and immediately ask about it. The composer already showed this as shell mode, but the command never actually ran since the workspace fork; it executes again now.
|
|
3
|
+
- The exclamation-hash memory pin is unchanged and still takes precedence, so pinning a note keeps working exactly as before.
|
|
4
|
+
- Release hygiene: regenerated the strict live-verification attestation against the running connected host so the published package carries current evidence.
|
|
11
5
|
- Test suite: 7931 pass / 0 fail / 2 skip across 554 files.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ShellPassthrough — runs user-typed `!<command>` shell escapes.
|
|
3
|
+
*
|
|
4
|
+
* The composer routes a leading `!` to "shell" mode; this runs the command
|
|
5
|
+
* directly (a user-initiated terminal escape, not an agent tool call), shows
|
|
6
|
+
* its output, and buffers a context block that is prepended to the user's next
|
|
7
|
+
* real message — making the result visible to the model on the next turn
|
|
8
|
+
* without triggering a turn of its own.
|
|
9
|
+
*
|
|
10
|
+
* A buffer is used rather than appending a conversation message because the
|
|
11
|
+
* SDK drops `system` messages from the LLM view and does not merge consecutive
|
|
12
|
+
* `user` messages (which would trip a consecutive-user-message API error).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const MAX_SHELL_OUTPUT = 16_000;
|
|
16
|
+
|
|
17
|
+
export const SHELL_USAGE_HINT =
|
|
18
|
+
'[Shell] Usage: !<command> — runs a shell command; its output is shown and added as context for your next message.';
|
|
19
|
+
|
|
20
|
+
export interface ShellRunResult {
|
|
21
|
+
/** Formatted output for the conversation/activity feed. */
|
|
22
|
+
readonly display: string;
|
|
23
|
+
/** Context block buffered for the user's next turn. */
|
|
24
|
+
readonly context: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class ShellPassthrough {
|
|
28
|
+
private pending: string[] = [];
|
|
29
|
+
|
|
30
|
+
/** Run `command` in `cwd`, returning display + model-context renderings. */
|
|
31
|
+
async run(command: string, cwd: string): Promise<ShellRunResult> {
|
|
32
|
+
const proc = Bun.spawn(['bash', '-c', command], { cwd, stdout: 'pipe', stderr: 'pipe' });
|
|
33
|
+
const [out, err] = await Promise.all([
|
|
34
|
+
new Response(proc.stdout).text(),
|
|
35
|
+
new Response(proc.stderr).text(),
|
|
36
|
+
]);
|
|
37
|
+
const exitCode = await proc.exited;
|
|
38
|
+
const combined = [out, err].filter((s) => s.trim().length > 0).join('\n').trimEnd();
|
|
39
|
+
const truncated = combined.length > MAX_SHELL_OUTPUT
|
|
40
|
+
? `${combined.slice(0, MAX_SHELL_OUTPUT)}\n… [truncated ${combined.length - MAX_SHELL_OUTPUT} chars]`
|
|
41
|
+
: combined;
|
|
42
|
+
const body = truncated.length > 0 ? truncated : '(no output)';
|
|
43
|
+
const result: ShellRunResult = {
|
|
44
|
+
display: `[Shell] ${body}\n(exit ${exitCode})`,
|
|
45
|
+
context: `The user ran a shell command via the \`!\` prefix:\n$ ${command}\n--- output (exit ${exitCode}) ---\n${body}`,
|
|
46
|
+
};
|
|
47
|
+
this.pending.push(result.context);
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Prepend (and clear) any buffered shell context onto an outgoing message. */
|
|
52
|
+
consumeContext(text: string): string {
|
|
53
|
+
if (this.pending.length === 0) return text;
|
|
54
|
+
const context = this.pending.join('\n\n');
|
|
55
|
+
this.pending = [];
|
|
56
|
+
return text ? `${context}\n\n${text}` : context;
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/main.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { renderSettingsModal } from './renderer/settings-modal.ts';
|
|
|
20
20
|
import { registerBuiltinCommands } from './input/commands.ts';
|
|
21
21
|
import { ScheduleManager } from '@pellux/goodvibes-sdk/platform/tools';
|
|
22
22
|
import { InputHistory } from './input/input-history.ts';
|
|
23
|
+
import { ShellPassthrough, SHELL_USAGE_HINT } from './input/shell-passthrough.ts';
|
|
23
24
|
import { getTierPromptSupplement, getTierForContextWindow } from '@pellux/goodvibes-sdk/platform/providers';
|
|
24
25
|
import { createShellLayout } from './renderer/layout-engine.ts';
|
|
25
26
|
import { buildShellFooter, estimateShellFooterHeight } from './renderer/shell-surface.ts';
|
|
@@ -156,6 +157,8 @@ async function main() {
|
|
|
156
157
|
let scrollTop = 0;
|
|
157
158
|
let scrollLocked = true;
|
|
158
159
|
|
|
160
|
+
const shellPassthrough = new ShellPassthrough();
|
|
161
|
+
|
|
159
162
|
// Ambient autonomy surfacing: away digest at launch + sidebar Coming up.
|
|
160
163
|
const autonomy = createAutonomySurfacing({
|
|
161
164
|
shellPaths: ctx.services.shellPaths,
|
|
@@ -315,14 +318,28 @@ async function main() {
|
|
|
315
318
|
systemMessageRouter.high(`[Memory] Pinned: "${memoryText}" (${memId})`);
|
|
316
319
|
processedText = memoryText;
|
|
317
320
|
}
|
|
321
|
+
} else if (processedText.startsWith('!')) {
|
|
322
|
+
const command = processedText.slice(1).trim();
|
|
323
|
+
if (!command) {
|
|
324
|
+
systemMessageRouter.high(SHELL_USAGE_HINT);
|
|
325
|
+
render();
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
systemMessageRouter.high(`[Shell] $ ${command}`); render();
|
|
329
|
+
void shellPassthrough.run(command, workingDir)
|
|
330
|
+
.then((result) => systemMessageRouter.high(result.display))
|
|
331
|
+
.catch((shellErr: unknown) => systemMessageRouter.high(`[Shell] Failed to run: ${summarizeError(shellErr)}`))
|
|
332
|
+
.finally(() => render());
|
|
333
|
+
return;
|
|
318
334
|
}
|
|
319
335
|
if (processedText || content) {
|
|
320
336
|
void (async () => {
|
|
321
337
|
const inputOptions = options.spokenOutput ? createSpokenTurnInputOptions() : undefined;
|
|
338
|
+
const outgoing = shellPassthrough.consumeContext(processedText);
|
|
322
339
|
if (options.spokenOutput && processedText) {
|
|
323
340
|
spokenTurns.submitNextTurn(processedText);
|
|
324
341
|
}
|
|
325
|
-
orchestrator.handleUserInput(
|
|
342
|
+
orchestrator.handleUserInput(outgoing, content, inputOptions).catch((err: unknown) => {
|
|
326
343
|
logger.debug('handleUserInput safety catch (already handled by runTurn)', { error: summarizeError(err) });
|
|
327
344
|
});
|
|
328
345
|
})();
|
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.5.
|
|
9
|
+
let _version = '1.5.1';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
|
|
12
12
|
readonly version?: unknown;
|