@anynotate/protocol 0.2.0 → 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/PROTOCOL.md CHANGED
@@ -1,12 +1,12 @@
1
- # Anynotate protocol v1
1
+ # Anynotate protocol v2
2
2
 
3
3
  The bridge is an HTTP server on `127.0.0.1`, port `47291` by default (`ANYNOTATE_PORT`). Clients send annotation **bundles**; the bridge stores each one as a folder and delivers it to an AI agent session. Constants and schemas live in `@anynotate/protocol`; request/response examples for the extension-facing endpoints live in `@anynotate/protocol/fixtures` (`conformance`).
4
4
 
5
5
  ## Handshake
6
6
 
7
- `POST /health` (or `GET`) → `{ "ok": true, "bridgeVersion": "0.2.0", "protocol": { "version": 1, "min": 1 } }`.
7
+ `POST /health` (or `GET`) → `{ "ok": true, "bridgeVersion": "0.3.0", "protocol": { "version": 2, "min": 1 } }`.
8
8
 
9
- A client supports a range of protocol versions (the extension: `min 1, max 1`) and calls `compatibility(clientRange, response.protocol)`:
9
+ A client supports a range of protocol versions (the extension: `min 2, max 2`) and calls `compatibility(clientRange, response.protocol)`:
10
10
 
11
11
  - `ok` — the ranges overlap; proceed.
12
12
  - `bridge-too-old` — ask the user to update the bridge; don't send.
@@ -66,12 +66,29 @@ Each bundle is written to `$ANYNOTATE_HOME/inbox/<id>/` (default `~/.anynotate`)
66
66
 
67
67
  `$ANYNOTATE_HOME/inbox/latest` points at the newest bundle.
68
68
 
69
+ ## Intents
70
+
71
+ Each annotation may carry an `intent` telling the agent what the user wants. `INTENTS` lists the current ones; `README.md` puts a directive line under the note's heading instead of naming the intent:
72
+
73
+ | `intent` | Directive in `README.md` |
74
+ |---|---|
75
+ | `explain` | `**Explain** this.` |
76
+ | `change` | `**Change requested.**` |
77
+ | `approve` | `**Approved** — no change needed.` |
78
+
79
+ The v1 values `question`, `bug` and `note` are still accepted and appear in the heading as before, with no directive line. `change` was also a v1 value; it keeps its name and now gets the directive line. No `intent` means no directive either.
80
+
69
81
  ## Evolution
70
82
 
71
83
  - Additive changes — optional fields, new endpoints — keep `PROTOCOL_VERSION`. Both sides ignore fields they don't know.
72
84
  - Removing, renaming or changing the meaning of anything bumps `PROTOCOL_VERSION`; the bridge keeps accepting the previous version (`PROTOCOL_MIN`) for at least one release.
73
85
  - The bundle format has its own `v` (currently `1`); the agent-facing `README.md` stays human-readable.
74
86
 
87
+ ### Version history
88
+
89
+ - **v1** — handshake, token-only access, native-host token delivery.
90
+ - **v2** — intents `explain`, `change`, `approve` (legacy `question`, `bug`, `note` still accepted). `PROTOCOL_MIN` stays `1`: a v2 bridge accepts v1 clients.
91
+
75
92
  ## Threat model
76
93
 
77
94
  - **Web pages** can reach `127.0.0.1` from the user's browser. They are refused by `Origin` (including preflights), and DNS-rebinding pages by `Host`; a web request without an `Origin` (such as an `<img>` GET) fails the token check.
@@ -67,8 +67,10 @@ export declare const responseSchemas: {
67
67
  }>;
68
68
  comment: z.ZodString;
69
69
  intent: z.ZodOptional<z.ZodEnum<{
70
- question: "question";
70
+ explain: "explain";
71
71
  change: "change";
72
+ approve: "approve";
73
+ question: "question";
72
74
  bug: "bug";
73
75
  note: "note";
74
76
  }>>;
package/dist/fixtures.js CHANGED
@@ -11,7 +11,7 @@ export const exampleBundleInput = {
11
11
  target: { agent: "claude", sessionId: "s-1", cwd: "/tmp/repo" },
12
12
  overall: "can we make this vegan?",
13
13
  annotations: [{
14
- id: "A1", kind: "text", comment: "is there a substitute for cream?", intent: "question",
14
+ id: "A1", kind: "text", comment: "is there a substitute for cream?", intent: "explain",
15
15
  anchor: {
16
16
  quote: { exact: "200 ml cream", prefix: "stir in ", suffix: " before serving" },
17
17
  css: "section#ingredients > li:nth-child(3)", path: ["main", "section#ingredients", "ul"], near: "Ingredients",
@@ -25,7 +25,7 @@ export const examplePage = "# Tomato soup\n\nstir in ⟦A1⟧200 ml cream before
25
25
  export const responseSchemas = {
26
26
  HealthResponse, SessionsResponse, SendResponse, BundleStatusResponse, OkResponse, ErrorResponse,
27
27
  };
28
- const health = { ok: true, bridgeVersion: "0.2.0", protocol: { version: 1, min: 1 } };
28
+ const health = { ok: true, bridgeVersion: "0.3.0", protocol: { version: 2, min: 1 } };
29
29
  const queued = { state: "queued", at: "2026-09-24T15:32:01.000Z" };
30
30
  const exampleBundle = { ...exampleBundleInput, id: EXAMPLE_BUNDLE_ID, files: { page: "page.md", screenshot: "screenshot.png" } };
31
31
  export const conformance = [
package/dist/index.d.ts CHANGED
@@ -2,6 +2,10 @@ import { z } from "zod";
2
2
  export declare const AGENT_NAME: RegExp;
3
3
  export declare const Agent: z.ZodString;
4
4
  export type Agent = z.infer<typeof Agent>;
5
+ export declare const INTENTS: readonly ["explain", "change", "approve"];
6
+ export declare const LEGACY_INTENTS: readonly ["question", "bug", "note"];
7
+ /** The intent clients should send; parsed annotations may also hold a LEGACY_INTENTS value. */
8
+ export type Intent = (typeof INTENTS)[number];
5
9
  export declare const Annotation: z.ZodObject<{
6
10
  id: z.ZodString;
7
11
  kind: z.ZodEnum<{
@@ -10,8 +14,10 @@ export declare const Annotation: z.ZodObject<{
10
14
  }>;
11
15
  comment: z.ZodString;
12
16
  intent: z.ZodOptional<z.ZodEnum<{
13
- question: "question";
17
+ explain: "explain";
14
18
  change: "change";
19
+ approve: "approve";
20
+ question: "question";
15
21
  bug: "bug";
16
22
  note: "note";
17
23
  }>>;
@@ -80,8 +86,10 @@ export declare const BundleInput: z.ZodObject<{
80
86
  }>;
81
87
  comment: z.ZodString;
82
88
  intent: z.ZodOptional<z.ZodEnum<{
83
- question: "question";
89
+ explain: "explain";
84
90
  change: "change";
91
+ approve: "approve";
92
+ question: "question";
85
93
  bug: "bug";
86
94
  note: "note";
87
95
  }>>;
@@ -145,8 +153,10 @@ export declare const Bundle: z.ZodObject<{
145
153
  }>;
146
154
  comment: z.ZodString;
147
155
  intent: z.ZodOptional<z.ZodEnum<{
148
- question: "question";
156
+ explain: "explain";
149
157
  change: "change";
158
+ approve: "approve";
159
+ question: "question";
150
160
  bug: "bug";
151
161
  note: "note";
152
162
  }>>;
@@ -234,7 +244,7 @@ export declare const Session: z.ZodObject<{
234
244
  sessionIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
235
245
  }, z.core.$strip>;
236
246
  export type Session = z.infer<typeof Session>;
237
- export declare const PROTOCOL_VERSION = 1;
247
+ export declare const PROTOCOL_VERSION = 2;
238
248
  export declare const PROTOCOL_MIN = 1;
239
249
  export declare const HealthResponse: z.ZodObject<{
240
250
  ok: z.ZodLiteral<true>;
@@ -301,8 +311,10 @@ export declare const BundleStatusResponse: z.ZodObject<{
301
311
  }>;
302
312
  comment: z.ZodString;
303
313
  intent: z.ZodOptional<z.ZodEnum<{
304
- question: "question";
314
+ explain: "explain";
305
315
  change: "change";
316
+ approve: "approve";
317
+ question: "question";
306
318
  bug: "bug";
307
319
  note: "note";
308
320
  }>>;
package/dist/index.js CHANGED
@@ -1,13 +1,15 @@
1
1
  import { z } from "zod";
2
2
  export const AGENT_NAME = /^[a-z][a-z0-9_-]{0,31}$/;
3
3
  export const Agent = z.string().regex(AGENT_NAME);
4
+ export const INTENTS = ["explain", "change", "approve"];
5
+ export const LEGACY_INTENTS = ["question", "bug", "note"];
4
6
  const Box = z.object({ x: z.number(), y: z.number(), w: z.number(), h: z.number() });
5
7
  export const Annotation = z.object({
6
8
  id: z.string().regex(/^A\d+$/),
7
9
  // v1 kinds only; "region" | "draw" are reserved for later tools.
8
10
  kind: z.enum(["text", "element"]),
9
11
  comment: z.string(),
10
- intent: z.enum(["question", "change", "bug", "note"]).optional(),
12
+ intent: z.enum([...INTENTS, ...LEGACY_INTENTS]).optional(),
11
13
  anchor: z.object({
12
14
  quote: z.object({ exact: z.string(), prefix: z.string(), suffix: z.string() }).optional(),
13
15
  position: z.object({ start: z.number().int(), end: z.number().int() }).optional(),
@@ -68,9 +70,9 @@ export const Session = z.object({
68
70
  pane: z.string().optional(),
69
71
  sessionIds: z.array(z.string()).optional(),
70
72
  });
71
- // Protocol v1. Additive changes (optional fields, new endpoints) keep the version; removals, renames and
73
+ // Protocol v2. Additive changes (optional fields, new endpoints) keep the version; removals, renames and
72
74
  // semantic changes bump PROTOCOL_VERSION, and the bridge keeps accepting the previous version for a release.
73
- export const PROTOCOL_VERSION = 1;
75
+ export const PROTOCOL_VERSION = 2;
74
76
  export const PROTOCOL_MIN = 1;
75
77
  export const HealthResponse = z.object({
76
78
  ok: z.literal(true),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anynotate/protocol",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Wire types and zod schemas shared by Anynotate clients and the Anynotate bridge.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Kun Xu",
package/src/fixtures.ts CHANGED
@@ -16,7 +16,7 @@ export const exampleBundleInput: BundleInput = {
16
16
  target: { agent: "claude", sessionId: "s-1", cwd: "/tmp/repo" },
17
17
  overall: "can we make this vegan?",
18
18
  annotations: [{
19
- id: "A1", kind: "text", comment: "is there a substitute for cream?", intent: "question",
19
+ id: "A1", kind: "text", comment: "is there a substitute for cream?", intent: "explain",
20
20
  anchor: {
21
21
  quote: { exact: "200 ml cream", prefix: "stir in ", suffix: " before serving" },
22
22
  css: "section#ingredients > li:nth-child(3)", path: ["main", "section#ingredients", "ul"], near: "Ingredients",
@@ -49,7 +49,7 @@ export type Exchange = {
49
49
  response: { schema: SchemaName; example: unknown };
50
50
  };
51
51
 
52
- const health = { ok: true, bridgeVersion: "0.2.0", protocol: { version: 1, min: 1 } };
52
+ const health = { ok: true, bridgeVersion: "0.3.0", protocol: { version: 2, min: 1 } };
53
53
  const queued = { state: "queued", at: "2026-09-24T15:32:01.000Z" };
54
54
  const exampleBundle = { ...exampleBundleInput, id: EXAMPLE_BUNDLE_ID, files: { page: "page.md", screenshot: "screenshot.png" } };
55
55
 
package/src/index.ts CHANGED
@@ -4,6 +4,11 @@ export const AGENT_NAME = /^[a-z][a-z0-9_-]{0,31}$/;
4
4
  export const Agent = z.string().regex(AGENT_NAME);
5
5
  export type Agent = z.infer<typeof Agent>;
6
6
 
7
+ export const INTENTS = ["explain", "change", "approve"] as const;
8
+ export const LEGACY_INTENTS = ["question", "bug", "note"] as const;
9
+ /** The intent clients should send; parsed annotations may also hold a LEGACY_INTENTS value. */
10
+ export type Intent = (typeof INTENTS)[number];
11
+
7
12
  const Box = z.object({ x: z.number(), y: z.number(), w: z.number(), h: z.number() });
8
13
 
9
14
  export const Annotation = z.object({
@@ -11,7 +16,7 @@ export const Annotation = z.object({
11
16
  // v1 kinds only; "region" | "draw" are reserved for later tools.
12
17
  kind: z.enum(["text", "element"]),
13
18
  comment: z.string(),
14
- intent: z.enum(["question", "change", "bug", "note"]).optional(),
19
+ intent: z.enum([...INTENTS, ...LEGACY_INTENTS]).optional(),
15
20
  anchor: z.object({
16
21
  quote: z.object({ exact: z.string(), prefix: z.string(), suffix: z.string() }).optional(),
17
22
  position: z.object({ start: z.number().int(), end: z.number().int() }).optional(),
@@ -87,9 +92,9 @@ export const Session = z.object({
87
92
  });
88
93
  export type Session = z.infer<typeof Session>;
89
94
 
90
- // Protocol v1. Additive changes (optional fields, new endpoints) keep the version; removals, renames and
95
+ // Protocol v2. Additive changes (optional fields, new endpoints) keep the version; removals, renames and
91
96
  // semantic changes bump PROTOCOL_VERSION, and the bridge keeps accepting the previous version for a release.
92
- export const PROTOCOL_VERSION = 1;
97
+ export const PROTOCOL_VERSION = 2;
93
98
  export const PROTOCOL_MIN = 1;
94
99
 
95
100
  export const HealthResponse = z.object({