@openvcs/sdk 0.2.3 → 0.2.5

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.
Files changed (54) hide show
  1. package/README.md +39 -3
  2. package/lib/build.d.ts +8 -0
  3. package/lib/build.js +81 -2
  4. package/lib/dist.js +1 -0
  5. package/lib/init.d.ts +2 -0
  6. package/lib/init.js +7 -4
  7. package/lib/runtime/contracts.d.ts +45 -0
  8. package/lib/runtime/contracts.js +4 -0
  9. package/lib/runtime/dispatcher.d.ts +16 -0
  10. package/lib/runtime/dispatcher.js +133 -0
  11. package/lib/runtime/errors.d.ts +5 -0
  12. package/lib/runtime/errors.js +26 -0
  13. package/lib/runtime/factory.d.ts +3 -0
  14. package/lib/runtime/factory.js +153 -0
  15. package/lib/runtime/host.d.ts +10 -0
  16. package/lib/runtime/host.js +48 -0
  17. package/lib/runtime/index.d.ts +10 -0
  18. package/lib/runtime/index.js +23 -0
  19. package/lib/runtime/registration.d.ts +39 -0
  20. package/lib/runtime/registration.js +37 -0
  21. package/lib/runtime/transport.d.ts +14 -0
  22. package/lib/runtime/transport.js +72 -0
  23. package/lib/types/host.d.ts +57 -0
  24. package/lib/types/host.js +4 -0
  25. package/lib/types/index.d.ts +4 -0
  26. package/lib/types/index.js +22 -0
  27. package/lib/types/plugin.d.ts +56 -0
  28. package/lib/types/plugin.js +4 -0
  29. package/lib/types/protocol.d.ts +77 -0
  30. package/lib/types/protocol.js +13 -0
  31. package/lib/types/vcs.d.ts +459 -0
  32. package/lib/types/vcs.js +4 -0
  33. package/package.json +14 -1
  34. package/src/lib/build.ts +104 -2
  35. package/src/lib/dist.ts +2 -0
  36. package/src/lib/init.ts +7 -4
  37. package/src/lib/runtime/contracts.ts +52 -0
  38. package/src/lib/runtime/dispatcher.ts +185 -0
  39. package/src/lib/runtime/errors.ts +27 -0
  40. package/src/lib/runtime/factory.ts +182 -0
  41. package/src/lib/runtime/host.ts +72 -0
  42. package/src/lib/runtime/index.ts +36 -0
  43. package/src/lib/runtime/registration.ts +93 -0
  44. package/src/lib/runtime/transport.ts +93 -0
  45. package/src/lib/types/host.ts +71 -0
  46. package/src/lib/types/index.ts +7 -0
  47. package/src/lib/types/plugin.ts +110 -0
  48. package/src/lib/types/protocol.ts +97 -0
  49. package/src/lib/types/vcs.ts +579 -0
  50. package/test/build.test.js +147 -6
  51. package/test/cli.test.js +5 -3
  52. package/test/dist.test.js +27 -18
  53. package/test/init.test.js +29 -0
  54. package/test/runtime.test.js +235 -0
@@ -0,0 +1,93 @@
1
+ // Copyright © 2025-2026 OpenVCS Contributors
2
+ // SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ import type { JsonRpcRequest } from '../types';
5
+
6
+ /** Describes the parsed result of draining one buffered transport chunk. */
7
+ export interface FramedMessageParseResult {
8
+ /** Stores the decoded requests found in the current buffer. */
9
+ messages: JsonRpcRequest[];
10
+ /** Stores any remaining incomplete bytes. */
11
+ remainder: Buffer;
12
+ }
13
+
14
+ /** Serializes one JSON-RPC payload into an LSP-style framed stdio message. */
15
+ export function serializeFramedMessage(value: unknown): Buffer {
16
+ const payload = Buffer.from(JSON.stringify(value), 'utf8');
17
+ const header = Buffer.from(`Content-Length: ${payload.length}\r\n\r\n`, 'utf8');
18
+ return Buffer.concat([header, payload]);
19
+ }
20
+
21
+ /** Writes one JSON-RPC payload to the supplied stdout-like stream. */
22
+ export async function writeFramedMessage(
23
+ writer: NodeJS.WritableStream,
24
+ value: unknown,
25
+ ): Promise<void> {
26
+ try {
27
+ const serialized = serializeFramedMessage(value);
28
+ const canContinue = writer.write(serialized);
29
+ if (!canContinue) {
30
+ await new Promise<void>((resolve) => writer.once('drain', resolve));
31
+ }
32
+ } catch (error) {
33
+ console.error(
34
+ `[transport] failed to write framed message: ${error instanceof Error ? error.message : String(error)}`,
35
+ );
36
+ }
37
+ }
38
+
39
+ /** Parses all complete framed JSON-RPC requests currently present in a buffer. */
40
+ export function parseFramedMessages(buffer: Buffer): FramedMessageParseResult {
41
+ const messages: JsonRpcRequest[] = [];
42
+ let remainder = buffer;
43
+
44
+ while (true) {
45
+ const marker = remainder.indexOf('\r\n\r\n');
46
+ if (marker < 0) {
47
+ return { messages, remainder };
48
+ }
49
+
50
+ const header = remainder.subarray(0, marker).toString('utf8');
51
+ const contentLength = readContentLength(header);
52
+ if (contentLength == null) {
53
+ remainder = remainder.subarray(marker + 4);
54
+ continue;
55
+ }
56
+
57
+ const totalLength = marker + 4 + contentLength;
58
+ if (remainder.length < totalLength) {
59
+ return { messages, remainder };
60
+ }
61
+
62
+ const payload = remainder.subarray(marker + 4, totalLength).toString('utf8');
63
+ remainder = remainder.subarray(totalLength);
64
+
65
+ try {
66
+ messages.push(JSON.parse(payload) as JsonRpcRequest);
67
+ } catch {
68
+ continue;
69
+ }
70
+ }
71
+ }
72
+
73
+ /** Reads one `Content-Length` header value from a framed message header block. */
74
+ function readContentLength(header: string): number | null {
75
+ const headerLines = header.split(/\r?\n/g);
76
+
77
+ for (const line of headerLines) {
78
+ const separatorIndex = line.indexOf(':');
79
+ if (separatorIndex < 0) {
80
+ continue;
81
+ }
82
+
83
+ const name = line.slice(0, separatorIndex).trim().toLowerCase();
84
+ if (name !== 'content-length') {
85
+ continue;
86
+ }
87
+
88
+ const rawValue = Number(line.slice(separatorIndex + 1).trim());
89
+ return Number.isFinite(rawValue) && rawValue >= 0 ? rawValue : null;
90
+ }
91
+
92
+ return null;
93
+ }
@@ -0,0 +1,71 @@
1
+ // Copyright © 2025-2026 OpenVCS Contributors
2
+ // SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ import type { JsonRpcId } from './protocol';
5
+
6
+ /** Enumerates the log levels accepted by the host log notification. */
7
+ export type HostLogLevel = 'error' | 'info';
8
+
9
+ /** Describes one `host.log` notification payload. */
10
+ export interface HostLogParams {
11
+ /** Stores the emitted log severity. */
12
+ level: HostLogLevel;
13
+ /** Stores the plugin log target name. */
14
+ target: string;
15
+ /** Stores the log message text. */
16
+ message: string;
17
+ }
18
+
19
+ /** Describes one `host.ui_notify` notification payload. */
20
+ export interface HostUiNotifyParams {
21
+ /** Stores the message shown by the host UI. */
22
+ message: string;
23
+ /** Stores an optional severity or category understood by the host. */
24
+ level?: string;
25
+ }
26
+
27
+ /** Describes one `host.status_set` notification payload. */
28
+ export interface HostStatusSetParams {
29
+ /** Stores the status text shown by the host. */
30
+ text: string;
31
+ }
32
+
33
+ /** Describes one `host.event_emit` notification payload. */
34
+ export interface HostEventEmitParams {
35
+ /** Stores the plugin-defined event name. */
36
+ name: string;
37
+ /** Stores the event payload forwarded to the host. */
38
+ payload?: Record<string, unknown>;
39
+ }
40
+
41
+ /** Describes one `vcs.event` notification payload. */
42
+ export interface VcsEventParams {
43
+ /** Stores the repository session id associated with the event. */
44
+ session_id: string;
45
+ /** Stores the originating request id when one exists. */
46
+ request_id: JsonRpcId | null;
47
+ /** Stores the event payload. */
48
+ event: Record<string, unknown>;
49
+ }
50
+
51
+ /** Describes the host helper API available inside delegate handlers. */
52
+ export interface PluginHost {
53
+ /** Emits a `host.log` notification. */
54
+ log(level: HostLogLevel, message: string): void;
55
+ /** Emits an informational `host.log` notification. */
56
+ info(message: string): void;
57
+ /** Emits an error `host.log` notification. */
58
+ error(message: string): void;
59
+ /** Emits a `host.ui_notify` notification. */
60
+ uiNotify(params: HostUiNotifyParams): void;
61
+ /** Emits a `host.status_set` notification. */
62
+ statusSet(params: HostStatusSetParams): void;
63
+ /** Emits a `host.event_emit` notification. */
64
+ emitEvent(params: HostEventEmitParams): void;
65
+ /** Emits a `vcs.event` notification. */
66
+ emitVcsEvent(
67
+ sessionId: string,
68
+ requestId: JsonRpcId | null,
69
+ event: Record<string, unknown>,
70
+ ): void;
71
+ }
@@ -0,0 +1,7 @@
1
+ // Copyright © 2025-2026 OpenVCS Contributors
2
+ // SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ export * from './host';
5
+ export * from './plugin';
6
+ export * from './protocol';
7
+ export * from './vcs';
@@ -0,0 +1,110 @@
1
+ // Copyright © 2025-2026 OpenVCS Contributors
2
+ // SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ import type { RequestParams, RpcMethodHandler } from './protocol';
5
+
6
+ /** Describes the capability flags reported during plugin initialization. */
7
+ export interface PluginImplements {
8
+ /** Indicates whether the plugin responds to `plugin.*` methods. */
9
+ plugin: boolean;
10
+ /** Indicates whether the plugin responds to `vcs.*` methods. */
11
+ vcs: boolean;
12
+ }
13
+
14
+ /** Describes the handshake payload returned from `plugin.initialize`. */
15
+ export interface PluginInitializeResult {
16
+ /** Stores the SDK protocol version mirrored from the host. */
17
+ protocol_version: number;
18
+ /** Stores the feature groups implemented by the plugin. */
19
+ implements: PluginImplements;
20
+ }
21
+
22
+ /** Describes one optional override returned by a custom initialize handler. */
23
+ export type PluginInitializeOverride = Partial<PluginInitializeResult>;
24
+
25
+ /** Describes one plugin-contributed menu definition. */
26
+ export type PluginMenuDefinition = Record<string, unknown>;
27
+
28
+ /** Describes one plugin settings value payload. */
29
+ export type PluginSettingsValue = Record<string, unknown>;
30
+
31
+ /** Describes the params shape for plugin action handling. */
32
+ export interface PluginHandleActionParams extends RequestParams {
33
+ /** Stores the action id selected by the user. */
34
+ action_id?: string;
35
+ }
36
+
37
+ /** Describes the params shape for plugin settings callbacks. */
38
+ export interface PluginSettingsValuesParams extends RequestParams {
39
+ /** Stores the list of values supplied by the host. */
40
+ values?: unknown[];
41
+ }
42
+
43
+ /** Enumerates all host `plugin.*` method names. */
44
+ export type PluginMethodName =
45
+ | 'plugin.initialize'
46
+ | 'plugin.init'
47
+ | 'plugin.deinit'
48
+ | 'plugin.get_menus'
49
+ | 'plugin.handle_action'
50
+ | 'plugin.settings.defaults'
51
+ | 'plugin.settings.on_load'
52
+ | 'plugin.settings.on_apply'
53
+ | 'plugin.settings.on_save'
54
+ | 'plugin.settings.on_reset';
55
+
56
+ /** Describes the delegate map supported by the SDK runtime for `plugin.*`. */
57
+ export interface PluginDelegates<TContext = unknown> {
58
+ /** Overrides the default handshake payload returned by `plugin.initialize`. */
59
+ 'plugin.initialize'?: RpcMethodHandler<
60
+ RequestParams,
61
+ PluginInitializeOverride,
62
+ TContext
63
+ >;
64
+ /** Handles plugin startup work. */
65
+ 'plugin.init'?: RpcMethodHandler<RequestParams, null, TContext>;
66
+ /** Handles plugin shutdown work. */
67
+ 'plugin.deinit'?: RpcMethodHandler<RequestParams, null, TContext>;
68
+ /** Returns plugin-contributed menus. */
69
+ 'plugin.get_menus'?: RpcMethodHandler<
70
+ RequestParams,
71
+ PluginMenuDefinition[],
72
+ TContext
73
+ >;
74
+ /** Handles a contributed plugin action. */
75
+ 'plugin.handle_action'?: RpcMethodHandler<
76
+ PluginHandleActionParams,
77
+ null,
78
+ TContext
79
+ >;
80
+ /** Returns the default settings values for the plugin. */
81
+ 'plugin.settings.defaults'?: RpcMethodHandler<
82
+ RequestParams,
83
+ PluginSettingsValue[],
84
+ TContext
85
+ >;
86
+ /** Transforms settings values when they are loaded. */
87
+ 'plugin.settings.on_load'?: RpcMethodHandler<
88
+ PluginSettingsValuesParams,
89
+ unknown[],
90
+ TContext
91
+ >;
92
+ /** Applies settings values to the running plugin. */
93
+ 'plugin.settings.on_apply'?: RpcMethodHandler<
94
+ PluginSettingsValuesParams,
95
+ null,
96
+ TContext
97
+ >;
98
+ /** Transforms settings values before they are saved. */
99
+ 'plugin.settings.on_save'?: RpcMethodHandler<
100
+ PluginSettingsValuesParams,
101
+ unknown[],
102
+ TContext
103
+ >;
104
+ /** Resets plugin settings state. */
105
+ 'plugin.settings.on_reset'?: RpcMethodHandler<
106
+ PluginSettingsValuesParams,
107
+ null,
108
+ TContext
109
+ >;
110
+ }
@@ -0,0 +1,97 @@
1
+ // Copyright © 2025-2026 OpenVCS Contributors
2
+ // SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ /** Stores the protocol version mirrored from the backend host contract. */
5
+ export const PROTOCOL_VERSION = 1;
6
+
7
+ /** Stores the reserved JSON-RPC error code used for plugin failures. */
8
+ export const PLUGIN_FAILURE_CODE = -32001;
9
+
10
+ /** Stores the reserved JSON-RPC error code used for uncaught plugin errors. */
11
+ export const PLUGIN_INTERNAL_ERROR_CODE = -32002;
12
+
13
+ /** Stores the reserved JSON-RPC error code used for protocol version mismatches. */
14
+ export const PROTOCOL_VERSION_MISMATCH_CODE = -32003;
15
+
16
+ /** Represents a JSON-RPC request identifier. */
17
+ export type JsonRpcId = number | string;
18
+
19
+ /** Represents an untyped JSON-RPC parameter object. */
20
+ export type RequestParams = Record<string, unknown>;
21
+
22
+ /** Describes one JSON-RPC error payload. */
23
+ export interface JsonRpcError {
24
+ /** Stores the machine-readable error code. */
25
+ code: number;
26
+ /** Stores the human-readable error message. */
27
+ message: string;
28
+ /** Stores optional structured error details. */
29
+ data?: unknown;
30
+ }
31
+
32
+ /** Describes one JSON-RPC request received from the host. */
33
+ export interface JsonRpcRequest {
34
+ /** Stores the JSON-RPC protocol marker when present. */
35
+ jsonrpc?: string;
36
+ /** Stores the request identifier used to match responses. */
37
+ id?: JsonRpcId;
38
+ /** Stores the requested method name. */
39
+ method?: unknown;
40
+ /** Stores the untyped parameter payload. */
41
+ params?: unknown;
42
+ }
43
+
44
+ /** Describes one JSON-RPC notification emitted without an id. */
45
+ export interface JsonRpcNotification {
46
+ /** Stores the JSON-RPC protocol marker. */
47
+ jsonrpc: '2.0';
48
+ /** Stores the notification method name. */
49
+ method: string;
50
+ /** Stores the notification payload. */
51
+ params?: unknown;
52
+ }
53
+
54
+ /** Describes one JSON-RPC success response. */
55
+ export interface JsonRpcSuccessResponse<TResult = unknown> {
56
+ /** Stores the JSON-RPC protocol marker. */
57
+ jsonrpc: '2.0';
58
+ /** Stores the request identifier being answered. */
59
+ id: JsonRpcId;
60
+ /** Stores the successful result payload. */
61
+ result: TResult;
62
+ }
63
+
64
+ /** Describes one JSON-RPC error response. */
65
+ export interface JsonRpcErrorResponse {
66
+ /** Stores the JSON-RPC protocol marker. */
67
+ jsonrpc: '2.0';
68
+ /** Stores the request identifier being answered. */
69
+ id: JsonRpcId;
70
+ /** Stores the structured error payload. */
71
+ error: JsonRpcError;
72
+ }
73
+
74
+ /** Describes one plugin-specific failure payload surfaced to the host. */
75
+ export interface PluginFailure {
76
+ /** Stores the reserved JSON-RPC error code for plugin failures. */
77
+ code: typeof PLUGIN_FAILURE_CODE;
78
+ /** Stores the top-level failure message. */
79
+ message: string;
80
+ /** Stores nested plugin-specific failure details. */
81
+ data: PluginFailureData;
82
+ }
83
+
84
+ /** Describes the structured data embedded in a plugin failure. */
85
+ export interface PluginFailureData {
86
+ /** Stores the stable plugin-specific error code. */
87
+ code: string;
88
+ /** Stores the user-facing failure message. */
89
+ message: string;
90
+ }
91
+
92
+ /** Describes one method handler used by the SDK delegate runtime. */
93
+ export type RpcMethodHandler<
94
+ TParams extends RequestParams = RequestParams,
95
+ TResult = unknown,
96
+ TContext = unknown,
97
+ > = (params: TParams, context: TContext) => TResult | Promise<TResult>;