@vibecontrols/plugin-sdk 2026.509.1
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 +22 -0
- package/README.md +206 -0
- package/boilerplate/.github/workflows/release.template.yml +57 -0
- package/boilerplate/README.md +41 -0
- package/boilerplate/bunfig.toml +13 -0
- package/boilerplate/eslint.config.base.js +36 -0
- package/boilerplate/lefthook.base.yml +10 -0
- package/boilerplate/package.template.json +52 -0
- package/boilerplate/tsconfig.base.json +20 -0
- package/dist/audit/index.d.ts +17 -0
- package/dist/audit/index.js +19 -0
- package/dist/broadcast/index.d.ts +15 -0
- package/dist/broadcast/index.js +14 -0
- package/dist/cli/index.d.ts +75 -0
- package/dist/cli/index.js +104 -0
- package/dist/config/index.d.ts +34 -0
- package/dist/config/index.js +66 -0
- package/dist/contract/index.d.ts +118 -0
- package/dist/contract/index.js +16 -0
- package/dist/http/index.d.ts +35 -0
- package/dist/http/index.js +70 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +595 -0
- package/dist/lifecycle/index.d.ts +31 -0
- package/dist/lifecycle/index.js +30 -0
- package/dist/log/index.d.ts +22 -0
- package/dist/log/index.js +25 -0
- package/dist/providers/index.d.ts +29 -0
- package/dist/providers/index.js +38 -0
- package/dist/routes/index.d.ts +37 -0
- package/dist/routes/index.js +77 -0
- package/dist/storage/index.d.ts +36 -0
- package/dist/storage/index.js +67 -0
- package/dist/subprocess/index.d.ts +37 -0
- package/dist/subprocess/index.js +69 -0
- package/dist/telemetry/index.d.ts +27 -0
- package/dist/telemetry/index.js +41 -0
- package/dist/testing/index.d.ts +31 -0
- package/dist/testing/index.js +97 -0
- package/package.json +159 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Burdenoff Consultancy Services Pvt. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the proprietary
|
|
6
|
+
property of Burdenoff Consultancy Services Pvt. Ltd. and its affiliates.
|
|
7
|
+
|
|
8
|
+
UNAUTHORIZED COPYING, MODIFICATION, DISTRIBUTION, OR USE OF THIS SOFTWARE, VIA ANY
|
|
9
|
+
MEDIUM, IS STRICTLY PROHIBITED.
|
|
10
|
+
|
|
11
|
+
The Software is provided under a proprietary license. You may use the Software only in
|
|
12
|
+
accordance with the terms of your license agreement with Burdenoff Consultancy Services
|
|
13
|
+
Pvt. Ltd.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
16
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
17
|
+
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
|
19
|
+
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
20
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
|
|
22
|
+
For licensing inquiries, contact: contact@vibecontrols.com
|
package/README.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# @vibecontrols/plugin-sdk
|
|
2
|
+
|
|
3
|
+
Shared contract, lifecycle, CLI, telemetry, storage, and HTTP helpers consumed by every `@vibecontrols/vibe-plugin-*` package and by the agent itself.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @vibecontrols/plugin-sdk
|
|
9
|
+
# or
|
|
10
|
+
npm install @vibecontrols/plugin-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Modules
|
|
14
|
+
|
|
15
|
+
Granular subpath imports so plugins tree-shake aggressively. The most-used helpers are also re-exported from the root barrel `@vibecontrols/plugin-sdk`.
|
|
16
|
+
|
|
17
|
+
### `contract` — types
|
|
18
|
+
|
|
19
|
+
The plugin contract v2 surface. `VibePlugin`, `HostServices`, `PluginCapabilities`, `Prerequisite`, `StorageProvider`, `ServiceRegistry`, plus `FULL_TRUST_CAPS`. Every host-side field is optional so plugins keep working against partial hosts.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import type { VibePluginFactory, VibePlugin } from "@vibecontrols/plugin-sdk/contract";
|
|
23
|
+
|
|
24
|
+
export const createPlugin: VibePluginFactory = (ctx) => ({
|
|
25
|
+
name: "demo",
|
|
26
|
+
version: "1.0.0",
|
|
27
|
+
capabilities: { storage: "rw", telemetry: true },
|
|
28
|
+
tags: ["backend"],
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### `lifecycle` — boilerplate-free init / shutdown
|
|
33
|
+
|
|
34
|
+
`createLifecycleHooks` collapses `onServerStart` / `onServerStop` boilerplate, emits a one-shot `<plugin>.ready` telemetry event, and skips on unsupported platforms.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { createLifecycleHooks } from "@vibecontrols/plugin-sdk/lifecycle";
|
|
38
|
+
|
|
39
|
+
const { onServerStart, onServerStop } = createLifecycleHooks({
|
|
40
|
+
name: "demo",
|
|
41
|
+
telemetryEventName: "demo.ready",
|
|
42
|
+
onInit: async (hostServices) => {
|
|
43
|
+
/* ... */
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### `cli` — multimode + redaction + command builder
|
|
49
|
+
|
|
50
|
+
`runMultimode<T>` selects between JSON / plain / interactive renderers from a single `fetchData` call. `redact(value)` strips secrets recursively. `CliCommandBuilder` registers status sub-commands with `--json` / `--plain` baked in.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { CliCommandBuilder, redact } from "@vibecontrols/plugin-sdk/cli";
|
|
54
|
+
|
|
55
|
+
new CliCommandBuilder(program).addStatusCommand("status", {
|
|
56
|
+
description: "Show plugin status",
|
|
57
|
+
fetchData: () => fetchStatus(),
|
|
58
|
+
redact: true,
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### `routes` — Elysia fluent builder
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { RoutesBuilder } from "@vibecontrols/plugin-sdk/routes";
|
|
66
|
+
|
|
67
|
+
const app = new RoutesBuilder("demo", hostServices)
|
|
68
|
+
.withPrefix("/api/demo")
|
|
69
|
+
.withAuth(() => process.env.AGENT_API_KEY ?? "")
|
|
70
|
+
.withErrorHandler()
|
|
71
|
+
.withLogging()
|
|
72
|
+
.build();
|
|
73
|
+
|
|
74
|
+
app.get("/ping", () => ({ ok: true }));
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `telemetry` — auto-tagged emitter
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { TelemetryEmitter } from "@vibecontrols/plugin-sdk/telemetry";
|
|
81
|
+
|
|
82
|
+
const tel = new TelemetryEmitter("demo", "1.0.0", hostServices);
|
|
83
|
+
tel.emitReady({ port: 3005 });
|
|
84
|
+
tel.emitError(new Error("boom"));
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### `log` — source-bound logger
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { BoundLogger } from "@vibecontrols/plugin-sdk/log";
|
|
91
|
+
|
|
92
|
+
const log = new BoundLogger(hostServices.logger, "demo");
|
|
93
|
+
log.info("started", { port: 3005 });
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### `storage` — typed JSON-encoded helpers
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { TypedStore, NamespaceStore } from "@vibecontrols/plugin-sdk/storage";
|
|
100
|
+
|
|
101
|
+
const ns = new NamespaceStore(hostServices.storage!, "demo");
|
|
102
|
+
const settings = ns.typed<{ enabled: boolean }>("settings");
|
|
103
|
+
await settings.set({ enabled: true });
|
|
104
|
+
const current = await settings.get();
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### `config` — env + host config + defaults
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { ConfigManager } from "@vibecontrols/plugin-sdk/config";
|
|
111
|
+
|
|
112
|
+
const cfg = new ConfigManager("demo", hostServices, hostServices.logger);
|
|
113
|
+
const port = (await cfg.getInt("port", 3005))!;
|
|
114
|
+
const apiKey = await cfg.getRequired("api_key"); // throws if missing
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### `subprocess` — cross-platform process helpers
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import {
|
|
121
|
+
gracefulKill,
|
|
122
|
+
isProcessAlive,
|
|
123
|
+
findAvailablePort,
|
|
124
|
+
sleep,
|
|
125
|
+
} from "@vibecontrols/plugin-sdk/subprocess";
|
|
126
|
+
|
|
127
|
+
const port = await findAvailablePort(7000);
|
|
128
|
+
await gracefulKill(child.pid, 3000);
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `http` — HttpClient with retries + timeout
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { HttpClient } from "@vibecontrols/plugin-sdk/http";
|
|
135
|
+
|
|
136
|
+
const client = new HttpClient("https://api.example.com", { timeoutMs: 5000 });
|
|
137
|
+
const data = await client.get<{ ok: boolean }>("/v1/status");
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### `providers` — ProviderRegistry façade
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { ProviderRegistry } from "@vibecontrols/plugin-sdk/providers";
|
|
144
|
+
|
|
145
|
+
const reg = new ProviderRegistry(hostServices);
|
|
146
|
+
reg.registerProvider("tunnel", "cloudflare", myCloudflareProvider);
|
|
147
|
+
const all = reg.listProviders("tunnel");
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### `audit` — bound source emitter
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { AuditLogger } from "@vibecontrols/plugin-sdk/audit";
|
|
154
|
+
|
|
155
|
+
const audit = new AuditLogger("demo", hostServices);
|
|
156
|
+
audit.emit("started", { port: 3005 });
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `broadcast` — typed WebSocket emitter
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import { BroadcastEmitter } from "@vibecontrols/plugin-sdk/broadcast";
|
|
163
|
+
|
|
164
|
+
new BroadcastEmitter(hostServices).broadcast("demo.event", { count: 1 });
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### `testing` — Bun-mock factories
|
|
168
|
+
|
|
169
|
+
Run with `bun test` (depends on the runtime `bun:test` import).
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import { createMockHostServices, createMockProfileContext } from "@vibecontrols/plugin-sdk/testing";
|
|
173
|
+
|
|
174
|
+
const hs = createMockHostServices({ getAgentVersion: () => "test" });
|
|
175
|
+
const ctx = createMockProfileContext();
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Compatibility Matrix
|
|
179
|
+
|
|
180
|
+
| SDK version | Agent version | Plugin contract |
|
|
181
|
+
| ------------ | -------------- | --------------------------- |
|
|
182
|
+
| `2026.509.x` | `>=2026.509.1` | v2 (`createPlugin` factory) |
|
|
183
|
+
|
|
184
|
+
## Boilerplate
|
|
185
|
+
|
|
186
|
+
Downstream plugins can extend the shared configs in `boilerplate/`:
|
|
187
|
+
|
|
188
|
+
- `tsconfig.base.json` — strict TS + ESM
|
|
189
|
+
- `eslint.config.base.js` — no-any, no-eslint-disable, max-warnings 0
|
|
190
|
+
- `lefthook.base.yml` — pre-push sanity gate
|
|
191
|
+
- `bunfig.toml` — Verdaccio scope wiring
|
|
192
|
+
- `.github/workflows/release.template.yml` — CalVer publish pipeline
|
|
193
|
+
- `package.template.json` — minimal starter package.json
|
|
194
|
+
|
|
195
|
+
See `templates/plugin-scaffold.md` for the recommended layout.
|
|
196
|
+
|
|
197
|
+
## Contributing
|
|
198
|
+
|
|
199
|
+
1. `bun install`
|
|
200
|
+
2. `bun run sanity` must be green (0 errors, 0 warnings)
|
|
201
|
+
3. Trunk-based: `main` only. CalVer release via `gh workflow run release.yml -f version=YYYY.MDD.PATCH`.
|
|
202
|
+
4. Spec: `~/products/vibecontrols/vibecontrols-specs/architecture/PLUGIN_SDK_EXTRACTION.md`
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
Proprietary — Burdenoff Consultancy Services Pvt. Ltd. See `LICENSE`.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Release — publish a vibe-plugin-* package to npmjs (public) + Verdaccio.
|
|
2
|
+
#
|
|
3
|
+
# Trigger: workflow_dispatch (manual version) or CalVer git-tag push.
|
|
4
|
+
# Replace `@vibecontrols/vibe-plugin-EXAMPLE` with the real package name.
|
|
5
|
+
|
|
6
|
+
name: Release
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
tags:
|
|
11
|
+
- "[0-9][0-9][0-9][0-9].[0-9]*.[0-9]*"
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
inputs:
|
|
14
|
+
version:
|
|
15
|
+
description: "CalVer version (YYYY.MDD.PATCH). Leave empty to auto-compute."
|
|
16
|
+
required: false
|
|
17
|
+
type: string
|
|
18
|
+
|
|
19
|
+
concurrency:
|
|
20
|
+
group: release
|
|
21
|
+
cancel-in-progress: false
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
release:
|
|
25
|
+
name: Release to npmjs + Verdaccio
|
|
26
|
+
runs-on: org-runners
|
|
27
|
+
timeout-minutes: 15
|
|
28
|
+
permissions:
|
|
29
|
+
contents: write
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v5
|
|
32
|
+
with:
|
|
33
|
+
fetch-depth: 0
|
|
34
|
+
- uses: oven-sh/setup-bun@v2
|
|
35
|
+
with:
|
|
36
|
+
bun-version-file: .bun-version
|
|
37
|
+
- name: Configure Verdaccio scoped registry
|
|
38
|
+
run: |
|
|
39
|
+
AUTH=$(echo -n "ci-publisher:${{ secrets.VERDACCIO_CI_PASSWORD }}" | base64)
|
|
40
|
+
cat > bunfig.toml << EOF
|
|
41
|
+
[install]
|
|
42
|
+
exact = true
|
|
43
|
+
[install.scopes]
|
|
44
|
+
vibecontrols = { token = "${AUTH}", url = "https://verdaccio.tooling.internal.burdenoff.com/" }
|
|
45
|
+
burdenoff = { token = "${AUTH}", url = "https://verdaccio.tooling.internal.burdenoff.com/" }
|
|
46
|
+
EOF
|
|
47
|
+
- run: bun install --frozen-lockfile
|
|
48
|
+
- run: bun run sanity
|
|
49
|
+
- run: bun run build
|
|
50
|
+
- name: Publish to npmjs
|
|
51
|
+
run: |
|
|
52
|
+
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPMJS_VIBECONTROLS_TOKEN }}" > ~/.npmrc
|
|
53
|
+
bunx npm publish --access public
|
|
54
|
+
- name: Publish to Verdaccio
|
|
55
|
+
run: |
|
|
56
|
+
echo "//verdaccio.tooling.internal.burdenoff.com/:_authToken=$(echo -n 'ci-publisher:${{ secrets.VERDACCIO_CI_PASSWORD }}' | base64)" > ~/.npmrc
|
|
57
|
+
bunx npm publish --registry https://verdaccio.tooling.internal.burdenoff.com/
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Plugin Boilerplate
|
|
2
|
+
|
|
3
|
+
Extends-able starters for `@vibecontrols/vibe-plugin-*` packages. Copy or extend from a downstream plugin's config files:
|
|
4
|
+
|
|
5
|
+
| File | Purpose |
|
|
6
|
+
| ---------------------------------------- | ------------------------------------------------------------------------ |
|
|
7
|
+
| `tsconfig.base.json` | Strict TS + ESM, ES2022, declaration emit. `extends` from your tsconfig. |
|
|
8
|
+
| `eslint.config.base.js` | No `any`, no `@ts-ignore`, no `eslint-disable`. Spread into your config. |
|
|
9
|
+
| `lefthook.base.yml` | Pre-push sanity gate. |
|
|
10
|
+
| `bunfig.toml` | Verdaccio scope wiring for `@burdenoff` + `@vibecontrols`. |
|
|
11
|
+
| `package.template.json` | Minimal `package.json` starter. |
|
|
12
|
+
| `.github/workflows/release.template.yml` | CalVer release pipeline (npmjs + Verdaccio). |
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
mkdir vibe-plugin-myplugin && cd vibe-plugin-myplugin
|
|
18
|
+
cp ../vibecontrols-plugin-sdk/boilerplate/package.template.json package.json
|
|
19
|
+
cp ../vibecontrols-plugin-sdk/boilerplate/bunfig.toml ./
|
|
20
|
+
cp ../vibecontrols-plugin-sdk/boilerplate/lefthook.base.yml lefthook.yml
|
|
21
|
+
mkdir -p .github/workflows
|
|
22
|
+
cp ../vibecontrols-plugin-sdk/boilerplate/.github/workflows/release.template.yml .github/workflows/release.yml
|
|
23
|
+
bun install
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Then point your `tsconfig.json` and `eslint.config.js` at the bases:
|
|
27
|
+
|
|
28
|
+
```jsonc
|
|
29
|
+
// tsconfig.json
|
|
30
|
+
{
|
|
31
|
+
"extends": "@vibecontrols/plugin-sdk/boilerplate/tsconfig.base.json",
|
|
32
|
+
"compilerOptions": { "outDir": "./dist", "noEmit": true },
|
|
33
|
+
"include": ["src/**/*", "tests/**/*"],
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
// eslint.config.js
|
|
39
|
+
import base from "@vibecontrols/plugin-sdk/boilerplate/eslint.config.base.js";
|
|
40
|
+
export default [...base];
|
|
41
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Shared bunfig.toml for vibe-plugin-* packages.
|
|
2
|
+
# Resolves @burdenoff/* and @vibecontrols/* from Verdaccio while public
|
|
3
|
+
# releases also flow through npmjs. CI may overwrite per-environment.
|
|
4
|
+
|
|
5
|
+
[install]
|
|
6
|
+
exact = true
|
|
7
|
+
|
|
8
|
+
[run]
|
|
9
|
+
shell = "bun"
|
|
10
|
+
|
|
11
|
+
[install.scopes]
|
|
12
|
+
burdenoff = { username = "ci-publisher", password = "$VERDACCIO_PASSWORD", url = "https://verdaccio.tooling.internal.burdenoff.com/" }
|
|
13
|
+
vibecontrols = { username = "ci-publisher", password = "$VERDACCIO_PASSWORD", url = "https://verdaccio.tooling.internal.burdenoff.com/" }
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Base ESLint config for vibe-plugin-* packages.
|
|
2
|
+
//
|
|
3
|
+
// Usage (downstream eslint.config.js):
|
|
4
|
+
// import base from "@vibecontrols/plugin-sdk/boilerplate/eslint.config.base.js";
|
|
5
|
+
// export default [...base, { /* per-package overrides */ }];
|
|
6
|
+
|
|
7
|
+
import js from "@eslint/js";
|
|
8
|
+
import tseslint from "typescript-eslint";
|
|
9
|
+
import globals from "globals";
|
|
10
|
+
|
|
11
|
+
export default tseslint.config(
|
|
12
|
+
{
|
|
13
|
+
ignores: ["dist/", "node_modules/", "coverage/", ".eslintcache"],
|
|
14
|
+
},
|
|
15
|
+
js.configs.recommended,
|
|
16
|
+
...tseslint.configs.recommended,
|
|
17
|
+
{
|
|
18
|
+
languageOptions: {
|
|
19
|
+
globals: {
|
|
20
|
+
...globals.node,
|
|
21
|
+
Bun: "readonly",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
rules: {
|
|
25
|
+
"@typescript-eslint/no-explicit-any": "error",
|
|
26
|
+
"@typescript-eslint/no-unused-vars": [
|
|
27
|
+
"error",
|
|
28
|
+
{
|
|
29
|
+
argsIgnorePattern: "^_",
|
|
30
|
+
varsIgnorePattern: "^_",
|
|
31
|
+
destructuredArrayIgnorePattern: "^_",
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Shared pre-push sanity gate for vibe-plugin-* packages.
|
|
2
|
+
# Install:
|
|
3
|
+
# bun add -d lefthook && bunx lefthook install
|
|
4
|
+
# Then either copy this file to lefthook.yml or extend via include.
|
|
5
|
+
|
|
6
|
+
pre-push:
|
|
7
|
+
parallel: false
|
|
8
|
+
commands:
|
|
9
|
+
sanity:
|
|
10
|
+
run: bun run sanity
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vibecontrols/vibe-plugin-EXAMPLE",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Replace with the plugin description",
|
|
6
|
+
"engines": { "bun": ">=1.3.10" },
|
|
7
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": ["dist/**/*", "!dist/**/*.map", "README.md", "LICENSE"],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"dev": "tsup --watch",
|
|
20
|
+
"lint": "eslint ./src ./tests",
|
|
21
|
+
"lint:sanity": "bun run lint -- --max-warnings 0",
|
|
22
|
+
"format": "prettier . --write",
|
|
23
|
+
"format:check": "prettier . --check",
|
|
24
|
+
"type:check": "tsc --noEmit",
|
|
25
|
+
"test": "bun test tests/**/*.test.ts",
|
|
26
|
+
"clean": "rimraf dist .eslintcache",
|
|
27
|
+
"prebuild": "bun run clean",
|
|
28
|
+
"sanity": "bun run format:check && bun run lint:sanity && bun run type:check && bun run test && bun run build"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@vibecontrols/plugin-sdk": "^2026.509.1"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@eslint/js": "^10.0.1",
|
|
35
|
+
"@types/bun": "^1.3.9",
|
|
36
|
+
"eslint": "^10.0.1",
|
|
37
|
+
"globals": "^17.3.0",
|
|
38
|
+
"prettier": "^3.8.1",
|
|
39
|
+
"rimraf": "^6.1.3",
|
|
40
|
+
"tsup": "^8.5.0",
|
|
41
|
+
"typescript": "^5.9.3",
|
|
42
|
+
"typescript-eslint": "^8.56.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"elysia": ">=1.3.0",
|
|
46
|
+
"commander": ">=14.0.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependenciesMeta": {
|
|
49
|
+
"elysia": { "optional": true },
|
|
50
|
+
"commander": { "optional": true }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"types": ["bun"],
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"noUncheckedIndexedAccess": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"declaration": true,
|
|
16
|
+
"declarationMap": false,
|
|
17
|
+
"sourceMap": true,
|
|
18
|
+
"removeComments": false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { HostServices } from '../contract/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @vibecontrols/plugin-sdk/audit
|
|
5
|
+
*
|
|
6
|
+
* `AuditLogger` binds `source` to the plugin name and forwards events to
|
|
7
|
+
* `hostServices.audit?.emit`. No-op when the host doesn't expose audit.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
declare class AuditLogger {
|
|
11
|
+
private readonly source;
|
|
12
|
+
private readonly hostServices?;
|
|
13
|
+
constructor(source: string, hostServices?: HostServices | undefined);
|
|
14
|
+
emit(event: string, payload?: Record<string, unknown>): void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { AuditLogger };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/audit/index.ts
|
|
2
|
+
var AuditLogger = class {
|
|
3
|
+
constructor(source, hostServices) {
|
|
4
|
+
this.source = source;
|
|
5
|
+
this.hostServices = hostServices;
|
|
6
|
+
}
|
|
7
|
+
source;
|
|
8
|
+
hostServices;
|
|
9
|
+
emit(event, payload) {
|
|
10
|
+
this.hostServices?.audit?.emit(event, {
|
|
11
|
+
source: this.source,
|
|
12
|
+
...payload ?? {}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export { AuditLogger };
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { HostServices } from '../contract/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @vibecontrols/plugin-sdk/broadcast
|
|
5
|
+
*
|
|
6
|
+
* Type-safe wrapper over `hostServices.broadcast` — no-op when absent.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
declare class BroadcastEmitter {
|
|
10
|
+
private readonly hostServices?;
|
|
11
|
+
constructor(hostServices?: HostServices | undefined);
|
|
12
|
+
broadcast<T>(type: string, payload: T): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { BroadcastEmitter };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/broadcast/index.ts
|
|
2
|
+
var BroadcastEmitter = class {
|
|
3
|
+
constructor(hostServices) {
|
|
4
|
+
this.hostServices = hostServices;
|
|
5
|
+
}
|
|
6
|
+
hostServices;
|
|
7
|
+
broadcast(type, payload) {
|
|
8
|
+
this.hostServices?.broadcast?.(type, payload);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { BroadcastEmitter };
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Multi-mode output dispatcher.
|
|
5
|
+
*
|
|
6
|
+
* Lifted from vibecontrols-agent/src/cli/utils/multimode.ts but trimmed:
|
|
7
|
+
* the SDK doesn't ship the agent's `isInteractive()` helper since plugins
|
|
8
|
+
* can't depend on opentui from the SDK. Instead we use a stdout-isTTY +
|
|
9
|
+
* env CI/NO_COLOR check inline.
|
|
10
|
+
*/
|
|
11
|
+
type OutputMode = "auto" | "interactive" | "plain" | "json";
|
|
12
|
+
interface OutputFlags {
|
|
13
|
+
json?: boolean;
|
|
14
|
+
plain?: boolean;
|
|
15
|
+
interactive?: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface MultimodeOptions<T> {
|
|
18
|
+
fetchData: () => Promise<T> | T;
|
|
19
|
+
plain: (data: T) => void | Promise<void>;
|
|
20
|
+
interactive?: (data: T) => Promise<void>;
|
|
21
|
+
json?: (data: T) => unknown;
|
|
22
|
+
mode?: OutputMode;
|
|
23
|
+
}
|
|
24
|
+
/** Resolve user-supplied CLI flags into an OutputMode. */
|
|
25
|
+
declare function pickOutputMode(flags: OutputFlags): OutputMode;
|
|
26
|
+
declare function runMultimode<T>(opts: MultimodeOptions<T>): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Convenience: emit `data` as JSON if `--json` is set; return `true` when
|
|
29
|
+
* something was printed. Mutating commands (start/stop/install/...) reach
|
|
30
|
+
* for this when they want a scriptable JSON opt-in.
|
|
31
|
+
*/
|
|
32
|
+
declare function maybePrintJson(flags: OutputFlags, data: unknown): boolean;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Recursive sensitive-field stripper. Replaces values for keys matching the
|
|
36
|
+
* sensitive regex with the literal string "[redacted]". Walks arrays, plain
|
|
37
|
+
* objects, and leaves primitives / null / undefined untouched.
|
|
38
|
+
*/
|
|
39
|
+
declare function redact<T>(value: T): T;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* CliCommandBuilder — fluent helper that wires the standard `--json` /
|
|
43
|
+
* `--plain` flags onto a Commander command and routes the action through
|
|
44
|
+
* `runMultimode`. Removes the ~30-line boilerplate every plugin author
|
|
45
|
+
* pastes for status/list commands.
|
|
46
|
+
*
|
|
47
|
+
* commander is a peerDep — this module imports `Command` as a *type* from
|
|
48
|
+
* "commander" so the SDK builds without commander present, and runs only
|
|
49
|
+
* when the consumer installed it.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
interface StatusCommandSpec<T> {
|
|
53
|
+
description: string;
|
|
54
|
+
fetchData: () => Promise<T> | T;
|
|
55
|
+
/** Plain renderer override. Defaults to `JSON.stringify` if absent. */
|
|
56
|
+
format?: (data: T) => void | Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Apply redaction before any renderer. Strips sensitive keys recursively
|
|
59
|
+
* (see ./redaction.ts).
|
|
60
|
+
*/
|
|
61
|
+
redact?: boolean;
|
|
62
|
+
}
|
|
63
|
+
declare class CliCommandBuilder {
|
|
64
|
+
private readonly program;
|
|
65
|
+
constructor(program: Command);
|
|
66
|
+
/**
|
|
67
|
+
* Register a `<name>` sub-command that fetches once and renders via
|
|
68
|
+
* `--json` / `--plain` / interactive (when stdout is a TTY).
|
|
69
|
+
*/
|
|
70
|
+
addStatusCommand<T>(name: string, spec: StatusCommandSpec<T>): this;
|
|
71
|
+
/** Escape hatch: hand back the underlying commander Command. */
|
|
72
|
+
command(): Command;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { CliCommandBuilder, type MultimodeOptions, type OutputFlags, type OutputMode, type StatusCommandSpec, maybePrintJson, pickOutputMode, redact, runMultimode };
|