@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 CHANGED
@@ -1,11 +1,88 @@
1
1
  # @opencode-cockpit/protocol
2
2
 
3
- Wire protocol for cockpitd: JSON-RPC 2.0 over NDJSON on a unix socket. Zod schemas for every method and event, error codes, filesystem layout and the daemon build id. No runtime I/O beyond path and hash helpers.
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
- Part of [opencode-cockpit](https://github.com/Codestz/opencode-cockpit). Install the plugin, not this package, unless you are building your own front end:
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
- ```sh
8
- opencode plugin opencode-cockpit --global
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
- Requires Bun 1.3.5 (OpenCode's embedded runtime qualifies). License: MIT.
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
@@ -3,7 +3,7 @@
3
3
  /** Bump MAJOR on breaking changes to methods, events or framing. */
4
4
  export const PROTOCOL_VERSION = {
5
5
  major: 1,
6
- minor: 3
6
+ minor: 4
7
7
  };
8
8
  export const ErrorCode = {
9
9
  ParseError: -32700,
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencode-cockpit/protocol",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Wire protocol, method and event contracts for cockpitd (opencode-cockpit)",
5
5
  "type": "module",
6
6
  "license": "MIT",
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
@@ -2,7 +2,7 @@
2
2
  /** Bump MAJOR on breaking changes to methods, events or framing. */
3
3
  export declare const PROTOCOL_VERSION: {
4
4
  readonly major: 1;
5
- readonly minor: 3;
5
+ readonly minor: 4;
6
6
  };
7
7
  export type RequestId = number | string;
8
8
  export interface RpcRequest {
@@ -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;
@@ -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<{