viber-channel 0.8.23 → 0.8.25
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/lib/capabilities.ts +125 -42
- package/lib/claude_tool_defs.ts +3 -2
- package/lib/team_template_tool.ts +4 -1
- package/package.json +1 -1
- package/viber-channel.ts +2 -1
- package/viber-codex-bridge.ts +9 -7
package/lib/capabilities.ts
CHANGED
|
@@ -1,51 +1,134 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Control-plane capabilities help (#332).
|
|
2
|
+
* Control-plane capabilities help (#332, rewritten for the Gateway in #651).
|
|
3
3
|
*
|
|
4
|
-
* An agent connected via the channel does not otherwise know
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* An agent connected via the channel does not otherwise know how Viber launches,
|
|
5
|
+
* supervises and dissolves other agents. Per the issue + JP: this must be
|
|
6
|
+
* DISCOVERABLE ON DEMAND, never injected into every conversation. So the channel
|
|
7
|
+
* exposes a `capabilities` MCP tool that returns this text only when the agent
|
|
8
|
+
* chooses to call it; the channel instructions carry just a one-line pointer.
|
|
9
|
+
*
|
|
10
|
+
* This is the HOME of "how to USE Viber" for every project (TaskMan points here,
|
|
11
|
+
* #651). Every claim below was checked against the code at #651; keep it that way.
|
|
10
12
|
*
|
|
11
13
|
* Pure (no I/O) so it is trivially testable and identical across hosts.
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
|
-
export function capabilitiesText(): string {
|
|
16
|
+
export function capabilitiesText(channelVersion: string | null = null): string {
|
|
15
17
|
return [
|
|
16
|
-
|
|
17
|
-
"",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"",
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
18
|
+
`viber-channel ${channelVersion ?? "(version unknown)"} — this text is served by that version.`,
|
|
19
|
+
"Viber control plane — launch, supervise and dissolve OTHER agents (Codex, Claude, Gemma).",
|
|
20
|
+
"Launched agents appear in the Viber web UI and answer in their own conversations.",
|
|
21
|
+
"",
|
|
22
|
+
"INSTALL (new machine, Windows): run install.ps1 from the newest GitHub release tagged",
|
|
23
|
+
"vibe-master-v* in dgx80/viber. Those releases are NOT marked \"Latest\" (Latest is the",
|
|
24
|
+
"core v* release, which has no install.ps1), so resolve the tag instead of using /latest:",
|
|
25
|
+
" $t = (gh release list --repo dgx80/viber --limit 30 --json tagName --jq",
|
|
26
|
+
" '.[].tagName' | Where-Object { $_ -like 'vibe-master-v*' })[0]",
|
|
27
|
+
" gh release download $t --repo dgx80/viber --pattern install.ps1 --clobber",
|
|
28
|
+
" .\\install.ps1 -Token <PAT> # fine-grained, READ-ONLY on dgx80/viber + dgx80/vctl:",
|
|
29
|
+
" it is stored on disk for auto-update — never pass your full `gh auth token`.",
|
|
30
|
+
"It installs vibe-master.exe + viber-gateway.exe (%LOCALAPPDATA%\\vibe-master, on PATH),",
|
|
31
|
+
"vctl, bun, viber-channel and the Start-menu app \"Viber\". Then, in the project folder:",
|
|
32
|
+
"`bunx viber-channel connect <url from the web>` writes .viber/auth.json.",
|
|
33
|
+
"",
|
|
34
|
+
"THE VIBER APP (runner) carries presence. Start \"Viber\" (viber-gateway.exe, no args):",
|
|
35
|
+
"a tray app whose runner beats every 30 s for every agent it launched. Agents do not",
|
|
36
|
+
"heartbeat themselves: while the app is not running they stay PAUSED — shown offline,",
|
|
37
|
+
"and send_message / message_agent answer \"Paused — … Nothing was sent\". That is not",
|
|
38
|
+
"a failure: it resumes by itself once the runner covers the agent again.",
|
|
39
|
+
"Quitting the app does not kill agents. The runner also relaunches a dead agent when",
|
|
40
|
+
"the web asks (greyed rows).",
|
|
41
|
+
"",
|
|
42
|
+
"LAUNCH A TEAM (from the project folder, which must hold .viber/auth.json, or",
|
|
43
|
+
".viber/dev.auth.json for --env dev):",
|
|
44
|
+
" viber-gateway launch-team <template> --prefix <p> [--team <t>] [--env dev|staging]",
|
|
45
|
+
" [--cwd <dir>]",
|
|
46
|
+
" → --env defaults to staging (the stable channel: agents register with no trust",
|
|
47
|
+
" prompt; use it for working teams). --team defaults to the PREFIX (so dissolve",
|
|
48
|
+
" --team <prefix> when you omitted it). Each agent is named <prefix>-<role>.",
|
|
49
|
+
" Built-in template: dev-team (dev lead + 2 reviewers).",
|
|
50
|
+
" Output is verbose; only these lines matter:",
|
|
51
|
+
" team: verdict COMPLETE|INCOMPLET — N member(s)",
|
|
52
|
+
" member <launch-id>: <outcome> one per agent; launched = success, keep the id",
|
|
53
|
+
" for dissolve --agent. Anything else (existing,",
|
|
54
|
+
" unknown, no-outcome-published): read the counts",
|
|
55
|
+
" INCOMPLET: read missing / mayHaveTree / treeUnknown — mayHaveTree means a process",
|
|
56
|
+
" tree may exist anyway: dissolve it before relaunching.",
|
|
57
|
+
" team: REFUSED before anything was created — <why> (nothing was launched)",
|
|
58
|
+
" ONLINE DELAY: up to ~45 s after the agent has started, plus the runtime boot",
|
|
59
|
+
" (runner beat every 30 s + coverage re-read every 15 s). An empty list_agents right",
|
|
60
|
+
" after launching is NOT a failure: wait and list again.",
|
|
61
|
+
"ONE AGENT ALONE = a one-role team. launch-team has no --name and there is no solo",
|
|
62
|
+
"shortcut: add a one-role template to .viber/agent-teams.json once (merged with the",
|
|
63
|
+
"built-ins; an entry with a built-in's name REPLACES it entirely), then launch it:",
|
|
64
|
+
" {\"teams\":{\"solo\":{\"roles\":[{\"role\":\"dev\",\"runtime\":\"claude\",",
|
|
65
|
+
" \"permission\":\"read-write\",\"rolePrompt\":\"You are the dev of {prefix}.\"}]}}}",
|
|
66
|
+
" viber-gateway launch-team solo --prefix g1 → agent \"g1-dev\", team \"g1\"",
|
|
67
|
+
" runtime: claude|codex|gemma · permission: read-only|read-write (gemma: read-only",
|
|
68
|
+
" only; all roles of one template must share one permission) · count optional;",
|
|
69
|
+
" model: leave it OUT (runtime default) UNLESS the owner explicitly asks for one.",
|
|
70
|
+
" (On the web, sidebar ⋯ → Add agent launches ONE named agent without a template edit.)",
|
|
71
|
+
"",
|
|
72
|
+
"DISSOLVE (stops the processes, then revokes the proven-stopped instances):",
|
|
73
|
+
" viber-gateway dissolve --team <t> | --agent <launch-id> --dir <registry>",
|
|
74
|
+
" [--auth <auth.json>] [--base-url <url>]",
|
|
75
|
+
" --dir is REQUIRED, no default (exit 2 without it; refused under %TEMP%). For agents",
|
|
76
|
+
" launched by the app or launch-team, pass it in full (PowerShell):",
|
|
77
|
+
" --dir \"$env:LOCALAPPDATA\\Viber\\.viber\\gateway-registry\"",
|
|
78
|
+
" (the app home is %LOCALAPPDATA%\\Viber unless VIBER_APP_HOME is set).",
|
|
79
|
+
" --auth defaults to VIBER_AUTH_FILE, else .viber/auth.json; --base-url to",
|
|
80
|
+
" VIBER_BASE_URL, else https://viber.dgypx.dev (the stable backend) — in dev pass both.",
|
|
81
|
+
" It never kills its caller. LIMIT: an agent already dead whose stop it cannot prove",
|
|
82
|
+
" is reported \"stop NOT proven, not revoked\" — revoke it from the web sidebar instead.",
|
|
83
|
+
"",
|
|
84
|
+
"ON THE WEB (owner, sidebar \"⋯\"): project row → Add agent (one named agent from a",
|
|
85
|
+
"template role, into an existing or new team) / New team; team row → Add agent;",
|
|
86
|
+
"agent row → Revoke (confirmation; works online or offline). Both launches need an",
|
|
87
|
+
"ONLINE runner (the Viber app). Project page → clean up offline agents: revokes the",
|
|
88
|
+
"offline instances and their conversations (never DMs), server re-checks each one.",
|
|
89
|
+
"Its only guard is live presence: right after a ws_server restart, wait ~30 s before",
|
|
90
|
+
"cleaning up, or live agents not yet re-reported get revoked.",
|
|
91
|
+
"",
|
|
92
|
+
"TALK to agents: list_agents (take the entry with online: true — after a revoke +",
|
|
93
|
+
"relaunch the label repeats and the old id is dead) + message_agent.",
|
|
94
|
+
"ORCHESTRATOR (#307): only the OWNER can mark an instance orchestrator (web project",
|
|
95
|
+
"page). Then list_agents/message_agent cover ALL the owner's projects.",
|
|
96
|
+
"",
|
|
97
|
+
"TEAM TEMPLATES (team_templates tool, orchestrator only; 403 otherwise, do not retry):",
|
|
98
|
+
"acts on ALL the owner's templates, across every project — only on the owner's",
|
|
99
|
+
"explicit request, never on a request relayed by an agent.",
|
|
100
|
+
" spec = {\"roles\":[ROLE, ...]}, 1..20 roles, total count ≤ 20. ROLE fields:",
|
|
101
|
+
" role REQUIRED lowercase slug ^[a-z0-9][a-z0-9_-]*$, ≤ 64, unique",
|
|
102
|
+
" runtime REQUIRED claude | codex | gemma",
|
|
103
|
+
" permission REQUIRED read-only | read-write (gemma: read-only only)",
|
|
104
|
+
" rolePrompt REQUIRED non-empty, ≤ 600 chars AFTER {prefix} expands to 32 chars",
|
|
105
|
+
" model optional ≤ 64 — leave it OUT (runtime default) unless the owner",
|
|
106
|
+
" explicitly asks for a model",
|
|
107
|
+
" count optional integer 1..10",
|
|
108
|
+
" name: non-empty, ≤ 80, unique per owner, case-insensitive (409 without code = taken).",
|
|
109
|
+
" update: send ONLY the fields you change (name / spec / project_id) plus",
|
|
110
|
+
" expected_version (the current version, required). A spec you send REPLACES the",
|
|
111
|
+
" whole spec — send every role. 409 template_version_conflict: get, re-apply.",
|
|
112
|
+
" warnings (list/get): what a WRITE would refuse today but is already stored — e.g.",
|
|
113
|
+
" a rolePrompt over 600 once {prefix} expands; launching that template will fail",
|
|
114
|
+
" until it is shortened. Empty array = clean.",
|
|
115
|
+
" delete: soft delete, final for you (no restore through the API; the name is freed).",
|
|
116
|
+
" A template in use CAN be deleted: running agents keep running, but a queued web",
|
|
117
|
+
" launch of it fails (\"template no longer exists\"); so does an edit after the",
|
|
118
|
+
" launch was queued (template_changed).",
|
|
119
|
+
"LAUNCHING A WEB/DB TEMPLATE: launch-team does NOT read these templates (only built-ins",
|
|
120
|
+
"+ .viber/agent-teams.json), and agents cannot launch through the API. Either the owner",
|
|
121
|
+
"launches it from the web (sidebar ⋯ → New team / Add agent), or you copy its spec",
|
|
122
|
+
"(team_templates get) into .viber/agent-teams.json under a name, then launch-team it.",
|
|
123
|
+
"",
|
|
124
|
+
"CODEX agents, observed today: their Viber MCP calls, message_agent included, have",
|
|
125
|
+
"been rejected by their approval policy (#609), so they cannot open an exchange — write",
|
|
126
|
+
"to them FIRST and read their reply on that DM. Their `gh` has no usable token in",
|
|
127
|
+
"the sandbox (#525): run gh (labels, PR comments) for them.",
|
|
128
|
+
"",
|
|
129
|
+
"Low level, not relaunchable from the web: `vibe-master spawn --permission <p>",
|
|
130
|
+
"[--runtime codex|claude|gemma] [--name <id>]` (`vibe-master --help`).",
|
|
131
|
+
"viber-gateway has no --help: an unknown verb runs the startup command (exit 2",
|
|
132
|
+
"without --dir; with --dir it runs startup on that registry).",
|
|
50
133
|
].join("\n");
|
|
51
134
|
}
|
package/lib/claude_tool_defs.ts
CHANGED
|
@@ -125,8 +125,9 @@ export const CLAUDE_TOOL_DEFS = [
|
|
|
125
125
|
{
|
|
126
126
|
name: "capabilities",
|
|
127
127
|
description:
|
|
128
|
-
"On-demand:
|
|
129
|
-
"
|
|
128
|
+
"On-demand: how Viber launches, supervises and dissolves OTHER agents (Codex, " +
|
|
129
|
+
"Claude, Gemma) — install, the Viber app/runner, viber-gateway launch-team and " +
|
|
130
|
+
"dissolve, the web sidebar, orchestrator template admin, Codex limits. " +
|
|
130
131
|
"Call this only when orchestrating other agents is relevant; it is not part " +
|
|
131
132
|
"of the default context. Returns a short usage reference.",
|
|
132
133
|
inputSchema: {
|
|
@@ -54,7 +54,10 @@ export const TEAM_TEMPLATES_TOOL_DEF = {
|
|
|
54
54
|
spec: {
|
|
55
55
|
type: "object",
|
|
56
56
|
description:
|
|
57
|
-
"The roster, for create/update: { roles: [{ role, runtime, permission, rolePrompt, model? }] } — same shape `get` returns."
|
|
57
|
+
"The roster, for create/update: { roles: [{ role, runtime, permission, rolePrompt, model?, count? }] } — same shape `get` returns. " +
|
|
58
|
+
"On update a spec REPLACES the whole spec: send every role. " +
|
|
59
|
+
"model: leave it OUT (the runtime picks its own default) UNLESS the owner explicitly asks for a model. " +
|
|
60
|
+
"Full field rules: the capabilities tool.",
|
|
58
61
|
},
|
|
59
62
|
project_id: {
|
|
60
63
|
type: ["integer", "null"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "viber-channel",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.25",
|
|
4
4
|
"description": "Voice + text MCP channel between a Claude Code session and the Viber UI (https://viber.dgypx.dev). Push transcripts to Claude; send_message tool delivers text back to the UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/viber-channel.ts
CHANGED
|
@@ -69,6 +69,7 @@ import { CLAUDE_TOOL_DEFS } from "./lib/claude_tool_defs.ts";
|
|
|
69
69
|
import { teamTemplates as teamTemplatesTool } from "./lib/team_template_tool.ts";
|
|
70
70
|
import { warnIfStale } from "./lib/version_check.ts";
|
|
71
71
|
import { capabilitiesText } from "./lib/capabilities.ts";
|
|
72
|
+
import { readLocalVersion } from "./lib/version_check.ts";
|
|
72
73
|
import { BOW_OUT_MESSAGE, shouldBowOutToPlugin } from "./lib/cli_bow_out.ts";
|
|
73
74
|
import { resolveLockDir } from "./lib/lock_dir.ts";
|
|
74
75
|
import { acquireLockFile, createLockSlot } from "./lib/bridge_lock.ts";
|
|
@@ -516,7 +517,7 @@ async function handleCallTool(
|
|
|
516
517
|
|
|
517
518
|
// #332: on-demand control-plane discovery — static help, no runtime state.
|
|
518
519
|
if (request.params.name === "capabilities") {
|
|
519
|
-
return { content: [{ type: "text" as const, text: capabilitiesText() }] };
|
|
520
|
+
return { content: [{ type: "text" as const, text: capabilitiesText(readLocalVersion()) }] };
|
|
520
521
|
}
|
|
521
522
|
|
|
522
523
|
if (request.params.name !== "send_message") {
|
package/viber-codex-bridge.ts
CHANGED
|
@@ -492,22 +492,23 @@ export const VOICE_CONCISE_LINE = `Your replies are returned to a voice/text con
|
|
|
492
492
|
// outbound tool was used — but once an outbound tool is called, the bridge does
|
|
493
493
|
// NOT also auto-post (anti-double-post), so the tool call must carry everything.
|
|
494
494
|
const CHANNEL_TOOLS_LINE =
|
|
495
|
-
"You have
|
|
495
|
+
"You have four Viber channel tools: send_message (post your reply to the current conversation — " +
|
|
496
496
|
"`text` is the spoken reply, optional `artifact` {content, format: markdown|code|json|html} carries " +
|
|
497
497
|
"technical content shown in a side panel), list_agents (list the other agents in this project), and " +
|
|
498
|
-
"message_agent (open or reuse a direct message to another agent by its instance id)
|
|
498
|
+
"message_agent (open or reuse a direct message to another agent by its instance id), and " +
|
|
499
|
+
"team_templates (orchestrator only: administer the owner's team templates, on the owner's request). " +
|
|
499
500
|
"To reply you may EITHER call send_message OR simply write your answer as this turn's text: if you did " +
|
|
500
501
|
"NOT call send_message or message_agent, the bridge auto-delivers your turn text as the reply. If you DID " +
|
|
501
502
|
"call an outbound tool, the bridge does not also auto-post — so put everything you want delivered into the " +
|
|
502
503
|
"tool call(s). Keep the spoken text short and natural; put code, lists, JSON, or long technical detail in " +
|
|
503
504
|
"send_message's artifact, not the spoken text.";
|
|
504
505
|
|
|
505
|
-
function instructionsForTier(tier: AgentTier): string {
|
|
506
|
+
export function instructionsForTier(tier: AgentTier): string {
|
|
506
507
|
if (tier === "write") {
|
|
507
508
|
return [
|
|
508
509
|
"You are a bridge-owned Codex agent connected to Viber, in READ-WRITE mode.",
|
|
509
510
|
"You MAY read files, create/modify files within the workspace, and run commands (including state-changing ones) to carry out the user's requests.",
|
|
510
|
-
"The sandbox is workspace-write: writes are confined to the workspace, and network access is ENABLED — so you can run git (including `git push`)
|
|
511
|
+
"The sandbox is workspace-write: writes are confined to the workspace, and network access is ENABLED — so you can run git (including `git push`). `gh` has no usable token in this sandbox (#525): ask the agent who briefed you to run gh for you.",
|
|
511
512
|
"There is NO human approval step, so be deliberate: make only the changes the user asked for, and avoid destructive commands unless explicitly requested.",
|
|
512
513
|
VOICE_CONCISE_LINE,
|
|
513
514
|
CHANNEL_TOOLS_LINE,
|
|
@@ -608,9 +609,10 @@ export function decideServerRequestResponse(
|
|
|
608
609
|
return { decision: "decline" };
|
|
609
610
|
}
|
|
610
611
|
// NB (codex review): `serverName === "viber"` is sufficient today because OUR
|
|
611
|
-
// host advertises only
|
|
612
|
-
//
|
|
613
|
-
//
|
|
612
|
+
// host advertises only its 4 channel tools (ListTools; #642 added team_templates,
|
|
613
|
+
// server-gated by the orchestrator flag), and the "viber" name is bound to our own
|
|
614
|
+
// loopback URL by config WE set — not attacker-controllable. If the host ever
|
|
615
|
+
// exposes a tool that is not a channel tool, tighten here by tool name.
|
|
614
616
|
|
|
615
617
|
|
|
616
618
|
/**
|