dsh-cursor-subscription 0.5.3

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/lib/proto.js ADDED
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Minimal protobuf wire-format helpers for the Cursor Agent protocol.
3
+ *
4
+ * Only the subset of protobuf needed by `dsh-cursor-subscription` is
5
+ * implemented: varints, length-delimited fields, fixed64/double, and nested
6
+ * messages. Map fields are encoded as repeated entry messages, exactly like
7
+ * the official protobuf runtime.
8
+ *
9
+ * @module dsh-cursor-subscription/proto
10
+ */
11
+
12
+ /** Encode one unsigned varint into a Uint8Array. */
13
+ export function varintEncode(value) {
14
+ const out = [];
15
+ let n = Math.trunc(value);
16
+ while (n > 0x7f) {
17
+ out.push((n & 0x7f) | 0x80);
18
+ n = Math.floor(n / 128);
19
+ }
20
+ out.push(n);
21
+ return Uint8Array.from(out);
22
+ }
23
+
24
+ /** Combine byte arrays. */
25
+ export function concatBytes(parts) {
26
+ let total = 0;
27
+ for (const part of parts) total += part.length;
28
+ const out = new Uint8Array(total);
29
+ let offset = 0;
30
+ for (const part of parts) {
31
+ out.set(part, offset);
32
+ offset += part.length;
33
+ }
34
+ return out;
35
+ }
36
+
37
+ /** A streaming protobuf message writer. */
38
+ export class Writer {
39
+ constructor() {
40
+ this.parts = [];
41
+ }
42
+
43
+ /** Append a raw field tag. */
44
+ tag(field, wireType) {
45
+ this.parts.push(varintEncode((field << 3) | wireType));
46
+ return this;
47
+ }
48
+
49
+ /** Append a length-delimited payload. */
50
+ bytes(field, data) {
51
+ this.tag(field, 2);
52
+ this.parts.push(varintEncode(data.length));
53
+ this.parts.push(data);
54
+ return this;
55
+ }
56
+
57
+ /** Append a UTF-8 string field. */
58
+ string(field, value) {
59
+ return this.bytes(field, new TextEncoder().encode(value));
60
+ }
61
+
62
+ /** Append a nested message field. */
63
+ message(field, inner) {
64
+ return this.bytes(field, inner);
65
+ }
66
+
67
+ /** Append a varint field (uint32/int32/bool/enum). */
68
+ varint(field, value) {
69
+ this.tag(field, 0);
70
+ this.parts.push(varintEncode(Math.trunc(value)));
71
+ return this;
72
+ }
73
+
74
+ /** Append a double (fixed64, little-endian) field. */
75
+ double(field, value) {
76
+ this.tag(field, 1);
77
+ const buffer = new ArrayBuffer(8);
78
+ new DataView(buffer).setFloat64(0, value, true);
79
+ this.parts.push(new Uint8Array(buffer));
80
+ return this;
81
+ }
82
+
83
+ finish() {
84
+ return concatBytes(this.parts);
85
+ }
86
+ }
87
+
88
+ /** A streaming protobuf message reader. */
89
+ export class Reader {
90
+ constructor(bytes) {
91
+ this.data = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
92
+ this.pos = 0;
93
+ }
94
+
95
+ get done() {
96
+ return this.pos >= this.data.length;
97
+ }
98
+
99
+ varint() {
100
+ let result = 0;
101
+ let shift = 0;
102
+ while (true) {
103
+ if (this.pos >= this.data.length) throw new Error("protobuf: truncated varint");
104
+ const byte = this.data[this.pos++];
105
+ result += (byte & 0x7f) * 2 ** shift;
106
+ if ((byte & 0x80) === 0) break;
107
+ shift += 7;
108
+ if (shift > 63) throw new Error("protobuf: varint too long");
109
+ }
110
+ return result;
111
+ }
112
+
113
+ /** Read the tag and return { field, wireType }. */
114
+ tag() {
115
+ const raw = this.varint();
116
+ return { field: Math.floor(raw / 8), wireType: raw % 8 };
117
+ }
118
+
119
+ bytes() {
120
+ const length = this.varint();
121
+ if (this.pos + length > this.data.length) throw new Error("protobuf: truncated bytes");
122
+ const out = this.data.subarray(this.pos, this.pos + length);
123
+ this.pos += length;
124
+ return out;
125
+ }
126
+
127
+ string() {
128
+ return new TextDecoder().decode(this.bytes());
129
+ }
130
+
131
+ double() {
132
+ if (this.pos + 8 > this.data.length) throw new Error("protobuf: truncated double");
133
+ const view = new DataView(this.data.buffer, this.data.byteOffset + this.pos, 8);
134
+ this.pos += 8;
135
+ return view.getFloat64(0, true);
136
+ }
137
+
138
+ /** Skip a field of the given wire type (length-delimited or varint or fixed64). */
139
+ skip(wireType) {
140
+ if (wireType === 0) {
141
+ this.varint();
142
+ } else if (wireType === 1) {
143
+ if (this.pos + 8 > this.bytes.length) throw new Error("protobuf: truncated fixed64");
144
+ this.pos += 8;
145
+ } else if (wireType === 2) {
146
+ this.bytes();
147
+ } else if (wireType === 5) {
148
+ if (this.pos + 4 > this.bytes.length) throw new Error("protobuf: truncated fixed32");
149
+ this.pos += 4;
150
+ } else {
151
+ throw new Error(`protobuf: unsupported wire type ${wireType}`);
152
+ }
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Encode a JSON value as `google.protobuf.Value` (the wire format Cursor uses
158
+ * for MCP tool input schemas and MCP argument values).
159
+ */
160
+ export function encodeValue(value) {
161
+ const writer = new Writer();
162
+ if (value === null || value === undefined) {
163
+ writer.varint(1, 0); // null_value
164
+ } else if (typeof value === "boolean") {
165
+ writer.varint(4, value ? 1 : 0); // bool_value
166
+ } else if (typeof value === "number") {
167
+ writer.double(2, value); // number_value
168
+ } else if (typeof value === "string") {
169
+ writer.string(3, value); // string_value
170
+ } else if (Array.isArray(value)) {
171
+ const list = new Writer();
172
+ for (const item of value) list.message(1, encodeValue(item)); // ListValue.values
173
+ writer.message(6, list.finish()); // list_value
174
+ } else if (typeof value === "object") {
175
+ const struct = new Writer();
176
+ for (const [key, item] of Object.entries(value)) {
177
+ const entry = new Writer();
178
+ entry.string(1, key); // Struct.FieldsEntry.key
179
+ entry.message(2, encodeValue(item)); // Struct.FieldsEntry.value
180
+ struct.message(1, entry.finish()); // Struct.fields
181
+ }
182
+ writer.message(5, struct.finish()); // struct_value
183
+ } else {
184
+ throw new Error(`cannot encode ${typeof value} as google.protobuf.Value`);
185
+ }
186
+ return writer.finish();
187
+ }
188
+
189
+ /**
190
+ * Decode `google.protobuf.Value` bytes back into a JSON value.
191
+ * @param {Uint8Array} bytes - serialized google.protobuf.Value message.
192
+ * @returns {unknown} the decoded JSON value.
193
+ */
194
+ export function decodeValue(bytes) {
195
+ const reader = new Reader(bytes);
196
+ while (!reader.done) {
197
+ const { field, wireType } = reader.tag();
198
+ if (field === 1 && wireType === 0) {
199
+ reader.varint();
200
+ return null;
201
+ }
202
+ if (field === 2 && wireType === 1) {
203
+ return reader.double();
204
+ }
205
+ if (field === 3 && wireType === 2) {
206
+ return reader.string();
207
+ }
208
+ if (field === 4 && wireType === 0) {
209
+ return reader.varint() !== 0;
210
+ }
211
+ if (field === 5 && wireType === 2) {
212
+ return decodeStruct(reader.bytes());
213
+ }
214
+ if (field === 6 && wireType === 2) {
215
+ return decodeList(reader.bytes());
216
+ }
217
+ reader.skip(wireType);
218
+ }
219
+ return null;
220
+ }
221
+
222
+ function decodeStruct(bytes) {
223
+ const reader = new Reader(bytes);
224
+ const result = {};
225
+ while (!reader.done) {
226
+ const { field, wireType } = reader.tag();
227
+ if (field === 1 && wireType === 2) {
228
+ const entry = new Reader(reader.bytes());
229
+ let key = "";
230
+ let value = null;
231
+ while (!entry.done) {
232
+ const tag = entry.tag();
233
+ if (tag.field === 1 && tag.wireType === 2) key = entry.string();
234
+ else if (tag.field === 2 && tag.wireType === 2) value = decodeValue(entry.bytes());
235
+ else entry.skip(tag.wireType);
236
+ }
237
+ result[key] = value;
238
+ } else {
239
+ reader.skip(wireType);
240
+ }
241
+ }
242
+ return result;
243
+ }
244
+
245
+ function decodeList(bytes) {
246
+ const reader = new Reader(bytes);
247
+ const result = [];
248
+ while (!reader.done) {
249
+ const { field, wireType } = reader.tag();
250
+ if (field === 1 && wireType === 2) result.push(decodeValue(reader.bytes()));
251
+ else reader.skip(wireType);
252
+ }
253
+ return result;
254
+ }
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "dsh-cursor-subscription",
3
+ "version": "0.5.3",
4
+ "packageManager": "pnpm@11.19.0",
5
+ "description": "Cursor subscription for DeepSeek Harness with browser login, token refresh, model discovery, and the Cursor Agent chat protocol",
6
+ "type": "module",
7
+ "main": "./lib/index.js",
8
+ "exports": {
9
+ ".": "./lib/index.js",
10
+ "./client": "./lib/client.js",
11
+ "./proto": "./lib/proto.js",
12
+ "./cordis.patch.yml": "./cordis.patch.yml",
13
+ "./package.json": "./package.json"
14
+ },
15
+ "files": [
16
+ "lib/*.js",
17
+ "cordis.patch.yml",
18
+ "README.md",
19
+ "README_zh.md",
20
+ "AGENTS.md",
21
+ "LICENSE"
22
+ ],
23
+ "dsh": {
24
+ "bundle": {
25
+ "patch": "./cordis.patch.yml"
26
+ },
27
+ "client": {
28
+ "inject": [
29
+ "@deepseek-ai/dsh-client-connection",
30
+ "@deepseek-ai/dsh-client-locale",
31
+ "@deepseek-ai/dsh-client-runtime",
32
+ "@deepseek-ai/dsh-client-ui-settings",
33
+ "@deepseek-ai/dsh-client-ui-tool"
34
+ ],
35
+ "platform": "web"
36
+ }
37
+ },
38
+ "scripts": {
39
+ "test": "node --test tests/*.test.mjs"
40
+ },
41
+ "keywords": [
42
+ "dsh-plugin",
43
+ "deepseek",
44
+ "deepseek-harness",
45
+ "dsh",
46
+ "cursor",
47
+ "cursor-agent",
48
+ "subscription",
49
+ "oauth",
50
+ "pkce"
51
+ ],
52
+ "author": "dsh-cursor-subscription contributors",
53
+ "license": "MIT",
54
+ "engines": {
55
+ "node": "^22.19.0 || >=24.0.0"
56
+ },
57
+ "peerDependencies": {
58
+ "@deepseek-ai/cordis": "4.0.1",
59
+ "@deepseek-ai/dsh-client-connection": "0.1.0-rc.6",
60
+ "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6",
61
+ "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6",
62
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6",
63
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.6",
64
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6",
65
+ "@deepseek-ai/dsh-client-ui-tool": "0.1.0-rc.6",
66
+ "@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
67
+ "@deepseek-ai/dsh-llm": "^0.1.2-rc.1",
68
+ "@deepseek-ai/dsh-settings": "0.1.0-rc.6",
69
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.6",
70
+ "@deepseek-ai/schemastery": "^3.18.1",
71
+ "react": "^18.2.0"
72
+ }
73
+ }
74
+