@pellux/goodvibes-agent 0.1.27 → 0.1.29
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 +10 -0
- package/docs/README.md +1 -0
- package/docs/getting-started.md +19 -1
- package/docs/operator-capability-benchmark.md +4 -4
- package/package.json +1 -1
- package/src/agent/runtime-profile.ts +119 -0
- package/src/cli/completion.ts +8 -0
- package/src/cli/entrypoint.ts +22 -3
- package/src/cli/help.ts +10 -0
- package/src/cli/management.ts +6 -0
- package/src/cli/parser.ts +9 -0
- package/src/cli/profiles-command.ts +208 -0
- package/src/cli/types.ts +2 -0
- package/src/input/agent-workspace.ts +13 -0
- package/src/main.ts +2 -2
- package/src/operator/capability-benchmark.ts +11 -11
- package/src/renderer/agent-workspace.ts +7 -0
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GoodVibes Agent will be recorded here.
|
|
4
4
|
|
|
5
|
+
## 0.1.29 - 2026-05-31
|
|
6
|
+
|
|
7
|
+
- 3fafcda Add Agent channel workspace guidance
|
|
8
|
+
|
|
9
|
+
## 0.1.28 - 2026-05-31
|
|
10
|
+
|
|
11
|
+
- 77a9dc4 Add isolated Agent runtime profiles
|
|
12
|
+
|
|
5
13
|
## 0.1.27 - 2026-05-31
|
|
6
14
|
|
|
7
15
|
- b5be172 Add capabilities CLI handler
|
package/README.md
CHANGED
|
@@ -46,6 +46,16 @@ Inside the Agent TUI, use `/agent`, `/home`, or `/operator` to open the operator
|
|
|
46
46
|
|
|
47
47
|
Use `goodvibes-agent capabilities` or `/capabilities` to inspect the OpenClaw/Hermes benchmark, current Agent posture, configuration commands, usage paths, and remaining gaps.
|
|
48
48
|
|
|
49
|
+
Use isolated Agent runtime profiles when one machine needs separate operator identities or local state:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
goodvibes-agent profiles create household --yes
|
|
53
|
+
goodvibes-agent --agent-profile household status
|
|
54
|
+
GOODVIBES_AGENT_HOME=/path/to/agent-home goodvibes-agent status
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Profiles isolate Agent-local config, sessions, local memory, personas, skills, routines, and setup state. The daemon is still external and shared unless your daemon host is separately configured otherwise.
|
|
58
|
+
|
|
49
59
|
Local Agent behavior is editable from the TUI:
|
|
50
60
|
|
|
51
61
|
```text
|
package/docs/README.md
CHANGED
|
@@ -20,6 +20,7 @@ Important baseline constraints:
|
|
|
20
20
|
- Agent does not start, stop, restart, install, uninstall, or own daemon/listener/web/service lifecycle.
|
|
21
21
|
- Agent Knowledge/Wiki uses only `/api/goodvibes-agent/knowledge/*`; there is no default Knowledge/Wiki, HomeGraph, or Home Assistant fallback.
|
|
22
22
|
- Agent exposes `goodvibes-agent capabilities` and `/capabilities` to compare OpenClaw/Hermes capability targets against current Agent readiness and configuration paths.
|
|
23
|
+
- Agent supports isolated runtime homes with `GOODVIBES_AGENT_HOME=<path>` and named profile homes with `goodvibes-agent profiles create <name> --yes` plus `--agent-profile <name>`.
|
|
23
24
|
- Local personas, routines, and Agent skills are stored under the Agent surface root and are injected only into the serial Agent conversation.
|
|
24
25
|
- Normal assistant chat is not coding-session delegation.
|
|
25
26
|
- Build/fix/review delegation to GoodVibes TUI must be explicit; WRFC is not the default Agent behavior.
|
package/docs/getting-started.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Getting Started
|
|
2
2
|
|
|
3
|
-
GoodVibes Agent
|
|
3
|
+
GoodVibes Agent is the installable public alpha of the personal operator assistant built on the GoodVibes TUI foundation.
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
@@ -37,6 +37,24 @@ bun run dev
|
|
|
37
37
|
|
|
38
38
|
Once the TUI opens, run `/agent`, `/home`, or `/operator` to open the Agent operator workspace. That fullscreen workspace is the current front door for setup/config, knowledge status, local memory and skills, read-only work/approval/automation views, and explicit GoodVibes TUI build delegation.
|
|
39
39
|
|
|
40
|
+
## Isolated Agent Profiles
|
|
41
|
+
|
|
42
|
+
Use a separate Agent home when you want isolated local state:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
GOODVIBES_AGENT_HOME=/path/to/agent-home goodvibes-agent status
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Use named runtime profiles for repeatable local identities:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
goodvibes-agent profiles create household --yes
|
|
52
|
+
goodvibes-agent --agent-profile household status
|
|
53
|
+
goodvibes-agent --agent-profile household
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Named profiles isolate Agent-local config, sessions, memory, personas, skills, routines, and setup state under a profile-specific home. They do not start or isolate the external daemon by themselves.
|
|
57
|
+
|
|
40
58
|
## Local Personas, Routines, And Skills
|
|
41
59
|
|
|
42
60
|
Personas, routines, and reusable Agent skills are local to GoodVibes Agent. They do not write into default Knowledge/Wiki or HomeGraph.
|
|
@@ -43,14 +43,14 @@ Primary sources used for the benchmark:
|
|
|
43
43
|
| --- | --- | --- |
|
|
44
44
|
| Terminal operator UI | Interactive CLI/TUI, commands, sessions | Near-fork GoodVibes TUI compositor/input/fullscreen foundation |
|
|
45
45
|
| Always-on gateway | Gateway/service owns channels, sessions, tools, events | External GoodVibes daemon, never Agent-owned lifecycle |
|
|
46
|
-
| Channels | WhatsApp, Telegram, Slack, Discord, Signal, iMessage, web chat | GoodVibes daemon channel and companion surfaces with Agent-side policy |
|
|
46
|
+
| Channels | WhatsApp, Telegram, Slack, Discord, Signal, iMessage, web chat | GoodVibes daemon channel and companion surfaces with Agent-side policy and a Channels operator workspace |
|
|
47
47
|
| Knowledge/memory | Durable memory, semantic search, wiki/claim layers | Isolated Agent Knowledge routes plus local memory/skills/personas/routines |
|
|
48
48
|
| Skills/procedural memory | Skills directories, registries, skill lifecycle | Local Agent skills with review/stale/source/provenance fields |
|
|
49
49
|
| Scheduling | Natural-language cron, run/pause/resume/edit/remove, delivery | Guarded automation/schedule routes plus local routines; hidden model scheduling blocked |
|
|
50
50
|
| Tools/MCP | Broad toolsets, MCP, browser, media, terminal, files | GoodVibes SDK tools with Agent policy guards and MCP/provider integrations |
|
|
51
51
|
| Voice/media/canvas/nodes | Voice, TTS, mobile nodes, live canvas, browser automation | GoodVibes media/voice/browser primitives copied in; Agent-first setup still being wired |
|
|
52
52
|
| Build/code work | Direct terminal/file/code tools and subagents | Explicit delegation to GoodVibes TUI; local WRFC/spawn fanout blocked |
|
|
53
|
-
| Profiles | Independent profiles with own config/memory/skills/gateway |
|
|
53
|
+
| Profiles | Independent profiles with own config/memory/skills/gateway | `GOODVIBES_AGENT_HOME` and named `--agent-profile` homes isolate Agent-local state; daemon remains external |
|
|
54
54
|
| Security | DM pairing, approvals, sandboxing, allowlists | Daemon approvals, auth diagnostics, secret refs, confirmation gates, model-tool policy |
|
|
55
55
|
|
|
56
56
|
## Exceed Targets
|
|
@@ -66,9 +66,9 @@ GoodVibes Agent should exceed OpenClaw/Hermes by making these properties true fr
|
|
|
66
66
|
|
|
67
67
|
## Current Gaps To Close
|
|
68
68
|
|
|
69
|
-
-
|
|
69
|
+
- Per-channel account readiness, delivery defaults, and risk labels in the Channels workspace detail pane.
|
|
70
70
|
- Richer Agent Knowledge ingest/review workspace for URLs, bookmarks, artifacts, issue queues, and consolidation.
|
|
71
|
-
-
|
|
71
|
+
- Profile-aware onboarding summaries and profile export/import shortcuts from the Agent workspace.
|
|
72
72
|
- Voice/media/browser/node setup workspaces.
|
|
73
73
|
- Delegation receipts and artifact review inside the operator workspace.
|
|
74
74
|
- Approval center with route risk labels and saved policy presets.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Near-fork GoodVibes operator assistant with the GoodVibes TUI shell, renderer, input, fullscreen workspace, and daemon-connected Agent product brain.",
|
|
6
6
|
"type": "module",
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
export interface AgentRuntimeProfileResolution {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly homeDirectory: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface AgentRuntimeProfileInfo extends AgentRuntimeProfileResolution {
|
|
10
|
+
readonly createdAt: string | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface AgentRuntimeProfileCommandResult {
|
|
14
|
+
readonly ok: boolean;
|
|
15
|
+
readonly kind:
|
|
16
|
+
| 'agent.profiles.list'
|
|
17
|
+
| 'agent.profiles.show'
|
|
18
|
+
| 'agent.profiles.create'
|
|
19
|
+
| 'agent.profiles.delete'
|
|
20
|
+
| 'agent.profiles.error';
|
|
21
|
+
readonly data?: {
|
|
22
|
+
readonly profiles?: readonly AgentRuntimeProfileInfo[];
|
|
23
|
+
readonly profile?: AgentRuntimeProfileInfo;
|
|
24
|
+
readonly nextCommand?: string;
|
|
25
|
+
};
|
|
26
|
+
readonly error?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const PROFILE_CREATED_FILE = 'profile.json';
|
|
30
|
+
const PROFILE_ID_PATTERN = /^[a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?$/;
|
|
31
|
+
|
|
32
|
+
export function normalizeAgentRuntimeProfileId(value: string): string {
|
|
33
|
+
return value
|
|
34
|
+
.trim()
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.replace(/[^a-z0-9._-]+/g, '-')
|
|
37
|
+
.replace(/^[._-]+|[._-]+$/g, '')
|
|
38
|
+
.replace(/[-_]{2,}/g, '-');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function assertValidAgentRuntimeProfileId(value: string): string {
|
|
42
|
+
const raw = value.trim();
|
|
43
|
+
if (raw.includes('..') || raw.includes('/') || raw.includes('\\')) {
|
|
44
|
+
throw new Error('Agent profile names cannot contain path traversal sequences.');
|
|
45
|
+
}
|
|
46
|
+
const normalized = normalizeAgentRuntimeProfileId(value);
|
|
47
|
+
if (!PROFILE_ID_PATTERN.test(normalized)) {
|
|
48
|
+
throw new Error('Agent profile names must normalize to 1-64 lowercase letters, numbers, dots, underscores, or dashes.');
|
|
49
|
+
}
|
|
50
|
+
return normalized;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getAgentRuntimeProfilesRoot(baseHomeDirectory: string): string {
|
|
54
|
+
return join(baseHomeDirectory, '.goodvibes', 'agent', 'profile-homes');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function resolveAgentRuntimeProfileHome(baseHomeDirectory: string, profileName: string): AgentRuntimeProfileResolution {
|
|
58
|
+
const id = assertValidAgentRuntimeProfileId(profileName);
|
|
59
|
+
return {
|
|
60
|
+
id,
|
|
61
|
+
homeDirectory: join(getAgentRuntimeProfilesRoot(baseHomeDirectory), id),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function readProfileCreatedAt(homeDirectory: string): string | null {
|
|
66
|
+
const path = join(homeDirectory, PROFILE_CREATED_FILE);
|
|
67
|
+
if (!existsSync(path)) return null;
|
|
68
|
+
try {
|
|
69
|
+
const raw = JSON.parse(readFileSync(path, 'utf-8'));
|
|
70
|
+
if (raw && typeof raw === 'object' && typeof raw.createdAt === 'string') return raw.createdAt;
|
|
71
|
+
} catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function buildProfileInfo(baseHomeDirectory: string, id: string): AgentRuntimeProfileInfo {
|
|
78
|
+
const { homeDirectory } = resolveAgentRuntimeProfileHome(baseHomeDirectory, id);
|
|
79
|
+
return {
|
|
80
|
+
id,
|
|
81
|
+
homeDirectory,
|
|
82
|
+
createdAt: readProfileCreatedAt(homeDirectory),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function listAgentRuntimeProfiles(baseHomeDirectory: string): readonly AgentRuntimeProfileInfo[] {
|
|
87
|
+
const root = getAgentRuntimeProfilesRoot(baseHomeDirectory);
|
|
88
|
+
if (!existsSync(root)) return [];
|
|
89
|
+
return readdirSync(root)
|
|
90
|
+
.filter((entry) => PROFILE_ID_PATTERN.test(entry) && !entry.includes('..'))
|
|
91
|
+
.filter((entry) => {
|
|
92
|
+
try {
|
|
93
|
+
return statSync(join(root, entry)).isDirectory();
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
.sort((left, right) => left.localeCompare(right))
|
|
99
|
+
.map((entry) => buildProfileInfo(baseHomeDirectory, entry));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function createAgentRuntimeProfile(baseHomeDirectory: string, profileName: string): AgentRuntimeProfileInfo {
|
|
103
|
+
const resolution = resolveAgentRuntimeProfileHome(baseHomeDirectory, profileName);
|
|
104
|
+
mkdirSync(resolution.homeDirectory, { recursive: true });
|
|
105
|
+
const createdAt = new Date().toISOString();
|
|
106
|
+
writeFileSync(
|
|
107
|
+
join(resolution.homeDirectory, PROFILE_CREATED_FILE),
|
|
108
|
+
`${JSON.stringify({ id: resolution.id, createdAt }, null, 2)}\n`,
|
|
109
|
+
'utf-8',
|
|
110
|
+
);
|
|
111
|
+
return { ...resolution, createdAt };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function deleteAgentRuntimeProfile(baseHomeDirectory: string, profileName: string): boolean {
|
|
115
|
+
const resolution = resolveAgentRuntimeProfileHome(baseHomeDirectory, profileName);
|
|
116
|
+
if (!existsSync(resolution.homeDirectory)) return false;
|
|
117
|
+
rmSync(resolution.homeDirectory, { recursive: true, force: true });
|
|
118
|
+
return true;
|
|
119
|
+
}
|
package/src/cli/completion.ts
CHANGED
|
@@ -11,7 +11,14 @@ const COMMANDS = [
|
|
|
11
11
|
'status',
|
|
12
12
|
'models',
|
|
13
13
|
'providers',
|
|
14
|
+
'profiles',
|
|
14
15
|
'auth',
|
|
16
|
+
'compat',
|
|
17
|
+
'capabilities',
|
|
18
|
+
'knowledge',
|
|
19
|
+
'ask',
|
|
20
|
+
'search',
|
|
21
|
+
'delegate',
|
|
15
22
|
'subscription',
|
|
16
23
|
'secrets',
|
|
17
24
|
'sessions',
|
|
@@ -34,6 +41,7 @@ const OPTIONS = [
|
|
|
34
41
|
'--version',
|
|
35
42
|
'--model',
|
|
36
43
|
'--provider',
|
|
44
|
+
'--agent-profile',
|
|
37
45
|
'--cd',
|
|
38
46
|
'--working-dir',
|
|
39
47
|
'--daemon-home',
|
package/src/cli/entrypoint.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from './index.ts';
|
|
24
24
|
import { buildCliServicePosture } from './service-posture.ts';
|
|
25
25
|
import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
|
|
26
|
+
import { resolveAgentRuntimeProfileHome } from '../agent/runtime-profile.ts';
|
|
26
27
|
|
|
27
28
|
type ShellEntrypointOwnership = {
|
|
28
29
|
readonly workingDirectory: string;
|
|
@@ -41,10 +42,17 @@ export type PreparedShellCliRuntime = {
|
|
|
41
42
|
readonly bootstrapHomeDirectory: string;
|
|
42
43
|
};
|
|
43
44
|
|
|
44
|
-
function resolveShellEntrypointOwnership(
|
|
45
|
+
function resolveShellEntrypointOwnership(
|
|
46
|
+
roots: ShellEntrypointRoots,
|
|
47
|
+
workingDirOverride?: string,
|
|
48
|
+
agentProfile?: string,
|
|
49
|
+
): ShellEntrypointOwnership {
|
|
50
|
+
const homeDirectory = agentProfile
|
|
51
|
+
? resolveAgentRuntimeProfileHome(roots.homeDirectory, agentProfile).homeDirectory
|
|
52
|
+
: roots.homeDirectory;
|
|
45
53
|
return {
|
|
46
54
|
workingDirectory: workingDirOverride ?? roots.defaultWorkingDirectory,
|
|
47
|
-
homeDirectory
|
|
55
|
+
homeDirectory,
|
|
48
56
|
};
|
|
49
57
|
}
|
|
50
58
|
|
|
@@ -86,10 +94,21 @@ export async function prepareShellCliRuntime(
|
|
|
86
94
|
process.exit(2);
|
|
87
95
|
}
|
|
88
96
|
|
|
97
|
+
let ownership: ShellEntrypointOwnership;
|
|
98
|
+
try {
|
|
99
|
+
ownership = resolveShellEntrypointOwnership(
|
|
100
|
+
roots,
|
|
101
|
+
cli.flags.workingDir ?? (cli.command === 'tui' ? cli.commandArgs[0] : undefined),
|
|
102
|
+
cli.command === 'profiles' ? undefined : cli.flags.agentProfile,
|
|
103
|
+
);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
106
|
+
process.exit(2);
|
|
107
|
+
}
|
|
89
108
|
const {
|
|
90
109
|
workingDirectory: bootstrapWorkingDir,
|
|
91
110
|
homeDirectory: bootstrapHomeDirectory,
|
|
92
|
-
} =
|
|
111
|
+
} = ownership;
|
|
93
112
|
configureActivityLogger(join(bootstrapWorkingDir, '.goodvibes', 'logs'));
|
|
94
113
|
const configManager = new ConfigManager({
|
|
95
114
|
workingDir: bootstrapWorkingDir,
|
package/src/cli/help.ts
CHANGED
|
@@ -38,6 +38,7 @@ export function renderGoodVibesHelp(binary = 'goodvibes-agent'): string {
|
|
|
38
38
|
' onboarding [status] Open Agent onboarding, or print onboarding status',
|
|
39
39
|
' models [provider] List/use/pin selectable models and recent model history',
|
|
40
40
|
' providers List/inspect/use provider config/auth posture',
|
|
41
|
+
' profiles Manage isolated Agent runtime profile homes',
|
|
41
42
|
' auth Inspect and manage local users, sessions, and bootstrap auth',
|
|
42
43
|
' compat Inspect Agent SDK pin, daemon version, and Agent knowledge route readiness',
|
|
43
44
|
' capabilities Show OpenClaw/Hermes capability parity and Agent readiness',
|
|
@@ -62,6 +63,7 @@ export function renderGoodVibesHelp(binary = 'goodvibes-agent'): string {
|
|
|
62
63
|
'Options:',
|
|
63
64
|
' -m, --model <registryKey> Override model. provider:model infers --provider',
|
|
64
65
|
' --provider <id> Override provider',
|
|
66
|
+
' --agent-profile <name> Use an isolated Agent runtime profile home',
|
|
65
67
|
' -C, --cd <dir> Set working directory for this launch',
|
|
66
68
|
' --working-dir <dir> Alias for --cd',
|
|
67
69
|
' --daemon-home <dir> Override daemon home for daemon-backed commands',
|
|
@@ -94,6 +96,8 @@ export function renderGoodVibesHelp(binary = 'goodvibes-agent'): string {
|
|
|
94
96
|
` ${binary} models current`,
|
|
95
97
|
` ${binary} models use openai:gpt-5.2`,
|
|
96
98
|
` ${binary} providers inspect openai`,
|
|
99
|
+
` ${binary} profiles create household --yes`,
|
|
100
|
+
` ${binary} --agent-profile household`,
|
|
97
101
|
` ${binary} compat`,
|
|
98
102
|
` ${binary} capabilities`,
|
|
99
103
|
` ${binary} knowledge status`,
|
|
@@ -149,6 +153,11 @@ const COMMAND_HELP: Record<string, CommandHelp> = {
|
|
|
149
153
|
summary: 'Inspect and change provider setup, auth posture, model counts, and setup class.',
|
|
150
154
|
examples: ['providers', 'providers inspect openai-subscriber', 'providers use openai openai:gpt-5.4'],
|
|
151
155
|
},
|
|
156
|
+
profiles: {
|
|
157
|
+
usage: ['profiles list', 'profiles show <name>', 'profiles create <name> --yes', 'profiles delete <name> --yes', '--agent-profile <name>'],
|
|
158
|
+
summary: 'Create and inspect isolated Agent runtime profile homes. A profile changes Agent-local config, sessions, memory, personas, skills, routines, and setup paths without changing the externally owned daemon.',
|
|
159
|
+
examples: ['profiles create household --yes', 'profiles list', '--agent-profile household status', '--agent-profile household'],
|
|
160
|
+
},
|
|
152
161
|
models: {
|
|
153
162
|
usage: ['models [provider]', 'models current', 'models use <registryKey>', 'models pin <registryKey>', 'models recent'],
|
|
154
163
|
summary: 'List, inspect, select, pin, and review model choices.',
|
|
@@ -280,6 +289,7 @@ const HELP_ALIASES: Record<string, string> = {
|
|
|
280
289
|
setup: 'onboarding',
|
|
281
290
|
provider: 'providers',
|
|
282
291
|
model: 'models',
|
|
292
|
+
profile: 'profiles',
|
|
283
293
|
subscriptions: 'subscription',
|
|
284
294
|
secret: 'secrets',
|
|
285
295
|
session: 'sessions',
|
package/src/cli/management.ts
CHANGED
|
@@ -34,6 +34,7 @@ import { buildListenerTestResult, formatListenerTestResult, handleSurfacesComman
|
|
|
34
34
|
import { buildControlPlaneStatusResult, formatControlPlaneStatus, handleSecrets, handleSessions, handleTasks, renderPairing, renderRemote, renderSubscriptions, renderWeb } from './management-commands.ts';
|
|
35
35
|
import { handleAgentKnowledgeCommand, handleAgentKnowledgeShortcutCommand, handleCompatCommand, handleDelegateCommand } from './agent-knowledge-command.ts';
|
|
36
36
|
import { handleCapabilitiesCommand } from './capabilities-command.ts';
|
|
37
|
+
import { handleProfilesCommand } from './profiles-command.ts';
|
|
37
38
|
import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
|
|
38
39
|
|
|
39
40
|
export interface CliCommandRuntime {
|
|
@@ -704,6 +705,11 @@ export async function handleGoodVibesCliCommand(runtime: CliCommandRuntime): Pro
|
|
|
704
705
|
console.log(result.output);
|
|
705
706
|
return { handled: true, exitCode: result.exitCode };
|
|
706
707
|
}
|
|
708
|
+
case 'profiles': {
|
|
709
|
+
const result = await handleProfilesCommand(runtime);
|
|
710
|
+
console.log(result.output);
|
|
711
|
+
return { handled: true, exitCode: result.exitCode };
|
|
712
|
+
}
|
|
707
713
|
case 'knowledge': {
|
|
708
714
|
const result = await handleAgentKnowledgeCommand(runtime);
|
|
709
715
|
console.log(result.output);
|
package/src/cli/parser.ts
CHANGED
|
@@ -25,6 +25,8 @@ const COMMAND_ALIASES: Readonly<Record<string, GoodVibesCliCommand>> = {
|
|
|
25
25
|
model: 'models',
|
|
26
26
|
providers: 'providers',
|
|
27
27
|
provider: 'providers',
|
|
28
|
+
profiles: 'profiles',
|
|
29
|
+
profile: 'profiles',
|
|
28
30
|
auth: 'auth',
|
|
29
31
|
compat: 'compat',
|
|
30
32
|
compatibility: 'compat',
|
|
@@ -73,6 +75,7 @@ function createDefaultFlags(): GoodVibesCliFlags {
|
|
|
73
75
|
return {
|
|
74
76
|
provider: undefined,
|
|
75
77
|
model: undefined,
|
|
78
|
+
agentProfile: undefined,
|
|
76
79
|
daemonHome: undefined,
|
|
77
80
|
workingDir: undefined,
|
|
78
81
|
help: false,
|
|
@@ -279,6 +282,12 @@ export function parseGoodVibesCli(
|
|
|
279
282
|
}
|
|
280
283
|
continue;
|
|
281
284
|
}
|
|
285
|
+
if (name === '--agent-profile') {
|
|
286
|
+
const consumed = getValue(argv, index, inlineValue, name, errors);
|
|
287
|
+
index = consumed.nextIndex;
|
|
288
|
+
if (consumed.value !== undefined) flags = withFlag(flags, 'agentProfile', consumed.value);
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
282
291
|
if (name === '--daemon-home') {
|
|
283
292
|
const consumed = getValue(argv, index, inlineValue, name, errors);
|
|
284
293
|
index = consumed.nextIndex;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAgentRuntimeProfile,
|
|
3
|
+
deleteAgentRuntimeProfile,
|
|
4
|
+
listAgentRuntimeProfiles,
|
|
5
|
+
resolveAgentRuntimeProfileHome,
|
|
6
|
+
type AgentRuntimeProfileCommandResult,
|
|
7
|
+
type AgentRuntimeProfileInfo,
|
|
8
|
+
} from '../agent/runtime-profile.ts';
|
|
9
|
+
import type { CliCommandOutput, GoodVibesCliParseResult } from './types.ts';
|
|
10
|
+
|
|
11
|
+
interface ProfilesCommandRuntime {
|
|
12
|
+
readonly cli: GoodVibesCliParseResult;
|
|
13
|
+
readonly homeDirectory: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function hasYes(args: readonly string[]): boolean {
|
|
17
|
+
return args.includes('--yes');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function commandValues(args: readonly string[]): readonly string[] {
|
|
21
|
+
const values: string[] = [];
|
|
22
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
23
|
+
const token = args[index]!;
|
|
24
|
+
if (!token.startsWith('--')) values.push(token);
|
|
25
|
+
}
|
|
26
|
+
return values;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function profileLine(profile: AgentRuntimeProfileInfo): string {
|
|
30
|
+
const created = profile.createdAt ? ` created=${profile.createdAt}` : '';
|
|
31
|
+
return ` ${profile.id} home=${profile.homeDirectory}${created}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function renderProfilesResult(result: AgentRuntimeProfileCommandResult): string {
|
|
35
|
+
if (!result.ok) return result.error ?? 'Agent profile command failed.';
|
|
36
|
+
if (result.kind === 'agent.profiles.list') {
|
|
37
|
+
const profiles = result.data?.profiles ?? [];
|
|
38
|
+
if (profiles.length === 0) return 'No Agent runtime profiles. Use: goodvibes-agent profiles create <name> --yes';
|
|
39
|
+
return [
|
|
40
|
+
`Agent runtime profiles (${profiles.length})`,
|
|
41
|
+
...profiles.map(profileLine),
|
|
42
|
+
].join('\n');
|
|
43
|
+
}
|
|
44
|
+
const profile = result.data?.profile;
|
|
45
|
+
if (result.kind === 'agent.profiles.create' && profile) {
|
|
46
|
+
return [
|
|
47
|
+
`Agent runtime profile created: ${profile.id}`,
|
|
48
|
+
` home: ${profile.homeDirectory}`,
|
|
49
|
+
` use: ${result.data?.nextCommand ?? `goodvibes-agent --agent-profile ${profile.id}`}`,
|
|
50
|
+
].join('\n');
|
|
51
|
+
}
|
|
52
|
+
if (result.kind === 'agent.profiles.delete' && profile) {
|
|
53
|
+
return `Agent runtime profile deleted: ${profile.id}`;
|
|
54
|
+
}
|
|
55
|
+
return 'Agent profile command completed.';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function renderProfilesOutput(result: AgentRuntimeProfileCommandResult, format: string): string {
|
|
59
|
+
if (format === 'json') return JSON.stringify(result, null, 2);
|
|
60
|
+
return renderProfilesResult(result);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function handleProfilesCommand(runtime: ProfilesCommandRuntime): Promise<CliCommandOutput> {
|
|
64
|
+
const [sub = 'list', ...rawRest] = runtime.cli.commandArgs;
|
|
65
|
+
const values = commandValues(rawRest);
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
if (sub === 'list' || sub === 'ls') {
|
|
69
|
+
const result: AgentRuntimeProfileCommandResult = {
|
|
70
|
+
ok: true,
|
|
71
|
+
kind: 'agent.profiles.list',
|
|
72
|
+
data: { profiles: listAgentRuntimeProfiles(runtime.homeDirectory) },
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
|
|
76
|
+
exitCode: 0,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (sub === 'show' || sub === 'path' || sub === 'home') {
|
|
81
|
+
const name = values[0];
|
|
82
|
+
if (!name) {
|
|
83
|
+
const result: AgentRuntimeProfileCommandResult = {
|
|
84
|
+
ok: false,
|
|
85
|
+
kind: 'agent.profiles.error',
|
|
86
|
+
error: 'Usage: goodvibes-agent profiles show <name>',
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
|
|
90
|
+
exitCode: 2,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const profile = resolveAgentRuntimeProfileHome(runtime.homeDirectory, name);
|
|
94
|
+
const result: AgentRuntimeProfileCommandResult = {
|
|
95
|
+
ok: true,
|
|
96
|
+
kind: 'agent.profiles.show',
|
|
97
|
+
data: { profile: { ...profile, createdAt: null } },
|
|
98
|
+
};
|
|
99
|
+
const text = [`Agent runtime profile: ${profile.id}`, ` home: ${profile.homeDirectory}`, ` use: goodvibes-agent --agent-profile ${profile.id}`].join('\n');
|
|
100
|
+
return {
|
|
101
|
+
output: runtime.cli.flags.outputFormat === 'json' ? JSON.stringify(result, null, 2) : text,
|
|
102
|
+
exitCode: 0,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (sub === 'create') {
|
|
107
|
+
const name = values[0];
|
|
108
|
+
if (!name) {
|
|
109
|
+
const result: AgentRuntimeProfileCommandResult = {
|
|
110
|
+
ok: false,
|
|
111
|
+
kind: 'agent.profiles.error',
|
|
112
|
+
error: 'Usage: goodvibes-agent profiles create <name> --yes',
|
|
113
|
+
};
|
|
114
|
+
return {
|
|
115
|
+
output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
|
|
116
|
+
exitCode: 2,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (!hasYes(rawRest)) {
|
|
120
|
+
const result: AgentRuntimeProfileCommandResult = {
|
|
121
|
+
ok: false,
|
|
122
|
+
kind: 'agent.profiles.error',
|
|
123
|
+
error: `Refusing to create Agent runtime profile ${name} without --yes.`,
|
|
124
|
+
};
|
|
125
|
+
return {
|
|
126
|
+
output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
|
|
127
|
+
exitCode: 2,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const profile = createAgentRuntimeProfile(runtime.homeDirectory, name);
|
|
131
|
+
const result: AgentRuntimeProfileCommandResult = {
|
|
132
|
+
ok: true,
|
|
133
|
+
kind: 'agent.profiles.create',
|
|
134
|
+
data: {
|
|
135
|
+
profile,
|
|
136
|
+
nextCommand: `goodvibes-agent --agent-profile ${profile.id}`,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
|
|
141
|
+
exitCode: 0,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (sub === 'delete' || sub === 'remove') {
|
|
146
|
+
const name = values[0];
|
|
147
|
+
if (!name) {
|
|
148
|
+
const result: AgentRuntimeProfileCommandResult = {
|
|
149
|
+
ok: false,
|
|
150
|
+
kind: 'agent.profiles.error',
|
|
151
|
+
error: 'Usage: goodvibes-agent profiles delete <name> --yes',
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
|
|
155
|
+
exitCode: 2,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (!hasYes(rawRest)) {
|
|
159
|
+
const result: AgentRuntimeProfileCommandResult = {
|
|
160
|
+
ok: false,
|
|
161
|
+
kind: 'agent.profiles.error',
|
|
162
|
+
error: `Refusing to delete Agent runtime profile ${name} without --yes.`,
|
|
163
|
+
};
|
|
164
|
+
return {
|
|
165
|
+
output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
|
|
166
|
+
exitCode: 2,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const resolution = resolveAgentRuntimeProfileHome(runtime.homeDirectory, name);
|
|
170
|
+
const deleted = deleteAgentRuntimeProfile(runtime.homeDirectory, name);
|
|
171
|
+
const result: AgentRuntimeProfileCommandResult = deleted
|
|
172
|
+
? {
|
|
173
|
+
ok: true,
|
|
174
|
+
kind: 'agent.profiles.delete',
|
|
175
|
+
data: { profile: { ...resolution, createdAt: null } },
|
|
176
|
+
}
|
|
177
|
+
: {
|
|
178
|
+
ok: false,
|
|
179
|
+
kind: 'agent.profiles.error',
|
|
180
|
+
error: `Agent runtime profile not found: ${resolution.id}`,
|
|
181
|
+
};
|
|
182
|
+
return {
|
|
183
|
+
output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
|
|
184
|
+
exitCode: deleted ? 0 : 1,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const result: AgentRuntimeProfileCommandResult = {
|
|
189
|
+
ok: false,
|
|
190
|
+
kind: 'agent.profiles.error',
|
|
191
|
+
error: 'Usage: goodvibes-agent profiles [list|show <name>|create <name> --yes|delete <name> --yes]',
|
|
192
|
+
};
|
|
193
|
+
return {
|
|
194
|
+
output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
|
|
195
|
+
exitCode: 2,
|
|
196
|
+
};
|
|
197
|
+
} catch (error) {
|
|
198
|
+
const result: AgentRuntimeProfileCommandResult = {
|
|
199
|
+
ok: false,
|
|
200
|
+
kind: 'agent.profiles.error',
|
|
201
|
+
error: error instanceof Error ? error.message : String(error),
|
|
202
|
+
};
|
|
203
|
+
return {
|
|
204
|
+
output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
|
|
205
|
+
exitCode: 2,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
package/src/cli/types.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type GoodVibesCliCommand =
|
|
|
9
9
|
| 'onboarding'
|
|
10
10
|
| 'models'
|
|
11
11
|
| 'providers'
|
|
12
|
+
| 'profiles'
|
|
12
13
|
| 'auth'
|
|
13
14
|
| 'compat'
|
|
14
15
|
| 'capabilities'
|
|
@@ -42,6 +43,7 @@ export interface CliCommandOutput {
|
|
|
42
43
|
export interface GoodVibesCliFlags {
|
|
43
44
|
readonly provider: string | undefined;
|
|
44
45
|
readonly model: string | undefined;
|
|
46
|
+
readonly agentProfile: string | undefined;
|
|
45
47
|
readonly daemonHome: string | undefined;
|
|
46
48
|
readonly workingDir: string | undefined;
|
|
47
49
|
readonly help: boolean;
|
|
@@ -192,6 +192,19 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
192
192
|
{ id: 'auth', label: 'Auth review', detail: 'Review authentication posture without printing token values.', command: '/auth review', kind: 'command', safety: 'read-only' },
|
|
193
193
|
],
|
|
194
194
|
},
|
|
195
|
+
{
|
|
196
|
+
id: 'channels',
|
|
197
|
+
group: 'SETUP',
|
|
198
|
+
label: 'Channels',
|
|
199
|
+
summary: 'Companion pairing, channel posture, and delivery safety.',
|
|
200
|
+
detail: 'Agent uses externally owned daemon channel surfaces. Pairing, account inspection, and readiness checks are visible here; inbound delivery and public channel exposure stay policy-gated.',
|
|
201
|
+
actions: [
|
|
202
|
+
{ id: 'pair', label: 'Pair companion', detail: 'Open the TUI-derived QR pairing surface for companion app setup.', command: '/pair', kind: 'command', safety: 'safe' },
|
|
203
|
+
{ id: 'communication', label: 'Communication routes', detail: 'Inspect structured communication routes and recent activity.', command: '/communication', kind: 'command', safety: 'read-only' },
|
|
204
|
+
{ id: 'setup-review', label: 'Channel setup review', detail: 'Review setup posture without starting listeners or mutating daemon surface state.', command: '/setup review', kind: 'command', safety: 'read-only' },
|
|
205
|
+
{ id: 'channel-safety', label: 'Delivery safety', detail: 'External messages, channel DMs, and public delivery targets require explicit user action and daemon-side policy. Agent will not silently send or expose channels from this workspace.', kind: 'guidance', safety: 'blocked' },
|
|
206
|
+
],
|
|
207
|
+
},
|
|
195
208
|
{
|
|
196
209
|
id: 'knowledge',
|
|
197
210
|
group: 'KNOW',
|
package/src/main.ts
CHANGED
|
@@ -70,7 +70,7 @@ async function main() {
|
|
|
70
70
|
const stdin = process.stdin;
|
|
71
71
|
const { cli, configManager, bootstrapWorkingDir, bootstrapHomeDirectory } = await prepareShellCliRuntime(process.argv.slice(2), {
|
|
72
72
|
defaultWorkingDirectory: process.env['GOODVIBES_WORKING_DIR'] ?? process.cwd(),
|
|
73
|
-
homeDirectory: homedir(),
|
|
73
|
+
homeDirectory: process.env['GOODVIBES_AGENT_HOME'] ?? homedir(),
|
|
74
74
|
}, 'goodvibes-agent');
|
|
75
75
|
|
|
76
76
|
const ctx: BootstrapContext = await bootstrapRuntime(stdout, {
|
|
@@ -267,7 +267,7 @@ async function main() {
|
|
|
267
267
|
|
|
268
268
|
const submitInput = (text: string, content?: ContentPart[], options: { readonly spokenOutput?: boolean } = {}) => {
|
|
269
269
|
input.clearModalStack();
|
|
270
|
-
scrollLocked = true; // Re-lock on
|
|
270
|
+
scrollLocked = true; // Re-lock on user input
|
|
271
271
|
const AT_MODEL_RE = /@model:([^\s]+)/g;
|
|
272
272
|
let processedText = text;
|
|
273
273
|
let atModelMatch: RegExpExecArray | null;
|
|
@@ -69,11 +69,11 @@ export const OPERATOR_CAPABILITY_BENCHMARKS: readonly OperatorCapabilityBenchmar
|
|
|
69
69
|
posture: 'configurable',
|
|
70
70
|
competitors: ['openclaw', 'hermes'],
|
|
71
71
|
competitorBaseline: 'Messaging gateway for WhatsApp, Telegram, Slack, Discord, Signal, iMessage, web chat, and related platforms.',
|
|
72
|
-
goodvibesAgent: 'Uses GoodVibes daemon channel, companion, pairing, QR, and session surfaces while keeping side effects behind explicit user action.',
|
|
73
|
-
configure: ['goodvibes-agent pair', 'goodvibes-agent qrcode', 'goodvibes-agent surfaces check'],
|
|
74
|
-
use: ['/
|
|
75
|
-
exceedsBy: ['Agent-owned safety policy over shared channel routes', 'read-only inspection by default', 'explicit approval path for external side effects'],
|
|
76
|
-
next: ['Add
|
|
72
|
+
goodvibesAgent: 'Uses GoodVibes daemon channel, companion, pairing, QR, communication, and session surfaces while keeping side effects behind explicit user action. The Agent workspace exposes channel setup and safety as a first-class operator area.',
|
|
73
|
+
configure: ['goodvibes-agent pair', 'goodvibes-agent qrcode', 'goodvibes-agent surfaces check', '/agent → Channels'],
|
|
74
|
+
use: ['/agent → Channels', '/communication', '/pair'],
|
|
75
|
+
exceedsBy: ['Agent-owned safety policy over shared channel routes', 'read-only inspection by default', 'explicit approval path for external side effects', 'channel setup discoverable from the fullscreen operator workspace'],
|
|
76
|
+
next: ['Add per-channel account readiness, delivery defaults, and risk labels directly in the Channels workspace detail pane.'],
|
|
77
77
|
},
|
|
78
78
|
{
|
|
79
79
|
id: 'isolated-knowledge-wiki',
|
|
@@ -150,14 +150,14 @@ export const OPERATOR_CAPABILITY_BENCHMARKS: readonly OperatorCapabilityBenchmar
|
|
|
150
150
|
{
|
|
151
151
|
id: 'profiles-isolation',
|
|
152
152
|
title: 'Profiles And Isolated Operator State',
|
|
153
|
-
posture: '
|
|
153
|
+
posture: 'ready',
|
|
154
154
|
competitors: ['hermes'],
|
|
155
155
|
competitorBaseline: 'Profiles run independent agents with isolated configs, sessions, skills, memory, cron jobs, and gateway state.',
|
|
156
|
-
goodvibesAgent: '
|
|
157
|
-
configure: ['GOODVIBES_AGENT_HOME=<path> goodvibes-agent status', 'goodvibes-agent bundle export goodvibes-agent-bundle.json'],
|
|
158
|
-
use: ['goodvibes-agent --
|
|
159
|
-
exceedsBy: ['Typed support bundles', 'explicit daemon boundary', 'no accidental cross-product knowledge fallback'],
|
|
160
|
-
next: ['Add
|
|
156
|
+
goodvibesAgent: 'Supports GOODVIBES_AGENT_HOME and named --agent-profile homes for isolated Agent-local config, sessions, memory, personas, skills, routines, setup, and bundles; daemon remains shared/external by design.',
|
|
157
|
+
configure: ['GOODVIBES_AGENT_HOME=<path> goodvibes-agent status', 'goodvibes-agent profiles create household --yes', 'goodvibes-agent bundle export goodvibes-agent-bundle.json'],
|
|
158
|
+
use: ['goodvibes-agent --agent-profile household', 'goodvibes-agent --agent-profile household status', 'goodvibes-agent sessions list'],
|
|
159
|
+
exceedsBy: ['Typed support bundles', 'explicit daemon boundary', 'no accidental cross-product knowledge fallback', 'profile isolation without hidden daemon lifecycle ownership'],
|
|
160
|
+
next: ['Add profile-aware onboarding summaries and profile export/import shortcuts from the Agent workspace.'],
|
|
161
161
|
},
|
|
162
162
|
{
|
|
163
163
|
id: 'security-approvals',
|
|
@@ -88,6 +88,13 @@ function snapshotLines(category: AgentWorkspaceCategory, snapshot: AgentWorkspac
|
|
|
88
88
|
{ text: `Workspace: ${snapshot.workingDirectory}`, fg: PALETTE.muted },
|
|
89
89
|
{ text: `Home: ${snapshot.homeDirectory}`, fg: PALETTE.muted },
|
|
90
90
|
);
|
|
91
|
+
} else if (category.id === 'channels') {
|
|
92
|
+
base.push(
|
|
93
|
+
{ text: `External daemon: ${snapshot.daemonBaseUrl}`, fg: PALETTE.info },
|
|
94
|
+
{ text: 'Pairing: use /pair or /qrcode for companion setup.', fg: PALETTE.info },
|
|
95
|
+
{ text: 'Channel posture: inspect via /communication and /setup review.', fg: PALETTE.muted },
|
|
96
|
+
{ text: 'Safety: external delivery, unknown senders, and public exposure require explicit policy and user action.', fg: PALETTE.warn },
|
|
97
|
+
);
|
|
91
98
|
} else if (category.id === 'knowledge') {
|
|
92
99
|
base.push(
|
|
93
100
|
{ text: `Route family: ${snapshot.knowledgeRoute}/{status,ask,search}`, fg: PALETTE.info },
|
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 = '0.1.
|
|
9
|
+
let _version = '0.1.29';
|
|
10
10
|
let _sdkVersion = '0.33.35';
|
|
11
11
|
try {
|
|
12
12
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
|