@vibest/cli 0.0.0 → 0.0.1-beta.10

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 iamdin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/bin/vibest.cjs ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ // npm entry point: runs the compiled vibest binary from the platform package, @vibest/cli-<platform>-<arch>.
3
+ const childProcess = require("node:child_process")
4
+ const os = require("node:os")
5
+ const path = require("node:path")
6
+
7
+ const target = `${process.platform}-${process.arch}`
8
+ let binary
9
+ try {
10
+ binary = require.resolve(`@vibest/cli-${target}/bin/vibest`)
11
+ } catch {
12
+ console.error(`vibest: no binary for ${target} (reinstall @vibest/cli without --omit=optional)`)
13
+ process.exit(1)
14
+ }
15
+
16
+ // vibest's plugin for each harness ships in this package (scripts/build-harnesses.ts); the binary passes it to each harness it starts.
17
+ const env = { ...process.env, VIBEST_HARNESSES: path.join(__dirname, "..", "harnesses") }
18
+ const child = childProcess.spawn(binary, process.argv.slice(2), { stdio: "inherit", env })
19
+ // The terminal already delivers Ctrl-C to the child (same process group); forwarding it as well would turn one Ctrl-C into two.
20
+ process.on("SIGINT", () => {})
21
+ for (const signal of ["SIGTERM", "SIGHUP"]) process.on(signal, () => child.kill(signal))
22
+ child.on("error", (error) => {
23
+ console.error(`vibest: cannot run ${binary}: ${error.message}`)
24
+ process.exit(1)
25
+ })
26
+ child.on("exit", (code, signal) => {
27
+ if (!signal) process.exit(code ?? 1)
28
+ // Die of the same signal, so the caller sees what the binary saw; Node ignores some (SIGPIPE), so exit as a shell reports it.
29
+ process.removeAllListeners(signal)
30
+ process.kill(process.pid, signal)
31
+ process.exit(128 + os.constants.signals[signal])
32
+ })
@@ -0,0 +1,10 @@
1
+ {
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, with /vibest-reattach",
4
+ "author": {
5
+ "name": "iamdin"
6
+ },
7
+ "repository": "https://github.com/iamdin/orchestrate-my-agent-cli",
8
+ "license": "MIT",
9
+ "version": "0.0.1-beta.10"
10
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 iamdin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,158 @@
1
+ # @vibest/claude: the vibest Claude Code plugin
2
+
3
+ One ordinary Claude Code plugin with two parts:
4
+
5
+ - **Native classic listeners** for every VIBEST session, workers and the coordinator: `classic.Stop` and
6
+ `classic.StopFailure` report the turn end (a worker's result, or the coordinator's Claude session) by running
7
+ `vibest integration stop --harness claude`, and `classic.PreToolUse` runs `vibest integration guard --harness claude`. These are native event names, not
8
+ command-hook registrations.
9
+ - **The inbox module**, for a Claude **coordinator** only: it delivers VIBEST inbox claims into the coordinator as prompts,
10
+ through the native hooks API.
11
+
12
+ It ships inside `@vibest/cli` and is loaded only into the Claude sessions vibest starts (see Use).
13
+
14
+ ## Build
15
+
16
+ This package is private: the plugin is published as part of `@vibest/cli`, whose build writes it to
17
+ `apps/vibest-herdr/harnesses/claude` (`scripts/build-harnesses.ts`).
18
+
19
+ bun scripts/build.ts <outdir> # the complete plugin directory in <outdir>
20
+ bun run build # the generated files in place, for the tests
21
+
22
+ The plugin directory holds exactly:
23
+
24
+ - `.claude-plugin/plugin.json`, generated: `src/manifest.json` with `version` set from this `package.json`.
25
+ - `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` together with the
27
+ client (`src/inbox-client.ts`) and the adapters (`src/inbox-adapter.ts`) it uses. The native `classic.*` listeners are
28
+ in that module. Prebuilt JS is a delivery choice; Claude Code can also load TypeScript hooks modules.
29
+ - `README.md` and `LICENSE`.
30
+
31
+ The generated files are ignored by Git. `test/distribution.test.ts` packs this package and checks the extracted files.
32
+
33
+ ## Use
34
+
35
+ 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, beside the plugins
37
+ the user installed. vibest writes nothing into `~/.claude`. Plain `claude` sessions never load it.
38
+
39
+ **The `vibest` it calls is the one on PATH.** The module calls the bare `vibest`: `vibest inbox …` for the inbox, and
40
+ `vibest integration stop --harness claude` / `vibest integration guard --harness claude` for the native listeners. There
41
+ is no shell and no `VIBEST_COMMAND` override.
42
+
43
+ **Mods are not sandboxed.** The inbox module is a mod, code that Claude Code runs in its own process with your permissions.
44
+ Its own `$.fs` and `$.process` calls do not go through Claude's tool permission rules or `PreToolUse` hooks, and a
45
+ process it starts runs outside the Bash sandbox. What it intends to do is narrow: run the fixed bare argv `vibest inbox attach|pull|ack|release …`,
46
+ `vibest integration stop --harness claude` and `vibest integration guard --harness claude`, read the claim file `vibest inbox pull` names, and submit that text
47
+ as a prompt. The
48
+ module registers no `tool.call` interception, no `tool.check` approval, and changes no permission or policy setting.
49
+ `classic.PreToolUse` is a native listener in this module. It is not the settings.json command hook.
50
+
51
+ **Where it acts.** The plugin loads only into the Claude sessions vibest starts. The native listeners are always registered there.
52
+ `classic.PreToolUse` calls vibest only when `VIBEST_AGENT` is set; `classic.Stop` and `classic.StopFailure` call vibest only
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`.
139
+
140
+ ## API source
141
+
142
+ `src/plugin.ts` imports types from `claude-code`. Those declarations are not in this repository. `bun scripts/prepare-claude-types.ts`,
143
+ which `pnpm run typecheck` runs before the plugin project (`tsconfig.plugin.json`), writes an ignored cache at
144
+ `packages/integration/claude/.cache/claude-code.d.ts`. A cold cache needs network access to GitHub.
145
+ It reuses that file only when its SHA-256 is `e51e637fbbebb2a6a49c4bdc3860a251c2ca2295884822dff0f4c3e3ec802163`, including a copy placed there by hand for offline use. Otherwise it fetches
146
+ `https://raw.githubusercontent.com/anthropics/claude-code/2eff7a8d21c80be48904f62ebdea36d945d7b504/mods/types/claude-code.d.ts` and keeps the result only when that checksum matches.
147
+ The pin is anthropics/claude-code `2eff7a8d21c80be48904f62ebdea36d945d7b504`, `mods/types/claude-code.d.ts`. The file's own
148
+ "Written by Claude Code 2.1.277" header is stale and does not date that pin. Upstream marks the file all rights reserved
149
+ under Anthropic's commercial terms. This repository does not assert permission to redistribute it, and a missing or
150
+ unverified cache fails typecheck instead of skipping the plugin project. The cache was not produced by running Claude or `/plugin-types`.
151
+
152
+ The listeners are `classic.Stop`, `classic.StopFailure`, `classic.PreToolUse`, `session.start`, `session.end` and
153
+ `command.run`. Native calls stay in `register` or the top-level `nativeHost`: `$.process.run`, `$.session.cwd`,
154
+ `$.session.id`, `$.env.get`, `$.fs.read`, `$.prompt.submit`, `$.command.register`, `$.clock.every`, `$.ui.status`.
155
+
156
+ Hooks modules are early access and may change between releases. `claude plugin validate` and `claude plugin test` have
157
+ not been run on this revision. The E2E check I4 loads it with `--plugin-dir` into a real Claude: the guard refuses and the
158
+ turn end reports.
@@ -0,0 +1,6 @@
1
+ {
2
+ "description": "VIBEST: turn-end reports and the tool guard for VIBEST sessions; the coordinator inbox module",
3
+ "modules": [
4
+ "./register.mjs"
5
+ ]
6
+ }