@ai-matrx/desktop-protocol 0.3.0 → 0.5.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/dist/index.d.cts CHANGED
@@ -1,13 +1,19 @@
1
1
  import { z } from 'zod';
2
- export { B as BEARER_PREFIX, e as CancelMsg, f as ClientToCoreMsg, C as ClientType, g as CloseCode, h as CloseCodeValue, j as CoreToClientMsg, k as CreditMsg, D as DesktopProtocolError, d as EVENTS, l as EndMsg, E as EndReason, m as ErrorCode, n as ErrorCodeName, o as ErrorData, p as ErrorMsg, q as ErrorReason, r as ErrorReasonName, s as EventMsg, t as EventName, H as HelloMsg, L as Limits, N as NAMED_SCHEMAS, u as NamedSchemaId, c as OPS, v as OpDescriptor, O as OpName, a as OpParams, b as OpResult, w as OpSpec, P as PING_TEXT, x as PONG_TEXT, y as ProtocolErrorBody, R as RelayMsg, z as RequestMsg, A as ResponseMsg, F as SUBPROTOCOL, S as StreamMeta, G as StreamMsg, W as Welcome, i as isDesktopProtocolError } from './registry-DQ5_mP_5.cjs';
2
+ import { O as OpName } from './registry-BeY9D7h0.cjs';
3
+ export { B as BEARER_PREFIX, e as CancelMsg, f as ClientToCoreMsg, C as ClientType, g as CloseCode, h as CloseCodeValue, j as CoreToClientMsg, k as CreditMsg, D as DesktopProtocolError, d as EVENTS, l as EndMsg, E as EndReason, m as ErrorCode, n as ErrorCodeName, o as ErrorData, p as ErrorMsg, q as ErrorReason, r as ErrorReasonName, s as EventMsg, t as EventName, F as FsPatchEditFailure, H as HelloMsg, L as Limits, N as NAMED_SCHEMAS, u as NamedSchemaId, c as OPS, v as OpDescriptor, a as OpParams, b as OpResult, w as OpSpec, P as PING_TEXT, x as PONG_TEXT, y as ProtocolErrorBody, R as RelayMsg, z as RequestMsg, A as ResponseMsg, G as SUBPROTOCOL, S as StreamMeta, I as StreamMsg, W as Welcome, i as isDesktopProtocolError } from './registry-BeY9D7h0.cjs';
3
4
  export { BROADCAST_CID, DecodedFrame, FRAME_HEADER_BYTES, FRAME_STRUCT_FORMAT, FRAME_VERSION, FrameChannel, FrameChannelValue, FrameFlag, assertFrameHeader, connectionEndFrame, decodeFrame, encodeFrame, hasFlag, isConnectionEnd, readCid, stampCid } from './frame.cjs';
4
5
 
5
6
  /** @ai-matrx/desktop-protocol — version and primitive schemas. Schema source: lint-enforced rules in scripts/check-schema-source.mjs. */
6
7
 
7
8
  declare const PROTOCOL_MAJOR: 1;
8
- declare const PROTOCOL_MINOR: 0;
9
+ /**
10
+ * Minor history (same major = compatible; see src/versioning.ts for the rule and FIELDS_SINCE):
11
+ * 1.0 — the first contract.
12
+ * 1.1 — fs.patch per-edit results; /call reports the negotiated version.
13
+ */
14
+ declare const PROTOCOL_MINOR: 1;
9
15
  /** This package's version as the wire spells it ("major.minor"): hello, welcome, relay status. */
10
- declare const PROTOCOL_VERSION: "1.0";
16
+ declare const PROTOCOL_VERSION: "1.1";
11
17
  /** Internal building blocks — deliberately unnamed in $defs (inlined wherever used). */
12
18
  declare const u32: z.ZodInt;
13
19
  declare const nonNegInt: z.ZodInt;
@@ -366,13 +372,43 @@ declare const FsPatchParams: z.ZodObject<{
366
372
  create_if_missing: z.ZodDefault<z.ZodBoolean>;
367
373
  }, z.core.$strict>;
368
374
  type FsPatchParams = z.output<typeof FsPatchParams>;
375
+ /**
376
+ * = the daemon's /fs/patch answer per edit: edits apply in order, each sees the previous result; an
377
+ * edit whose old_text is missing, or matches more than once without replace_all, is skipped and
378
+ * listed in edits_failed with the daemon's reason; the file is written when at least one applied.
379
+ * (Every edit failing is a CONFLICT whose data.edits_failed lists them — the daemon's 422.)
380
+ */
369
381
  declare const FsPatchResult: z.ZodObject<{
370
382
  path: z.ZodString;
371
383
  applied: z.ZodInt;
372
384
  size: z.ZodInt;
373
385
  mtime_ms: z.ZodInt;
386
+ edits_applied: z.ZodOptional<z.ZodArray<z.ZodObject<{
387
+ edit_index: z.ZodInt;
388
+ mode: z.ZodEnum<{
389
+ replace_all: "replace_all";
390
+ create: "create";
391
+ replace: "replace";
392
+ }>;
393
+ matches_replaced: z.ZodOptional<z.ZodInt>;
394
+ }, z.core.$strict>>>;
395
+ edits_failed: z.ZodOptional<z.ZodArray<z.ZodObject<{
396
+ edit_index: z.ZodInt;
397
+ reason: z.ZodString;
398
+ }, z.core.$strict>>>;
374
399
  }, z.core.$strict>;
375
400
  type FsPatchResult = z.output<typeof FsPatchResult>;
401
+ /** One edit fs.patch applied — the daemon's `edits_applied[]` entry, verbatim. */
402
+ declare const FsPatchEditApplied: z.ZodObject<{
403
+ edit_index: z.ZodInt;
404
+ mode: z.ZodEnum<{
405
+ replace_all: "replace_all";
406
+ create: "create";
407
+ replace: "replace";
408
+ }>;
409
+ matches_replaced: z.ZodOptional<z.ZodInt>;
410
+ }, z.core.$strict>;
411
+ type FsPatchEditApplied = z.output<typeof FsPatchEditApplied>;
376
412
  /** = daemon SearchPathRequest (/search/paths). */
377
413
  declare const FsSearchPathsParams: z.ZodObject<{
378
414
  pattern: z.ZodString;
@@ -871,6 +907,11 @@ type SessionControlChangedEvent = z.output<typeof SessionControlChangedEvent>;
871
907
 
872
908
  /** @ai-matrx/desktop-protocol — cap relay. Schema source: lint-enforced rules in scripts/check-schema-source.mjs. */
873
909
 
910
+ /**
911
+ * The caller of /call announces the newest protocol it reads in this request header; the relay
912
+ * includes fields newer than 1.0 only when the announced version knows them (src/versioning.ts).
913
+ */
914
+ declare const RELAY_CALL_VERSION_HEADER: "x-matrx-protocol-version";
874
915
  /**
875
916
  * How the relay runs one /call on the device: a fresh cid (its own connection) carrying exactly
876
917
  * RelayCallHello then RelayCallEnvelope, answered on that cid by response/error with id "call"
@@ -900,6 +941,7 @@ type RelayCallRequest = z.output<typeof RelayCallRequest>;
900
941
  declare const RelayCallResponse: z.ZodDiscriminatedUnion<[z.ZodObject<{
901
942
  ok: z.ZodLiteral<true>;
902
943
  result: z.ZodUnknown;
944
+ protocol_version: z.ZodOptional<z.ZodString>;
903
945
  }, z.core.$strict>, z.ZodObject<{
904
946
  ok: z.ZodLiteral<false>;
905
947
  error: z.ZodObject<{
@@ -950,6 +992,10 @@ declare const RelayCallResponse: z.ZodDiscriminatedUnion<[z.ZodObject<{
950
992
  settings_url: z.ZodOptional<z.ZodString>;
951
993
  retry_after_ms: z.ZodOptional<z.ZodInt>;
952
994
  limit_bytes: z.ZodOptional<z.ZodInt>;
995
+ edits_failed: z.ZodOptional<z.ZodArray<z.ZodObject<{
996
+ edit_index: z.ZodInt;
997
+ reason: z.ZodString;
998
+ }, z.core.$strict>>>;
953
999
  upgrade: z.ZodOptional<z.ZodObject<{
954
1000
  min_version: z.ZodString;
955
1001
  max_version: z.ZodString;
@@ -957,6 +1003,7 @@ declare const RelayCallResponse: z.ZodDiscriminatedUnion<[z.ZodObject<{
957
1003
  }, z.core.$strict>>;
958
1004
  }, z.core.$strict>>;
959
1005
  }, z.core.$strict>;
1006
+ protocol_version: z.ZodOptional<z.ZodString>;
960
1007
  }, z.core.$strict>], "ok">;
961
1008
  type RelayCallResponse = z.output<typeof RelayCallResponse>;
962
1009
  /** HTTP GET /v1/devices/{device_id}/status (owner JWT). */
@@ -984,4 +1031,53 @@ declare const RelayCallEnvelope: z.ZodObject<{
984
1031
  }, z.core.$strict>;
985
1032
  type RelayCallEnvelope = z.output<typeof RelayCallEnvelope>;
986
1033
 
987
- export { AbsPath, DEFAULT_MAX_FRAME_PAYLOAD_BYTES, DEFAULT_MAX_MESSAGE_BYTES, DEFAULT_WINDOW_BYTES, DeviceId, ExecCwdEvent, ExecExitedEvent, ExecListParams, ExecListResult, ExecPtyKillParams, ExecPtyKillResult, ExecPtyResizeParams, ExecPtyResizeResult, ExecPtySignalParams, ExecPtySignalResult, ExecPtyStartParams, ExecPtyStartResult, ExecPtyWriteParams, ExecPtyWriteResult, ExecRunParams, ExecRunResult, ExecTitleEvent, FrameHeader, FsChange, FsChangedEvent, FsDeleteParams, FsDeleteResult, FsEncoding, FsEntry, FsKind, FsListParams, FsListResult, FsMkdirParams, FsMkdirResult, FsMoveParams, FsMoveResult, FsPatchParams, FsPatchResult, FsReadParams, FsReadResult, FsReadStreamParams, FsReadStreamResult, FsSearchContentParams, FsSearchContentResult, FsSearchPathsParams, FsSearchPathsResult, FsStatParams, FsStatResult, FsWatchParams, FsWatchResult, FsWriteParams, FsWriteResult, OsPermissionName, PROTOCOL_MAJOR, PROTOCOL_MINOR, PROTOCOL_VERSION, ProtocolVersion, PtyInfo, RELAY_CALL_HELLO_ID, RELAY_CALL_REQUEST_ID, RelayAuthExpiringEvent, RelayCallEnvelope, RelayCallHello, RelayCallRequest, RelayCallResponse, RelayDeviceStatusEvent, RelayHopConnectionEnd, RelayHopEnvelopeHeader, RelayStatusResponse, RequestId, ResourceId, ResourceInfo, SessionAttachParams, SessionAttachResult, SessionControlChangedEvent, SessionDetachParams, SessionDetachResult, SessionListParams, SessionListResult, SessionReleaseParams, SessionReleaseResult, Signal, SysinfoGetParams, SysinfoGetResult, epochMs, nonNegInt, u32 };
1034
+ /**
1035
+ * Version skew is the normal state: a phone, the server and a desktop app in the field run
1036
+ * different package versions, and a minor protocol bump must never make any of them fail.
1037
+ *
1038
+ * THE RULE (enforced by src/versioning.test.ts against generated/baseline-1.0.json):
1039
+ * 1. Within a major, a minor may only ADD. A field added after x.0 is OPTIONAL in the schema
1040
+ * (an older peer omits it) and is listed in FIELDS_SINCE with the minor that added it.
1041
+ * 2. A writer never sends a field newer than the version its peer negotiated (hello/welcome, or
1042
+ * the /call version header): older peers' strict schemas refuse unknown keys. `forPeer`
1043
+ * does the stripping; the core's Router applies it to every result and error it sends.
1044
+ * 3. A reader that needs a newer field checks the peer's version and says so loudly when the
1045
+ * peer is older (e.g. aidream's local_proxy marks a patch answer from a 1.0 app).
1046
+ */
1047
+
1048
+ /**
1049
+ * Fields added after x.0, by schema location: a named schema (`FsPatchResult`), a property path
1050
+ * inside one (`ProtocolErrorBody.data`), or a union branch (`RelayCallResponse|0`).
1051
+ */
1052
+ declare const FIELDS_SINCE: {
1053
+ readonly FsPatchResult: {
1054
+ readonly edits_applied: "1.1";
1055
+ readonly edits_failed: "1.1";
1056
+ };
1057
+ readonly "ProtocolErrorBody.data": {
1058
+ readonly edits_failed: "1.1";
1059
+ };
1060
+ readonly "RelayCallResponse|0": {
1061
+ readonly protocol_version: "1.1";
1062
+ };
1063
+ readonly "RelayCallResponse|1": {
1064
+ readonly protocol_version: "1.1";
1065
+ };
1066
+ };
1067
+ type FieldsSincePath = keyof typeof FIELDS_SINCE;
1068
+ /** "1.10" > "1.9". Same-major comparison of "major.minor" strings. */
1069
+ declare function compareVersions(a: string, b: string): number;
1070
+ /** True when a peer at `version` knows a field added in `since`. */
1071
+ declare function knows(version: string, since: string): boolean;
1072
+ /** The version two peers speak: the lower minor within this major. */
1073
+ declare function negotiate(peerVersion: string): string;
1074
+ /**
1075
+ * What to send a peer that negotiated `version`: `result` of `op`, or an error body, with every
1076
+ * field newer than that version removed (rule 2). Unchanged for a current peer.
1077
+ */
1078
+ declare function forPeer(op: OpName, part: "result", value: unknown, version: string): unknown;
1079
+ declare function forPeer(op: OpName | null, part: "error", value: unknown, version: string): unknown;
1080
+ /** Every op whose result has a versioned field is wired into forPeer (checked by the test). */
1081
+ declare const VERSIONED_RESULT_OPS: readonly OpName[];
1082
+
1083
+ export { AbsPath, DEFAULT_MAX_FRAME_PAYLOAD_BYTES, DEFAULT_MAX_MESSAGE_BYTES, DEFAULT_WINDOW_BYTES, DeviceId, ExecCwdEvent, ExecExitedEvent, ExecListParams, ExecListResult, ExecPtyKillParams, ExecPtyKillResult, ExecPtyResizeParams, ExecPtyResizeResult, ExecPtySignalParams, ExecPtySignalResult, ExecPtyStartParams, ExecPtyStartResult, ExecPtyWriteParams, ExecPtyWriteResult, ExecRunParams, ExecRunResult, ExecTitleEvent, FIELDS_SINCE, type FieldsSincePath, FrameHeader, FsChange, FsChangedEvent, FsDeleteParams, FsDeleteResult, FsEncoding, FsEntry, FsKind, FsListParams, FsListResult, FsMkdirParams, FsMkdirResult, FsMoveParams, FsMoveResult, FsPatchEditApplied, FsPatchParams, FsPatchResult, FsReadParams, FsReadResult, FsReadStreamParams, FsReadStreamResult, FsSearchContentParams, FsSearchContentResult, FsSearchPathsParams, FsSearchPathsResult, FsStatParams, FsStatResult, FsWatchParams, FsWatchResult, FsWriteParams, FsWriteResult, OpName, OsPermissionName, PROTOCOL_MAJOR, PROTOCOL_MINOR, PROTOCOL_VERSION, ProtocolVersion, PtyInfo, RELAY_CALL_HELLO_ID, RELAY_CALL_REQUEST_ID, RELAY_CALL_VERSION_HEADER, RelayAuthExpiringEvent, RelayCallEnvelope, RelayCallHello, RelayCallRequest, RelayCallResponse, RelayDeviceStatusEvent, RelayHopConnectionEnd, RelayHopEnvelopeHeader, RelayStatusResponse, RequestId, ResourceId, ResourceInfo, SessionAttachParams, SessionAttachResult, SessionControlChangedEvent, SessionDetachParams, SessionDetachResult, SessionListParams, SessionListResult, SessionReleaseParams, SessionReleaseResult, Signal, SysinfoGetParams, SysinfoGetResult, VERSIONED_RESULT_OPS, compareVersions, epochMs, forPeer, knows, negotiate, nonNegInt, u32 };
package/dist/index.d.ts CHANGED
@@ -1,13 +1,19 @@
1
1
  import { z } from 'zod';
2
- export { B as BEARER_PREFIX, e as CancelMsg, f as ClientToCoreMsg, C as ClientType, g as CloseCode, h as CloseCodeValue, j as CoreToClientMsg, k as CreditMsg, D as DesktopProtocolError, d as EVENTS, l as EndMsg, E as EndReason, m as ErrorCode, n as ErrorCodeName, o as ErrorData, p as ErrorMsg, q as ErrorReason, r as ErrorReasonName, s as EventMsg, t as EventName, H as HelloMsg, L as Limits, N as NAMED_SCHEMAS, u as NamedSchemaId, c as OPS, v as OpDescriptor, O as OpName, a as OpParams, b as OpResult, w as OpSpec, P as PING_TEXT, x as PONG_TEXT, y as ProtocolErrorBody, R as RelayMsg, z as RequestMsg, A as ResponseMsg, F as SUBPROTOCOL, S as StreamMeta, G as StreamMsg, W as Welcome, i as isDesktopProtocolError } from './registry-DQ5_mP_5.js';
2
+ import { O as OpName } from './registry-BeY9D7h0.js';
3
+ export { B as BEARER_PREFIX, e as CancelMsg, f as ClientToCoreMsg, C as ClientType, g as CloseCode, h as CloseCodeValue, j as CoreToClientMsg, k as CreditMsg, D as DesktopProtocolError, d as EVENTS, l as EndMsg, E as EndReason, m as ErrorCode, n as ErrorCodeName, o as ErrorData, p as ErrorMsg, q as ErrorReason, r as ErrorReasonName, s as EventMsg, t as EventName, F as FsPatchEditFailure, H as HelloMsg, L as Limits, N as NAMED_SCHEMAS, u as NamedSchemaId, c as OPS, v as OpDescriptor, a as OpParams, b as OpResult, w as OpSpec, P as PING_TEXT, x as PONG_TEXT, y as ProtocolErrorBody, R as RelayMsg, z as RequestMsg, A as ResponseMsg, G as SUBPROTOCOL, S as StreamMeta, I as StreamMsg, W as Welcome, i as isDesktopProtocolError } from './registry-BeY9D7h0.js';
3
4
  export { BROADCAST_CID, DecodedFrame, FRAME_HEADER_BYTES, FRAME_STRUCT_FORMAT, FRAME_VERSION, FrameChannel, FrameChannelValue, FrameFlag, assertFrameHeader, connectionEndFrame, decodeFrame, encodeFrame, hasFlag, isConnectionEnd, readCid, stampCid } from './frame.js';
4
5
 
5
6
  /** @ai-matrx/desktop-protocol — version and primitive schemas. Schema source: lint-enforced rules in scripts/check-schema-source.mjs. */
6
7
 
7
8
  declare const PROTOCOL_MAJOR: 1;
8
- declare const PROTOCOL_MINOR: 0;
9
+ /**
10
+ * Minor history (same major = compatible; see src/versioning.ts for the rule and FIELDS_SINCE):
11
+ * 1.0 — the first contract.
12
+ * 1.1 — fs.patch per-edit results; /call reports the negotiated version.
13
+ */
14
+ declare const PROTOCOL_MINOR: 1;
9
15
  /** This package's version as the wire spells it ("major.minor"): hello, welcome, relay status. */
10
- declare const PROTOCOL_VERSION: "1.0";
16
+ declare const PROTOCOL_VERSION: "1.1";
11
17
  /** Internal building blocks — deliberately unnamed in $defs (inlined wherever used). */
12
18
  declare const u32: z.ZodInt;
13
19
  declare const nonNegInt: z.ZodInt;
@@ -366,13 +372,43 @@ declare const FsPatchParams: z.ZodObject<{
366
372
  create_if_missing: z.ZodDefault<z.ZodBoolean>;
367
373
  }, z.core.$strict>;
368
374
  type FsPatchParams = z.output<typeof FsPatchParams>;
375
+ /**
376
+ * = the daemon's /fs/patch answer per edit: edits apply in order, each sees the previous result; an
377
+ * edit whose old_text is missing, or matches more than once without replace_all, is skipped and
378
+ * listed in edits_failed with the daemon's reason; the file is written when at least one applied.
379
+ * (Every edit failing is a CONFLICT whose data.edits_failed lists them — the daemon's 422.)
380
+ */
369
381
  declare const FsPatchResult: z.ZodObject<{
370
382
  path: z.ZodString;
371
383
  applied: z.ZodInt;
372
384
  size: z.ZodInt;
373
385
  mtime_ms: z.ZodInt;
386
+ edits_applied: z.ZodOptional<z.ZodArray<z.ZodObject<{
387
+ edit_index: z.ZodInt;
388
+ mode: z.ZodEnum<{
389
+ replace_all: "replace_all";
390
+ create: "create";
391
+ replace: "replace";
392
+ }>;
393
+ matches_replaced: z.ZodOptional<z.ZodInt>;
394
+ }, z.core.$strict>>>;
395
+ edits_failed: z.ZodOptional<z.ZodArray<z.ZodObject<{
396
+ edit_index: z.ZodInt;
397
+ reason: z.ZodString;
398
+ }, z.core.$strict>>>;
374
399
  }, z.core.$strict>;
375
400
  type FsPatchResult = z.output<typeof FsPatchResult>;
401
+ /** One edit fs.patch applied — the daemon's `edits_applied[]` entry, verbatim. */
402
+ declare const FsPatchEditApplied: z.ZodObject<{
403
+ edit_index: z.ZodInt;
404
+ mode: z.ZodEnum<{
405
+ replace_all: "replace_all";
406
+ create: "create";
407
+ replace: "replace";
408
+ }>;
409
+ matches_replaced: z.ZodOptional<z.ZodInt>;
410
+ }, z.core.$strict>;
411
+ type FsPatchEditApplied = z.output<typeof FsPatchEditApplied>;
376
412
  /** = daemon SearchPathRequest (/search/paths). */
377
413
  declare const FsSearchPathsParams: z.ZodObject<{
378
414
  pattern: z.ZodString;
@@ -871,6 +907,11 @@ type SessionControlChangedEvent = z.output<typeof SessionControlChangedEvent>;
871
907
 
872
908
  /** @ai-matrx/desktop-protocol — cap relay. Schema source: lint-enforced rules in scripts/check-schema-source.mjs. */
873
909
 
910
+ /**
911
+ * The caller of /call announces the newest protocol it reads in this request header; the relay
912
+ * includes fields newer than 1.0 only when the announced version knows them (src/versioning.ts).
913
+ */
914
+ declare const RELAY_CALL_VERSION_HEADER: "x-matrx-protocol-version";
874
915
  /**
875
916
  * How the relay runs one /call on the device: a fresh cid (its own connection) carrying exactly
876
917
  * RelayCallHello then RelayCallEnvelope, answered on that cid by response/error with id "call"
@@ -900,6 +941,7 @@ type RelayCallRequest = z.output<typeof RelayCallRequest>;
900
941
  declare const RelayCallResponse: z.ZodDiscriminatedUnion<[z.ZodObject<{
901
942
  ok: z.ZodLiteral<true>;
902
943
  result: z.ZodUnknown;
944
+ protocol_version: z.ZodOptional<z.ZodString>;
903
945
  }, z.core.$strict>, z.ZodObject<{
904
946
  ok: z.ZodLiteral<false>;
905
947
  error: z.ZodObject<{
@@ -950,6 +992,10 @@ declare const RelayCallResponse: z.ZodDiscriminatedUnion<[z.ZodObject<{
950
992
  settings_url: z.ZodOptional<z.ZodString>;
951
993
  retry_after_ms: z.ZodOptional<z.ZodInt>;
952
994
  limit_bytes: z.ZodOptional<z.ZodInt>;
995
+ edits_failed: z.ZodOptional<z.ZodArray<z.ZodObject<{
996
+ edit_index: z.ZodInt;
997
+ reason: z.ZodString;
998
+ }, z.core.$strict>>>;
953
999
  upgrade: z.ZodOptional<z.ZodObject<{
954
1000
  min_version: z.ZodString;
955
1001
  max_version: z.ZodString;
@@ -957,6 +1003,7 @@ declare const RelayCallResponse: z.ZodDiscriminatedUnion<[z.ZodObject<{
957
1003
  }, z.core.$strict>>;
958
1004
  }, z.core.$strict>>;
959
1005
  }, z.core.$strict>;
1006
+ protocol_version: z.ZodOptional<z.ZodString>;
960
1007
  }, z.core.$strict>], "ok">;
961
1008
  type RelayCallResponse = z.output<typeof RelayCallResponse>;
962
1009
  /** HTTP GET /v1/devices/{device_id}/status (owner JWT). */
@@ -984,4 +1031,53 @@ declare const RelayCallEnvelope: z.ZodObject<{
984
1031
  }, z.core.$strict>;
985
1032
  type RelayCallEnvelope = z.output<typeof RelayCallEnvelope>;
986
1033
 
987
- export { AbsPath, DEFAULT_MAX_FRAME_PAYLOAD_BYTES, DEFAULT_MAX_MESSAGE_BYTES, DEFAULT_WINDOW_BYTES, DeviceId, ExecCwdEvent, ExecExitedEvent, ExecListParams, ExecListResult, ExecPtyKillParams, ExecPtyKillResult, ExecPtyResizeParams, ExecPtyResizeResult, ExecPtySignalParams, ExecPtySignalResult, ExecPtyStartParams, ExecPtyStartResult, ExecPtyWriteParams, ExecPtyWriteResult, ExecRunParams, ExecRunResult, ExecTitleEvent, FrameHeader, FsChange, FsChangedEvent, FsDeleteParams, FsDeleteResult, FsEncoding, FsEntry, FsKind, FsListParams, FsListResult, FsMkdirParams, FsMkdirResult, FsMoveParams, FsMoveResult, FsPatchParams, FsPatchResult, FsReadParams, FsReadResult, FsReadStreamParams, FsReadStreamResult, FsSearchContentParams, FsSearchContentResult, FsSearchPathsParams, FsSearchPathsResult, FsStatParams, FsStatResult, FsWatchParams, FsWatchResult, FsWriteParams, FsWriteResult, OsPermissionName, PROTOCOL_MAJOR, PROTOCOL_MINOR, PROTOCOL_VERSION, ProtocolVersion, PtyInfo, RELAY_CALL_HELLO_ID, RELAY_CALL_REQUEST_ID, RelayAuthExpiringEvent, RelayCallEnvelope, RelayCallHello, RelayCallRequest, RelayCallResponse, RelayDeviceStatusEvent, RelayHopConnectionEnd, RelayHopEnvelopeHeader, RelayStatusResponse, RequestId, ResourceId, ResourceInfo, SessionAttachParams, SessionAttachResult, SessionControlChangedEvent, SessionDetachParams, SessionDetachResult, SessionListParams, SessionListResult, SessionReleaseParams, SessionReleaseResult, Signal, SysinfoGetParams, SysinfoGetResult, epochMs, nonNegInt, u32 };
1034
+ /**
1035
+ * Version skew is the normal state: a phone, the server and a desktop app in the field run
1036
+ * different package versions, and a minor protocol bump must never make any of them fail.
1037
+ *
1038
+ * THE RULE (enforced by src/versioning.test.ts against generated/baseline-1.0.json):
1039
+ * 1. Within a major, a minor may only ADD. A field added after x.0 is OPTIONAL in the schema
1040
+ * (an older peer omits it) and is listed in FIELDS_SINCE with the minor that added it.
1041
+ * 2. A writer never sends a field newer than the version its peer negotiated (hello/welcome, or
1042
+ * the /call version header): older peers' strict schemas refuse unknown keys. `forPeer`
1043
+ * does the stripping; the core's Router applies it to every result and error it sends.
1044
+ * 3. A reader that needs a newer field checks the peer's version and says so loudly when the
1045
+ * peer is older (e.g. aidream's local_proxy marks a patch answer from a 1.0 app).
1046
+ */
1047
+
1048
+ /**
1049
+ * Fields added after x.0, by schema location: a named schema (`FsPatchResult`), a property path
1050
+ * inside one (`ProtocolErrorBody.data`), or a union branch (`RelayCallResponse|0`).
1051
+ */
1052
+ declare const FIELDS_SINCE: {
1053
+ readonly FsPatchResult: {
1054
+ readonly edits_applied: "1.1";
1055
+ readonly edits_failed: "1.1";
1056
+ };
1057
+ readonly "ProtocolErrorBody.data": {
1058
+ readonly edits_failed: "1.1";
1059
+ };
1060
+ readonly "RelayCallResponse|0": {
1061
+ readonly protocol_version: "1.1";
1062
+ };
1063
+ readonly "RelayCallResponse|1": {
1064
+ readonly protocol_version: "1.1";
1065
+ };
1066
+ };
1067
+ type FieldsSincePath = keyof typeof FIELDS_SINCE;
1068
+ /** "1.10" > "1.9". Same-major comparison of "major.minor" strings. */
1069
+ declare function compareVersions(a: string, b: string): number;
1070
+ /** True when a peer at `version` knows a field added in `since`. */
1071
+ declare function knows(version: string, since: string): boolean;
1072
+ /** The version two peers speak: the lower minor within this major. */
1073
+ declare function negotiate(peerVersion: string): string;
1074
+ /**
1075
+ * What to send a peer that negotiated `version`: `result` of `op`, or an error body, with every
1076
+ * field newer than that version removed (rule 2). Unchanged for a current peer.
1077
+ */
1078
+ declare function forPeer(op: OpName, part: "result", value: unknown, version: string): unknown;
1079
+ declare function forPeer(op: OpName | null, part: "error", value: unknown, version: string): unknown;
1080
+ /** Every op whose result has a versioned field is wired into forPeer (checked by the test). */
1081
+ declare const VERSIONED_RESULT_OPS: readonly OpName[];
1082
+
1083
+ export { AbsPath, DEFAULT_MAX_FRAME_PAYLOAD_BYTES, DEFAULT_MAX_MESSAGE_BYTES, DEFAULT_WINDOW_BYTES, DeviceId, ExecCwdEvent, ExecExitedEvent, ExecListParams, ExecListResult, ExecPtyKillParams, ExecPtyKillResult, ExecPtyResizeParams, ExecPtyResizeResult, ExecPtySignalParams, ExecPtySignalResult, ExecPtyStartParams, ExecPtyStartResult, ExecPtyWriteParams, ExecPtyWriteResult, ExecRunParams, ExecRunResult, ExecTitleEvent, FIELDS_SINCE, type FieldsSincePath, FrameHeader, FsChange, FsChangedEvent, FsDeleteParams, FsDeleteResult, FsEncoding, FsEntry, FsKind, FsListParams, FsListResult, FsMkdirParams, FsMkdirResult, FsMoveParams, FsMoveResult, FsPatchEditApplied, FsPatchParams, FsPatchResult, FsReadParams, FsReadResult, FsReadStreamParams, FsReadStreamResult, FsSearchContentParams, FsSearchContentResult, FsSearchPathsParams, FsSearchPathsResult, FsStatParams, FsStatResult, FsWatchParams, FsWatchResult, FsWriteParams, FsWriteResult, OpName, OsPermissionName, PROTOCOL_MAJOR, PROTOCOL_MINOR, PROTOCOL_VERSION, ProtocolVersion, PtyInfo, RELAY_CALL_HELLO_ID, RELAY_CALL_REQUEST_ID, RELAY_CALL_VERSION_HEADER, RelayAuthExpiringEvent, RelayCallEnvelope, RelayCallHello, RelayCallRequest, RelayCallResponse, RelayDeviceStatusEvent, RelayHopConnectionEnd, RelayHopEnvelopeHeader, RelayStatusResponse, RequestId, ResourceId, ResourceInfo, SessionAttachParams, SessionAttachResult, SessionControlChangedEvent, SessionDetachParams, SessionDetachResult, SessionListParams, SessionListResult, SessionReleaseParams, SessionReleaseResult, Signal, SysinfoGetParams, SysinfoGetResult, VERSIONED_RESULT_OPS, compareVersions, epochMs, forPeer, knows, negotiate, nonNegInt, u32 };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/schema/primitives.ts
2
2
  import { z } from "zod";
3
3
  var PROTOCOL_MAJOR = 1;
4
- var PROTOCOL_MINOR = 0;
4
+ var PROTOCOL_MINOR = 1;
5
5
  var PROTOCOL_VERSION = `${PROTOCOL_MAJOR}.${PROTOCOL_MINOR}`;
6
6
  var ProtocolVersion = z.string().regex(/^[1-9][0-9]{0,2}\.[0-9]{1,3}$/);
7
7
  var RequestId = z.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
@@ -62,6 +62,7 @@ var ErrorReason = z2.enum([
62
62
  // another client of the same user took control
63
63
  "window_exhausted"
64
64
  ]);
65
+ var FsPatchEditFailure = z2.strictObject({ edit_index: nonNegInt, reason: z2.string().max(300) });
65
66
  var ProtocolErrorBody = z2.strictObject({
66
67
  code: ErrorCode,
67
68
  message: z2.string().max(300),
@@ -76,6 +77,8 @@ var ProtocolErrorBody = z2.strictObject({
76
77
  // PERMISSION_DENIED_OS deep link
77
78
  retry_after_ms: nonNegInt.optional(),
78
79
  limit_bytes: nonNegInt.optional(),
80
+ /** fs.patch when every edit failed (CONFLICT, patch_no_match / patch_ambiguous): the daemon's 422 `failures`. */
81
+ edits_failed: z2.array(FsPatchEditFailure).max(256).optional(),
79
82
  upgrade: z2.strictObject({
80
83
  min_version: ProtocolVersion,
81
84
  max_version: ProtocolVersion,
@@ -481,7 +484,22 @@ var FsPatchParams = z6.strictObject({
481
484
  ).min(1).max(256),
482
485
  create_if_missing: z6.boolean().default(false)
483
486
  });
484
- var FsPatchResult = z6.strictObject({ path: AbsPath, applied: nonNegInt, size: nonNegInt, mtime_ms: epochMs });
487
+ var FsPatchEditApplied = z6.strictObject({
488
+ edit_index: nonNegInt,
489
+ mode: z6.enum(["create", "replace", "replace_all"]),
490
+ /** Present for replace_all only, as the daemon sends it. */
491
+ matches_replaced: nonNegInt.optional()
492
+ });
493
+ var FsPatchResult = z6.strictObject({
494
+ path: AbsPath,
495
+ applied: nonNegInt,
496
+ size: nonNegInt,
497
+ mtime_ms: epochMs,
498
+ /** Since 1.1 (FIELDS_SINCE): a 1.0 app sends only `applied`. Always sent to a ≥1.1 peer. */
499
+ edits_applied: z6.array(FsPatchEditApplied).max(256).optional(),
500
+ /** Since 1.1 (FIELDS_SINCE). */
501
+ edits_failed: z6.array(FsPatchEditFailure).max(256).optional()
502
+ });
485
503
  var FsSearchPathsParams = z6.strictObject({
486
504
  pattern: z6.string().min(1).max(512),
487
505
  cwd: AbsPath,
@@ -631,9 +649,20 @@ var RelayCallRequest = z9.strictObject({
631
649
  params: z9.unknown(),
632
650
  timeout_ms: z9.int().min(100).max(37e5).default(7e4)
633
651
  });
652
+ var RELAY_CALL_VERSION_HEADER = "x-matrx-protocol-version";
634
653
  var RelayCallResponse = z9.discriminatedUnion("ok", [
635
- z9.strictObject({ ok: z9.literal(true), result: z9.unknown() }),
636
- z9.strictObject({ ok: z9.literal(false), error: ProtocolErrorBody })
654
+ z9.strictObject({
655
+ ok: z9.literal(true),
656
+ result: z9.unknown(),
657
+ /** Since 1.1: the version the device negotiated for this call (its welcome). */
658
+ protocol_version: ProtocolVersion.optional()
659
+ }),
660
+ z9.strictObject({
661
+ ok: z9.literal(false),
662
+ error: ProtocolErrorBody,
663
+ /** Since 1.1, as above (absent when the device never answered hello). */
664
+ protocol_version: ProtocolVersion.optional()
665
+ })
637
666
  ]);
638
667
  var RELAY_CALL_HELLO_ID = "hello";
639
668
  var RELAY_CALL_REQUEST_ID = "call";
@@ -698,6 +727,7 @@ var NAMED_SCHEMAS = {
698
727
  AbsPath,
699
728
  ErrorCode,
700
729
  ErrorReason,
730
+ FsPatchEditFailure,
701
731
  ProtocolErrorBody,
702
732
  FrameHeader,
703
733
  ClientType,
@@ -741,6 +771,7 @@ var NAMED_SCHEMAS = {
741
771
  FsDeleteResult,
742
772
  FsWatchParams,
743
773
  FsWatchResult,
774
+ FsPatchEditApplied,
744
775
  FsPatchParams,
745
776
  FsPatchResult,
746
777
  FsSearchPathsParams,
@@ -786,6 +817,51 @@ var NAMED_SCHEMAS = {
786
817
  RelayHopConnectionEnd,
787
818
  CloseCodeValue
788
819
  };
820
+
821
+ // src/versioning.ts
822
+ var FIELDS_SINCE = {
823
+ FsPatchResult: { edits_applied: "1.1", edits_failed: "1.1" },
824
+ "ProtocolErrorBody.data": { edits_failed: "1.1" },
825
+ "RelayCallResponse|0": { protocol_version: "1.1" },
826
+ "RelayCallResponse|1": { protocol_version: "1.1" }
827
+ };
828
+ function compareVersions(a, b) {
829
+ const [am = 0, an = 0] = a.split(".").map(Number);
830
+ const [bm = 0, bn = 0] = b.split(".").map(Number);
831
+ return am - bm || an - bn;
832
+ }
833
+ function knows(version, since) {
834
+ return compareVersions(version, since) >= 0;
835
+ }
836
+ function negotiate(peerVersion) {
837
+ const [major = 0, minor = 0] = peerVersion.split(".").map(Number);
838
+ if (major !== PROTOCOL_MAJOR) return `${PROTOCOL_MAJOR}.0`;
839
+ return `${PROTOCOL_MAJOR}.${Math.min(minor, PROTOCOL_MINOR)}`;
840
+ }
841
+ function strip(value, fields, version) {
842
+ if (!fields || value === null || typeof value !== "object" || Array.isArray(value)) return value;
843
+ let out = null;
844
+ for (const [field, since] of Object.entries(fields)) {
845
+ if (field in value && !knows(version, since)) {
846
+ out ??= { ...value };
847
+ delete out[field];
848
+ }
849
+ }
850
+ return out ?? value;
851
+ }
852
+ var RESULT_PATH = /* @__PURE__ */ new Map([["fs.patch", "FsPatchResult"]]);
853
+ function forPeer(op, part, value, version) {
854
+ if (part === "result") {
855
+ const path = op ? RESULT_PATH.get(op) : void 0;
856
+ return path ? strip(value, FIELDS_SINCE[path], version) : value;
857
+ }
858
+ if (value === null || typeof value !== "object") return value;
859
+ const body = value;
860
+ if (body.data === void 0) return value;
861
+ const data = strip(body.data, FIELDS_SINCE["ProtocolErrorBody.data"], version);
862
+ return data === body.data ? value : { ...body, data };
863
+ }
864
+ var VERSIONED_RESULT_OPS = [...RESULT_PATH.keys()];
789
865
  export {
790
866
  AbsPath,
791
867
  BEARER_PREFIX,
@@ -826,6 +902,7 @@ export {
826
902
  ExecRunParams,
827
903
  ExecRunResult,
828
904
  ExecTitleEvent,
905
+ FIELDS_SINCE,
829
906
  FRAME_HEADER_BYTES,
830
907
  FRAME_STRUCT_FORMAT,
831
908
  FRAME_VERSION,
@@ -845,6 +922,8 @@ export {
845
922
  FsMkdirResult,
846
923
  FsMoveParams,
847
924
  FsMoveResult,
925
+ FsPatchEditApplied,
926
+ FsPatchEditFailure,
848
927
  FsPatchParams,
849
928
  FsPatchResult,
850
929
  FsReadParams,
@@ -877,6 +956,7 @@ export {
877
956
  PtyInfo,
878
957
  RELAY_CALL_HELLO_ID,
879
958
  RELAY_CALL_REQUEST_ID,
959
+ RELAY_CALL_VERSION_HEADER,
880
960
  RelayAuthExpiringEvent,
881
961
  RelayCallEnvelope,
882
962
  RelayCallHello,
@@ -907,15 +987,20 @@ export {
907
987
  StreamMsg,
908
988
  SysinfoGetParams,
909
989
  SysinfoGetResult,
990
+ VERSIONED_RESULT_OPS,
910
991
  Welcome,
911
992
  assertFrameHeader,
993
+ compareVersions,
912
994
  connectionEndFrame,
913
995
  decodeFrame,
914
996
  encodeFrame,
915
997
  epochMs,
998
+ forPeer,
916
999
  hasFlag,
917
1000
  isConnectionEnd,
918
1001
  isDesktopProtocolError,
1002
+ knows,
1003
+ negotiate,
919
1004
  nonNegInt,
920
1005
  readCid,
921
1006
  stampCid,