@opencode-cockpit/protocol 0.2.1 → 0.3.0
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/README.md +82 -5
- package/dist/daemon.js +6 -1
- package/dist/rpc.js +1 -1
- package/dist/shell/params.js +7 -0
- package/package.json +1 -1
- package/types/daemon.d.ts +2 -0
- package/types/index.d.ts +3 -0
- package/types/rpc.d.ts +1 -1
- package/types/shell/contract.d.ts +2 -0
- package/types/shell/params.d.ts +2 -0
package/README.md
CHANGED
|
@@ -1,11 +1,88 @@
|
|
|
1
1
|
# @opencode-cockpit/protocol
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**The contract between `cockpitd` and everything that talks to it.** Zod schemas for every method
|
|
4
|
+
and event, the types generated from them, the socket paths, the framing, and the build identity used
|
|
5
|
+
to decide which daemon should be running.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Client and daemon import the *same* file, so a change to a shape is a compile error on both sides
|
|
8
|
+
rather than a runtime surprise in one of them.
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
> Installing the plugin is what you usually want. This package matters if you are writing a
|
|
11
|
+
> capability, or a client of your own.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What is in it
|
|
16
|
+
|
|
17
|
+
| Export | What it gives you |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `contract`, `Methods`, `MethodName` | Every method, its params and its result |
|
|
20
|
+
| `events`, `Events`, `Topic` | Every event topic and its payload |
|
|
21
|
+
| `PROTOCOL_VERSION` | `{ major, minor }` — the wire version |
|
|
22
|
+
| `shell` | The shell capability's schemas: `ShellInfo`, `StartParams`, `WatchRule`, `ReadResult`, … |
|
|
23
|
+
| `resolvePaths`, `CockpitPaths` | Where the socket, logs and registry live |
|
|
24
|
+
| `daemonBuildId` | Content identity of a daemon build |
|
|
25
|
+
| `encodeFrame`, `decodeFrames` | NDJSON framing |
|
|
26
|
+
| `RpcError`, `ErrorCode` | The error shape both sides speak |
|
|
27
|
+
|
|
28
|
+
## The shape of a call
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { contract, shell } from "@opencode-cockpit/protocol"
|
|
32
|
+
|
|
33
|
+
// Every method is params → result, both zod schemas:
|
|
34
|
+
contract["shell.start"].params // StartParams
|
|
35
|
+
contract["shell.start"].result // ShellInfo
|
|
36
|
+
|
|
37
|
+
// Schemas are usable on their own, so a UI can parse what it receives:
|
|
38
|
+
const info = shell.ShellInfo.parse(payload)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Requests and responses are JSON-RPC 2.0, one object per line (NDJSON) over a unix socket. Events are
|
|
42
|
+
notifications, delivered only to peers subscribed to the topic.
|
|
43
|
+
|
|
44
|
+
## Versioning
|
|
45
|
+
|
|
46
|
+
`PROTOCOL_VERSION` is `major.minor`:
|
|
47
|
+
|
|
48
|
+
- **Minor** goes up when something is added — a new method, a new optional field. Old clients keep
|
|
49
|
+
working, so a daemon may serve a client that predates the addition.
|
|
50
|
+
- **Major** goes up when something existing changes meaning or disappears. A mismatch is refused at
|
|
51
|
+
the handshake with a message naming both versions, instead of failing halfway through a call.
|
|
52
|
+
|
|
53
|
+
The handshake carries the version, so both ends know where they stand before any work starts.
|
|
54
|
+
|
|
55
|
+
## Build identity
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { daemonBuildId } from "@opencode-cockpit/protocol"
|
|
59
|
+
|
|
60
|
+
daemonBuildId(entry, version) // → "0.2.1+4eac93214393"
|
|
9
61
|
```
|
|
10
62
|
|
|
11
|
-
|
|
63
|
+
A hash of the daemon's own files plus its version. Equal versions with different hashes are how a
|
|
64
|
+
development build is recognised as newer than the daemon already running — which is what lets a
|
|
65
|
+
plugin under active work replace an idle daemon without a version bump.
|
|
66
|
+
|
|
67
|
+
## Adding a method
|
|
68
|
+
|
|
69
|
+
1. Add the schema to the capability's contract file (`src/shell/contract.ts`, or a new namespace).
|
|
70
|
+
2. Bump `PROTOCOL_VERSION.minor`.
|
|
71
|
+
3. Implement the handler in the daemon module — it is typed from the contract, so a missing or
|
|
72
|
+
mis-shaped handler will not compile.
|
|
73
|
+
4. Call it from the client. No client-side wiring: `call` picks up the new name.
|
|
74
|
+
|
|
75
|
+
Schemas are split by concern rather than piled into one file — for shell that is `common`, `info`,
|
|
76
|
+
`params`, `watch` and `contract` — so a capability's surface stays readable as it grows.
|
|
77
|
+
|
|
78
|
+
## Requirements
|
|
79
|
+
|
|
80
|
+
Bun ≥ 1.3.5 or Node ≥ 20 for the schemas alone. Runs anywhere zod runs.
|
|
81
|
+
|
|
82
|
+
## More
|
|
83
|
+
|
|
84
|
+
[Architecture](https://codestz.github.io/opencode-cockpit/platform/architecture/) ·
|
|
85
|
+
[Daemon](../daemon) · [Client](../client) ·
|
|
86
|
+
[Repository](https://github.com/Codestz/opencode-cockpit)
|
|
87
|
+
|
|
88
|
+
MIT
|
package/dist/daemon.js
CHANGED
|
@@ -3,7 +3,12 @@ import { method } from "./contract.js";
|
|
|
3
3
|
export const ClientInfo = z.object({
|
|
4
4
|
name: z.string().min(1),
|
|
5
5
|
version: z.string().min(1),
|
|
6
|
-
pid: z.number().int().optional()
|
|
6
|
+
pid: z.number().int().optional(),
|
|
7
|
+
/**
|
|
8
|
+
* Opaque id of the OpenCode window this client belongs to. Both halves of a plugin share one, so
|
|
9
|
+
* the daemon can tell "this window went away" from "one of its two connections dropped".
|
|
10
|
+
*/
|
|
11
|
+
instance: z.string().min(1).optional()
|
|
7
12
|
});
|
|
8
13
|
export const Version = z.object({
|
|
9
14
|
major: z.number().int(),
|
package/dist/rpc.js
CHANGED
package/dist/shell/params.js
CHANGED
|
@@ -20,6 +20,13 @@ export const StartParams = z.object({
|
|
|
20
20
|
idleTimeoutMs: z.number().int().positive().optional(),
|
|
21
21
|
/** Also write the clean log to a file, for debugging after the buffer has evicted old lines. */
|
|
22
22
|
logFile: z.boolean().default(false),
|
|
23
|
+
/** Stop this shell when the OpenCode window that started it goes away. */
|
|
24
|
+
stopOnExit: z.boolean().optional(),
|
|
25
|
+
/**
|
|
26
|
+
* Stop it after this long with nothing from its window connected. The answer to a shell that
|
|
27
|
+
* would otherwise run for a week because everyone who knew about it has gone.
|
|
28
|
+
*/
|
|
29
|
+
orphanAfterMs: z.number().int().positive().optional(),
|
|
23
30
|
/**
|
|
24
31
|
* Restart a finished shell with the same command, args, cwd, project and session instead of
|
|
25
32
|
* creating a new one. Repeated runs then share one id and one log.
|
package/package.json
CHANGED
package/types/daemon.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export declare const ClientInfo: z.ZodObject<{
|
|
|
3
3
|
name: z.ZodString;
|
|
4
4
|
version: z.ZodString;
|
|
5
5
|
pid: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
instance: z.ZodOptional<z.ZodString>;
|
|
6
7
|
}, z.core.$strip>;
|
|
7
8
|
export declare const Version: z.ZodObject<{
|
|
8
9
|
major: z.ZodNumber;
|
|
@@ -34,6 +35,7 @@ export declare const daemonContract: {
|
|
|
34
35
|
name: z.ZodString;
|
|
35
36
|
version: z.ZodString;
|
|
36
37
|
pid: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
instance: z.ZodOptional<z.ZodString>;
|
|
37
39
|
}, z.core.$strip>;
|
|
38
40
|
protocol: z.ZodObject<{
|
|
39
41
|
major: z.ZodNumber;
|
package/types/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare const contract: {
|
|
|
12
12
|
name: import("zod").ZodString;
|
|
13
13
|
version: import("zod").ZodString;
|
|
14
14
|
pid: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
15
|
+
instance: import("zod").ZodOptional<import("zod").ZodString>;
|
|
15
16
|
}, import("zod/v4/core").$strip>;
|
|
16
17
|
protocol: import("zod").ZodObject<{
|
|
17
18
|
major: import("zod").ZodNumber;
|
|
@@ -68,6 +69,8 @@ export declare const contract: {
|
|
|
68
69
|
timeoutMs: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
69
70
|
idleTimeoutMs: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
70
71
|
logFile: import("zod").ZodDefault<import("zod").ZodBoolean>;
|
|
72
|
+
stopOnExit: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
73
|
+
orphanAfterMs: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
71
74
|
reuse: import("zod").ZodDefault<import("zod").ZodBoolean>;
|
|
72
75
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
73
76
|
id: import("zod").ZodString;
|
package/types/rpc.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export declare const shellContract: {
|
|
|
16
16
|
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
17
17
|
idleTimeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
18
18
|
logFile: z.ZodDefault<z.ZodBoolean>;
|
|
19
|
+
stopOnExit: z.ZodOptional<z.ZodBoolean>;
|
|
20
|
+
orphanAfterMs: z.ZodOptional<z.ZodNumber>;
|
|
19
21
|
reuse: z.ZodDefault<z.ZodBoolean>;
|
|
20
22
|
}, z.core.$strip>, z.ZodObject<{
|
|
21
23
|
id: z.ZodString;
|
package/types/shell/params.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export declare const StartParams: z.ZodObject<{
|
|
|
15
15
|
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
16
16
|
idleTimeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
17
17
|
logFile: z.ZodDefault<z.ZodBoolean>;
|
|
18
|
+
stopOnExit: z.ZodOptional<z.ZodBoolean>;
|
|
19
|
+
orphanAfterMs: z.ZodOptional<z.ZodNumber>;
|
|
18
20
|
reuse: z.ZodDefault<z.ZodBoolean>;
|
|
19
21
|
}, z.core.$strip>;
|
|
20
22
|
export declare const ClearParams: z.ZodDefault<z.ZodObject<{
|