@pellux/goodvibes-daemon 1.28.11 → 1.28.12
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 +29 -1
- package/README.md +1 -1
- package/package.json +3 -3
- package/src/runtime/hosted-session-composition.ts +61 -8
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,35 @@ All notable changes to the GoodVibes daemon.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## [
|
|
7
|
+
## [1.28.12] - 2026-08-05
|
|
8
|
+
|
|
9
|
+
### Changes
|
|
10
|
+
|
|
11
|
+
- **Fixed: a hosted conversational turn no longer gets the host.** The daemon
|
|
12
|
+
composes hosted sessions through the same `createClientRuntimeServices` a
|
|
13
|
+
terminal runs, so a hosted command already ran inside the same bubblewrap
|
|
14
|
+
boundary — network, PID, UTS and IPC namespaced, system read-only, /tmp and
|
|
15
|
+
$HOME masked, `sandbox.egressAllowlist` the one way network comes back. What
|
|
16
|
+
differed was the fallback: with no boundary available the command ran
|
|
17
|
+
directly on the host and only said so afterwards, and a conversational turn
|
|
18
|
+
used that to read the whole process table and drive the owner's terminal.
|
|
19
|
+
The daemon now STATES the posture. Every session it hosts is
|
|
20
|
+
`conversational`, which makes the boundary REQUIRED: a command that cannot be
|
|
21
|
+
contained is refused, naming why, and `background: true` is not a spelling
|
|
22
|
+
that gets around it. A hosted workstream that genuinely needs the machine is
|
|
23
|
+
a per-spawn grant written into this daemon's own composition — nothing on the
|
|
24
|
+
wire and nothing in a tool argument can reach it.
|
|
25
|
+
- **Fixed: the owner's terminal is untouchable.** A command that drives an
|
|
26
|
+
existing tmux session, window or pane this platform did not create —
|
|
27
|
+
send-keys, kill, resize, attach, respawn, rename — is refused by the exec
|
|
28
|
+
guard for a hosted turn, with a refusal that names the rule. Creating and
|
|
29
|
+
driving the platform's own sessions is unchanged, and so is reading tmux
|
|
30
|
+
state (`list-sessions`, `list-panes`, `capture-pane`), which the fleet view
|
|
31
|
+
already does. The frozen catastrophic block is untouched.
|
|
32
|
+
- Changed: this daemon's hosted operator prompt carries the platform's
|
|
33
|
+
conversational diagnosis contract — report the state and propose, never
|
|
34
|
+
restart the owner's applications or type into his terminal to "fix" things,
|
|
35
|
+
and a "fixed" claim needs the live evidence it rests on.
|
|
8
36
|
|
|
9
37
|
## [1.28.11] - 2026-08-05
|
|
10
38
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/mgd34msu/goodvibes-daemon/actions/workflows/ci.yml)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://github.com/mgd34msu/goodvibes-daemon)
|
|
6
6
|
|
|
7
7
|
The GoodVibes daemon: one long-running process per machine that holds the control plane every
|
|
8
8
|
GoodVibes client talks to. It answers the operator verb families over HTTP, reads and replies on
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-daemon",
|
|
3
|
-
"version": "1.28.
|
|
3
|
+
"version": "1.28.12",
|
|
4
4
|
"description": "The GoodVibes daemon \u2014 the one long-running host for the control plane, channels, cluster membership, scheduled work, knowledge and memory stores, and the verb families every GoodVibes client calls.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/daemon/cli.ts",
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"@anthropic-ai/bedrock-sdk": "^0.28.1",
|
|
66
66
|
"@anthropic-ai/sdk": "^0.82.0",
|
|
67
67
|
"@ast-grep/napi": "^0.42.0",
|
|
68
|
-
"@pellux/goodvibes-sdk": "2.0.
|
|
69
|
-
"@pellux/goodvibes-terminal-shell": "2.0.
|
|
68
|
+
"@pellux/goodvibes-sdk": "2.0.10",
|
|
69
|
+
"@pellux/goodvibes-terminal-shell": "2.0.10",
|
|
70
70
|
"bash-language-server": "^5.6.0",
|
|
71
71
|
"fuse.js": "^7.1.0",
|
|
72
72
|
"graphql": "^16.13.2",
|
|
@@ -23,13 +23,46 @@
|
|
|
23
23
|
* Everything else in a floor comes from `createClientRuntimeServices` — the
|
|
24
24
|
* same composition a terminal runs — so a hosted turn's tools, hooks, plugins
|
|
25
25
|
* and model stack are the ones the platform already has, not a second set.
|
|
26
|
+
*
|
|
27
|
+
* ── The exec posture a hosted turn runs under ──────────────────────────────
|
|
28
|
+
*
|
|
29
|
+
* "The same composition a terminal runs" is what BUILDS the exec tool, and it
|
|
30
|
+
* builds it the same way here: the `sandbox.*` config and the `exec-sandbox`
|
|
31
|
+
* gate this daemon already reads produce the same bubblewrap boundary a local
|
|
32
|
+
* exec gets — network, PID, UTS and IPC namespaced, the system read-only, /tmp
|
|
33
|
+
* and $HOME masked, the workspace writable, and `sandbox.egressAllowlist` the
|
|
34
|
+
* one way network comes back — with the self-labelling note on every result.
|
|
35
|
+
*
|
|
36
|
+
* What was NOT the same was the fallback. When no boundary could be applied,
|
|
37
|
+
* the exec tool ran the command on the host and said so, which is right for a
|
|
38
|
+
* terminal (a person asked, a person is reading) and wrong for a turn nobody is
|
|
39
|
+
* watching. A hosted conversational turn reached the whole host that way: the
|
|
40
|
+
* full process table, the owner's /proc, and his tmux session — where it typed.
|
|
41
|
+
*
|
|
42
|
+
* So this daemon states the posture rather than inheriting a default:
|
|
43
|
+
*
|
|
44
|
+
* - CONVERSATIONAL is what every session created over `sessions.hosted.*`
|
|
45
|
+
* gets, and it is the posture the engine defaults to. The boundary is
|
|
46
|
+
* REQUIRED: a command that cannot be contained is refused, naming why, and
|
|
47
|
+
* running on the host is not a fallback available to it. The owner's
|
|
48
|
+
* terminal is denied outright, at the exec guard, regardless of boundary.
|
|
49
|
+
* - WORKSTREAM — a real work chain the owner authorized, which may genuinely
|
|
50
|
+
* need the machine itself — is a per-spawn grant this composition makes
|
|
51
|
+
* explicitly. There is no such spawn today, so the function below never
|
|
52
|
+
* returns it; when there is one, the grant is written HERE, in the daemon's
|
|
53
|
+
* own composition, where a reader can see which spawns hold it. Nothing on
|
|
54
|
+
* the wire and nothing in a tool argument can reach it.
|
|
26
55
|
*/
|
|
27
56
|
import { createShellPathService } from '@/runtime/index.ts';
|
|
28
57
|
import { createClientRuntimeServices } from '@pellux/goodvibes-sdk/platform/runtime/client-services';
|
|
29
58
|
import { createRuntimeStore } from '@pellux/goodvibes-sdk/platform/runtime/store';
|
|
30
59
|
import { createLaunchTolerantProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
|
|
31
60
|
import type { DaemonHostedSessionsOptions } from '@pellux/goodvibes-sdk/platform/daemon';
|
|
32
|
-
import type {
|
|
61
|
+
import type {
|
|
62
|
+
HostedSessionExecPosture,
|
|
63
|
+
HostedWorkspaceFloor,
|
|
64
|
+
} from '@pellux/goodvibes-sdk/platform/hosted-sessions';
|
|
65
|
+
import { CONVERSATIONAL_DIAGNOSIS_SECTION } from '@pellux/goodvibes-sdk/platform/agents';
|
|
33
66
|
import { operations } from '@pellux/goodvibes-sdk/platform/runtime';
|
|
34
67
|
const { WorkspaceTrustManager } = operations;
|
|
35
68
|
import { createWorkspaceTrustDecisionAsk, trustGatedApprovalRaiser, type ApprovalRaise } from './trust/trust-gated-approvals.ts';
|
|
@@ -39,13 +72,32 @@ import type { RuntimeServices } from './runtime-services-types.ts';
|
|
|
39
72
|
/** The operator policy a session hosted by THIS daemon runs under. */
|
|
40
73
|
function hostedSystemPrompt(input: { readonly workspaceRoot: string }): string {
|
|
41
74
|
return [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
75
|
+
[
|
|
76
|
+
'You are a GoodVibes session hosted by the daemon rather than by a terminal.',
|
|
77
|
+
`Your working directory is ${input.workspaceRoot}.`,
|
|
78
|
+
'Someone may be attached and watching this turn, or may have detached and read it later —',
|
|
79
|
+
'write for both. Say what you did and why; never report work you did not do.',
|
|
80
|
+
'Tool permissions are decided by whoever is attached: an ask you raise may take a while to be',
|
|
81
|
+
'answered, and an unanswered one is a refusal, not a reason to find another way round.',
|
|
82
|
+
].join(' '),
|
|
83
|
+
// The same contract every other conversational turn is held to, from the
|
|
84
|
+
// SDK rather than restated here — a second copy is a copy that drifts.
|
|
85
|
+
CONVERSATIONAL_DIAGNOSIS_SECTION,
|
|
86
|
+
].join('\n\n');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* What a hosted session's exec tool may do.
|
|
91
|
+
*
|
|
92
|
+
* Every session this daemon hosts is a conversation, so every one of them is
|
|
93
|
+
* contained (see the module header). Stated on the floor rather than left to
|
|
94
|
+
* the engine's default so that the day a workstream spawn exists, the grant is
|
|
95
|
+
* a visible change to THIS function and not an option someone set elsewhere —
|
|
96
|
+
* and it sits beside the trust gate, which is the other statement this daemon
|
|
97
|
+
* makes about how much authority a hosted run carries.
|
|
98
|
+
*/
|
|
99
|
+
function hostedExecPosture(): HostedSessionExecPosture {
|
|
100
|
+
return 'conversational';
|
|
49
101
|
}
|
|
50
102
|
|
|
51
103
|
/**
|
|
@@ -120,6 +172,7 @@ export function createHostedSessionOptions(services: RuntimeServices): DaemonHos
|
|
|
120
172
|
// The daemon has a real review-chain controller; a hosted session's
|
|
121
173
|
// orchestrator lists through it rather than reporting none.
|
|
122
174
|
wrfcController: services.wrfcController,
|
|
175
|
+
execPosture: hostedExecPosture,
|
|
123
176
|
dispose: (): void => floor.dispose(),
|
|
124
177
|
};
|
|
125
178
|
},
|
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.28.
|
|
9
|
+
let _version = '1.28.12';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
|
|
12
12
|
// Only trust a version read from OUR OWN package.json. A Bun single-file
|