@vibest/cli 0.0.1-beta.13 → 0.0.1-beta.15
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/bin/vibest.cjs +9 -1
- package/harnesses/claude/.claude-plugin/plugin.json +4 -4
- package/harnesses/claude/README.md +48 -117
- package/harnesses/claude/hooks/hooks.json +1 -3
- package/harnesses/claude/hooks/register.mjs +289 -494
- package/harnesses/claude/skills/delegate/SKILL.md +8 -6
- package/harnesses/claude/skills/pipeline/SKILL.md +3 -3
- package/harnesses/cursor/.cursor-plugin/plugin.json +1 -1
- package/harnesses/cursor/hooks/vibest.sh +22 -1
- package/harnesses/cursor/skills/delegate/SKILL.md +8 -6
- package/harnesses/cursor/skills/pipeline/SKILL.md +3 -3
- package/harnesses/pi/extension.mjs +693 -402
- package/harnesses/pi/skills/delegate/SKILL.md +8 -6
- package/harnesses/pi/skills/pipeline/SKILL.md +3 -3
- package/package.json +25 -25
package/bin/vibest.cjs
CHANGED
|
@@ -9,7 +9,15 @@ let binary
|
|
|
9
9
|
try {
|
|
10
10
|
binary = require.resolve(`@vibest/cli-${target}/bin/vibest`)
|
|
11
11
|
} catch {
|
|
12
|
-
|
|
12
|
+
// The package manager skipped the optional platform package (bun does at times): the exact command that adds it.
|
|
13
|
+
const pkg = `@vibest/cli-${target}@${require("../package.json").version}`
|
|
14
|
+
const prefix = /^(.+)\/lib\/node_modules\/@vibest\/cli\/bin$/.exec(__dirname)
|
|
15
|
+
const install = __dirname.includes("/.bun/")
|
|
16
|
+
? `bun add -g ${pkg}`
|
|
17
|
+
: prefix
|
|
18
|
+
? `npm install -g --prefix ${prefix[1]} ${pkg}`
|
|
19
|
+
: `npm install -g ${pkg}`
|
|
20
|
+
console.error(`vibest: no binary for ${target}; install it with: ${install}`)
|
|
13
21
|
process.exit(1)
|
|
14
22
|
}
|
|
15
23
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibest",
|
|
3
|
-
"description": "VIBEST for Claude Code: turn-end reports and the tool guard for VIBEST sessions, and the coordinator inbox that delivers VIBEST messages as prompts,
|
|
3
|
+
"description": "VIBEST for Claude Code: turn-end reports, prompt reports and the tool guard for VIBEST sessions, and the coordinator inbox that delivers VIBEST messages as prompts, all over HTTP to vibestd",
|
|
4
4
|
"author": {
|
|
5
|
-
"name": "
|
|
5
|
+
"name": "vibest-dev"
|
|
6
6
|
},
|
|
7
|
-
"repository": "https://github.com/
|
|
7
|
+
"repository": "https://github.com/vibest-dev/vibest",
|
|
8
8
|
"license": "MIT",
|
|
9
|
-
"version": "0.0.1-beta.
|
|
9
|
+
"version": "0.0.1-beta.15"
|
|
10
10
|
}
|
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
# @vibest/claude: the vibest Claude Code plugin
|
|
2
2
|
|
|
3
|
-
One ordinary Claude Code plugin
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
One ordinary Claude Code plugin, one hooks module. Every call to vibest is an HTTP request from `$.http.fetch` to
|
|
4
|
+
vibestd's unix socket `<VIBEST_HOME>/vibest-http.sock`; the plugin runs no `vibest` process.
|
|
5
|
+
|
|
6
|
+
- `turn.complete` posts each main-loop turn end to `/hooks/claude/turn-end` with its `reason`, the answer and the
|
|
7
|
+
current Claude session id. vibest maps the reason: `answer` is the result as it is; `aborted` is an interrupted
|
|
8
|
+
(failed) result when the person pressed Esc, and nothing when `vibest interrupt` (or remove, archive) stopped the
|
|
9
|
+
turn; `refusal` and `error` are failed results. A subagent's loop (`agentId` set) reports nothing. For the
|
|
10
|
+
coordinator vibestd records only the conversation id.
|
|
11
|
+
- `prompt.submit` posts a worker's prompt with its `origin.kind` to `/hooks/claude/prompt`; vibest keeps only what
|
|
12
|
+
the person submitted (`composer`, or `bridge` for Remote Control).
|
|
13
|
+
- `tool.call` posts each tool call, a subagent's included, to `/hooks/claude/guard` and returns `{ deny }` when vibest
|
|
14
|
+
refuses it. It tries for 2 s, then again after 100, 300 and 900 ms; when nothing answers, the call is refused.
|
|
15
|
+
- The **coordinator inbox**: from `session.start`, a coordinator polls `/inbox/poll` every second. A batch comes as
|
|
16
|
+
one short line (`<Type> Agent "<title>" completed (<id>) · +N more`) and its full text. The line is submitted with
|
|
17
|
+
`$.prompt.submit` from the AbovePrompt `ui.render` hook, one batch per draw, and this module's own `prompt.submit`
|
|
18
|
+
hook attaches the full text as context. An accepted submit is acked by row id (`/inbox/ack`) on the next tick; a
|
|
19
|
+
`drop` puts the batch back at the front of the queue.
|
|
20
|
+
|
|
21
|
+
Reports (turn end, prompt) retry in the background after 1, 2, 4, 8, 15 and 30 s while vibestd does not take them.
|
|
22
|
+
|
|
23
|
+
Every request carries the session headers from `@vibest/protocol` `sessionHeaders`: protocol, `VIBEST_SESSION_ID`,
|
|
24
|
+
`VIBEST_PROJECT_ID`, the current Claude session id, `VIBEST_AGENT`, `VIBEST_HARNESS`, the cwd, `VIBEST_RUNTIME` and the
|
|
25
|
+
plugin version. Paths carry no version; the only one is `PROTOCOL` in the `vibest-protocol` header. vibestd refuses a
|
|
26
|
+
request with an unknown session (404), a missing or wrong project id (403) or another protocol (409). A 409 body holds
|
|
27
|
+
vibestd's protocol and version, a message and the command to run (`action`); the plugin puts them on the status line
|
|
28
|
+
until a request goes through again, and the guard still refuses each tool call, giving them as the reason.
|
|
11
29
|
|
|
12
30
|
It ships inside `@vibest/cli` and is loaded only into the Claude sessions vibest starts (see Use).
|
|
13
31
|
|
|
@@ -23,9 +41,8 @@ The plugin directory holds exactly:
|
|
|
23
41
|
|
|
24
42
|
- `.claude-plugin/plugin.json`, generated: `src/manifest.json` with `version` set from this `package.json`.
|
|
25
43
|
- `hooks/hooks.json`: `"modules": ["./register.mjs"]` only. No command-hook map and no shell wrapper.
|
|
26
|
-
- `hooks/register.mjs`, generated: a single ES module with no imports. It bundles `src/plugin.ts`
|
|
27
|
-
|
|
28
|
-
in that module. Prebuilt JS is a delivery choice; Claude Code can also load TypeScript hooks modules.
|
|
44
|
+
- `hooks/register.mjs`, generated: a single ES module with no imports. It bundles `src/plugin.ts` with the header
|
|
45
|
+
helper it imports from `@vibest/protocol`; the build inlines the package version as `VIBEST_PLUGIN_VERSION`. Prebuilt JS is a delivery choice; Claude Code can also load TypeScript hooks modules.
|
|
29
46
|
- `README.md` and `LICENSE`.
|
|
30
47
|
|
|
31
48
|
The generated files are ignored by Git. `test/distribution.test.ts` packs this package and checks the extracted files.
|
|
@@ -33,109 +50,23 @@ The generated files are ignored by Git. `test/distribution.test.ts` packs this p
|
|
|
33
50
|
## Use
|
|
34
51
|
|
|
35
52
|
Nothing to install. vibest starts each Claude session (and a Claude coordinator) with
|
|
36
|
-
`claude --plugin-dir <@vibest/cli>/harnesses/claude`, which loads the plugin for that session only
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
is
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
`
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
when `VIBEST_AGENT` and `VIBEST_SESSION_ID` are both set. Elsewhere they return `next` and do not call vibest. The inbox
|
|
54
|
-
module acts only in a process whose environment marks it as an VIBEST coordinator. That environment is what `vibest`
|
|
55
|
-
sets up:
|
|
56
|
-
|
|
57
|
-
- `VIBEST_AGENT=coordinator` and `VIBEST_SESSION_ID`;
|
|
58
|
-
- `HERDR_PANE_ID` and `HERDR_SOCKET_PATH`;
|
|
59
|
-
- the reported Claude session that the daemon fences on.
|
|
60
|
-
|
|
61
|
-
The module always registers `session.start`, `session.end`, `command.run`, and the three `classic.*` listeners. In any other
|
|
62
|
-
process (a worker, or a plain `claude`) they activate no receiver: the module registers no `/vibest-reattach` command,
|
|
63
|
-
starts no timer and never calls `vibest inbox`. Setting the VIBEST
|
|
64
|
-
variables by hand is not a substitute, because it does not create the coordinator's daemon-side identity.
|
|
65
|
-
|
|
66
|
-
**Loading gate.** Claude Code statically analyzes a hooks module before loading it. Claude Code 2.1.316 loaded this
|
|
67
|
-
revision in `claude -p` (E2E I4): `classic.PreToolUse` refused a herdr call and `classic.Stop` wrote the result. The inbox
|
|
68
|
-
module has not been exercised in a live coordinator.
|
|
69
|
-
|
|
70
|
-
- `register` stays a top-level `function` declaration. Each hook passes `$` only to the top-level `nativeHost`.
|
|
71
|
-
- The distribution test checks that `register` is declared and exported, that `hooks.json` has no command hooks, that no
|
|
72
|
-
shell wrapper is shipped, and that the official-type source still bundles to import-free JS.
|
|
73
|
-
|
|
74
|
-
## Prerequisites (not checked, not forced)
|
|
75
|
-
|
|
76
|
-
- **Hooks modules enabled.** Claude Code must load hooks modules for non-builtin plugins. In 2.1.309 that depends on the
|
|
77
|
-
rollout flag `tengu_plugin_hooks_modules` and on accepted workspace trust (interactive sessions). The plugin does not
|
|
78
|
-
read or change either, and does not fake readiness when they are off. A module that does not load cannot receive
|
|
79
|
-
messages. A bridge attachment made earlier can still leave paste delivery suppressed, because VIBEST keeps the bridge
|
|
80
|
-
marker across receiver loss and restarts; disabling the plugin, or a module that fails to load, does not restore
|
|
81
|
-
paste delivery automatically.
|
|
82
|
-
- **`vibest` on PATH with the `inbox` command.** Calls are the bare argv `vibest inbox attach|pull|ack|release …`, run
|
|
83
|
-
through `$.process.run` with the host's PATH and environment, with no shell. An `vibest` without `inbox` makes attach fail
|
|
84
|
-
with an exit code, and the status line says so.
|
|
85
|
-
- **This Claude session reported to VIBEST.** VIBEST learns the coordinator's Claude session from the `Stop` /
|
|
86
|
-
`StopFailure` hook when a turn ends; there is no SessionStart report. Until then attach answers `not-reported`, and
|
|
87
|
-
the module keeps polling with ordinary attach (see Behavior). Before the first turn ends nothing is delivered.
|
|
88
|
-
|
|
89
|
-
## Behavior
|
|
90
|
-
|
|
91
|
-
**At startup** (the first `session.start`):
|
|
92
|
-
|
|
93
|
-
- Registers `/vibest-reattach` as `immediate`, so it also runs mid-turn, and one poll every 2 s.
|
|
94
|
-
- Polls never overlap, and each `vibest` call has a 15 s timeout.
|
|
95
|
-
- The first poll runs `vibest inbox attach <session id>`, without replace.
|
|
96
|
-
- If attach answers `not-reported` (exit 0, that error alone, no generation), nothing was attached: the status line says
|
|
97
|
-
it is waiting, and the next poll runs the same ordinary attach again. It never adds `--replace`.
|
|
98
|
-
- Any other refusal stops polling, and the status line says what to do:
|
|
99
|
-
- `stale-receiver`: another receiver is attached;
|
|
100
|
-
- a nonzero exit: `vibest` failed or has no `inbox` command;
|
|
101
|
-
- no reply, or a reply that cannot be read or contradicts itself.
|
|
102
|
-
- Once attached, the existing bridge marker suppresses Herdr paste delivery; the Claude adapter's `inbox` is `bridge`, so without one rows are pasted.
|
|
103
|
-
|
|
104
|
-
**Each poll:**
|
|
105
|
-
|
|
106
|
-
- Reads `$.session.id()` and pulls a claim.
|
|
107
|
-
- Reads the claim body with `$.fs.read`, never from stdout, and submits it with `$.prompt.submit`.
|
|
108
|
-
- Then settles the claim:
|
|
109
|
-
|
|
110
|
-
| Submit result | Settlement |
|
|
111
|
-
|---|---|
|
|
112
|
-
| Accepted or queued | `ack`. This means delivery was accepted, not that an VIBEST task finished. |
|
|
113
|
-
| Definite `drop` | `release --retry` |
|
|
114
|
-
| Ambiguous (the submit threw) | `release` |
|
|
115
|
-
|
|
116
|
-
- A lost settlement retries the same settlement and never submits again.
|
|
117
|
-
|
|
118
|
-
**When the session ends** (`session.end`: `/clear`, resume, exit):
|
|
119
|
-
|
|
120
|
-
- Polling stops, and the status line asks for `/vibest-reattach`.
|
|
121
|
-
- The end is permanent for this receiver. Ordinary polling never undoes it. A session id read that was in flight when the
|
|
122
|
-
session ended is discarded. Only a confirmed `/vibest-reattach` starts delivery again.
|
|
123
|
-
- Callbacks still in flight from the ended session cannot settle, and cannot submit anything new.
|
|
124
|
-
|
|
125
|
-
**`/vibest-reattach`:**
|
|
126
|
-
|
|
127
|
-
- Runs `vibest inbox attach <current session id> --replace`. One reattach runs at a time. A `not-reported` answer here is
|
|
128
|
-
a refusal like any other: the inbox is unchanged.
|
|
129
|
-
- **A generation is confirmed:** it is used only if no `session.end` happened while the command waited. Polling then
|
|
130
|
-
continues under it, even if a step of the old generation is still waiting.
|
|
131
|
-
- **Old callbacks:** they cannot settle, pull or submit under the new generation. But a prompt the old generation had
|
|
132
|
-
already handed to `$.prompt.submit` may still land once.
|
|
133
|
-
- **Refusal printed by the server:** the inbox is unchanged.
|
|
134
|
-
- **No usable answer** (timeout, nonzero exit, unparsable output): the replace may have committed and retired this
|
|
135
|
-
receiver. It is reported as unknown and never replayed automatically. Run `/vibest-reattach` again.
|
|
136
|
-
|
|
137
|
-
**Not done:** a shared store, takeover after a reload, detach, leases, or recovery after a pane move. A reloaded module
|
|
138
|
-
is a new receiver: it gets `stale-receiver` until `/vibest-reattach`.
|
|
53
|
+
`claude --plugin-dir <@vibest/cli>/harnesses/claude`, which loads the plugin for that session only. vibest writes
|
|
54
|
+
nothing into `~/.claude`. Plain `claude` sessions never load it, and in a Claude process without `VIBEST_AGENT` and
|
|
55
|
+
`VIBEST_SESSION_ID` every listener returns `next` and sends nothing.
|
|
56
|
+
|
|
57
|
+
**Mods are not sandboxed.** The module is code that Claude Code runs in its own process with your permissions. What it
|
|
58
|
+
does is narrow: POST to the fixed vibestd socket and submit the inbox line as a prompt. Its `tool.call` listener only
|
|
59
|
+
refuses; it registers no `tool.check` approval and changes no permission or policy setting. A module that does not
|
|
60
|
+
load guards nothing: with no `--settings`, the guard rules hold only while this module runs.
|
|
61
|
+
|
|
62
|
+
**`/clear`.** Claude Code 2.1.316 changes `$.session.id()` on `/clear`, fires `session.end` for the old id and no new
|
|
63
|
+
`session.start`; the poll timer keeps running. The plugin therefore has no `session.end` handler and sends the
|
|
64
|
+
current id on every request, and vibestd records the new id on the next request.
|
|
65
|
+
|
|
66
|
+
**Loading gate.** Claude Code statically analyzes a hooks module before loading it: `register` stays a top-level
|
|
67
|
+
`function` declaration and each hook passes `$` only to the top-level `nativeHost`. Hooks modules must be enabled for
|
|
68
|
+
non-builtin plugins (in 2.1.309 the rollout flag `tengu_plugin_hooks_modules` and accepted workspace trust); the plugin
|
|
69
|
+
does not read or change either. The AbovePrompt drain needs an interactive UI: under `claude -p` nothing is delivered.
|
|
139
70
|
|
|
140
71
|
## API source
|
|
141
72
|
|
|
@@ -149,9 +80,9 @@ The pin is anthropics/claude-code `2eff7a8d21c80be48904f62ebdea36d945d7b504`, `m
|
|
|
149
80
|
under Anthropic's commercial terms. This repository does not assert permission to redistribute it, and a missing or
|
|
150
81
|
unverified cache fails typecheck instead of skipping the plugin project. The cache was not produced by running Claude or `/plugin-types`.
|
|
151
82
|
|
|
152
|
-
The listeners are `
|
|
153
|
-
|
|
154
|
-
`$.
|
|
83
|
+
The listeners are `session.start`, `ui.render` (AbovePrompt), `turn.complete`, `prompt.submit` and `tool.call`. Native
|
|
84
|
+
calls stay in `register` or the top-level `nativeHost`: `$.http.fetch`, `$.session.cwd`, `$.session.id`, `$.env.get`,
|
|
85
|
+
`$.prompt.submit`, `$.clock.every`, `$.clock.after`, `$.ui.invalidate`, `$.ui.status`.
|
|
155
86
|
|
|
156
87
|
Hooks modules are early access and may change between releases. `claude plugin validate` and `claude plugin test` have
|
|
157
88
|
not been run on this revision. The E2E check I4 loads it with `--plugin-dir` into a real Claude: the guard refuses and the
|