@cleocode/contracts 2026.9.25 → 2026.10.1

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.
@@ -46,6 +46,29 @@ export const NEXUS_ACCOUNT_ERROR_CODES = [
46
46
  'E_NEXUS_REQUEST_FAILED',
47
47
  'E_NEXUS_NOT_A_PROJECT',
48
48
  'E_NEXUS_INVALID_LABEL',
49
+ // Device credentials (cleo-nexus device contract §3.3, §4.0.4; T12868).
50
+ /** No answer from the API (network error or timeout). */
51
+ 'E_NEXUS_UNREACHABLE',
52
+ /** `cleo login nexus` while a revoke of this device is unconfirmed (§3.3, v2.9). */
53
+ 'E_NEXUS_REVOKE_PENDING',
54
+ /** The device was signed out (E9, E11): 401 `device-signed-out`. */
55
+ 'E_NEXUS_DEVICE_SIGNED_OUT',
56
+ /** The device was revoked (E10, E12): 401 `device-revoked`. */
57
+ 'E_NEXUS_DEVICE_REVOKED',
58
+ /** A credential replaced or revoked elsewhere, or a `rotation-conflict` (R2). */
59
+ 'E_NEXUS_CREDENTIAL_COMPROMISED',
60
+ /** The device credential lacks the scope (a read-only device): 403 `insufficient-scope`. */
61
+ 'E_NEXUS_INSUFFICIENT_SCOPE',
62
+ /** A replica attach from a second device: 409 `replica-copied`. */
63
+ 'E_NEXUS_REPLICA_COPIED',
64
+ /** Another cleo process holds the device file or an upgrade in flight; retry. */
65
+ 'E_NEXUS_BUSY',
66
+ /** Several accounts hold a device credential on one origin and none was named. */
67
+ 'E_NEXUS_ACCOUNT_AMBIGUOUS',
68
+ /** An option that needs device credentials (`--read-only`) with `CLEO_NEXUS_DEVICE=0`. */
69
+ 'E_NEXUS_DEVICE_REQUIRED',
70
+ /** `.cleo/nexus-link.json` is in a format this CLEO cannot update (written by a newer CLEO). */
71
+ 'E_NEXUS_LINK_FILE_UNSUPPORTED',
49
72
  ] as const;
50
73
 
51
74
  /** One of {@link NEXUS_ACCOUNT_ERROR_CODES}. */
@@ -112,6 +135,20 @@ export interface NexusAccountStatus {
112
135
  summary: string;
113
136
  }
114
137
 
138
+ /** The enrolled device, as `cleo login nexus` reports it (device contract §3.3 step 10). */
139
+ export interface NexusLoginDevice {
140
+ /** The Nexus device id (UUIDv7, scoped to this CLEO home, origin and user). */
141
+ deviceId: string;
142
+ /** Display name the server holds. */
143
+ name: string;
144
+ /** Server-side state (`active` right after a login). */
145
+ state: string;
146
+ /** Credential profile: `device` or `read-only`. */
147
+ profile: string | null;
148
+ /** `true` when E1 created the device row, `false` when it re-enrolled it. */
149
+ created: boolean | null;
150
+ }
151
+
115
152
  /** Result of `cleo login nexus` (never carries the token). */
116
153
  export interface NexusLoginResult {
117
154
  /** API origin the session belongs to. */
@@ -126,6 +163,10 @@ export interface NexusLoginResult {
126
163
  credentialsPath: string;
127
164
  /** Non-fatal problems, e.g. the account lookup failed after a good login. */
128
165
  warnings: string[];
166
+ /** The enrolled device; present only with device credentials (the default; off with `CLEO_NEXUS_DEVICE=0`). */
167
+ device?: NexusLoginDevice;
168
+ /** Scopes of the stored device credential; present only with device credentials. */
169
+ scopes?: string[];
129
170
  }
130
171
 
131
172
  /** Result of `cleo logout nexus`. */
@@ -145,6 +186,56 @@ export interface NexusLogoutResult {
145
186
  warnings: string[];
146
187
  }
147
188
 
189
+ /**
190
+ * What happened to one device's sign-out (E9) or revoke (E10) in
191
+ * `cleo logout nexus [--revoke]` with device credentials (the default; `CLEO_NEXUS_DEVICE=0` turns them off) (cleo-nexus
192
+ * device contract §3.5, M3). Holds no secret.
193
+ *
194
+ * - `confirmed`: the server answered 200, or 401 `device-signed-out` /
195
+ * `device-revoked` (a revoke accepts only `device-revoked`);
196
+ * - `pending`: no usable answer (network, timeout, 429, 5xx, or a route the
197
+ * server does not have yet); the credentials stay in their slot and the
198
+ * next `cleo logout nexus`, `cleo login nexus` or cloud command retries;
199
+ * - `unconfirmed`: every credential held was refused as stale, so the CLI
200
+ * cannot finish it; the slot is kept, and a sign-out or revoke of the
201
+ * device on cleocode.dev lets the next retry confirm it;
202
+ * - `signed-out`: a revoke found the device already signed out (E10 401
203
+ * `device-signed-out`). Its credentials are dead, so the CLI cannot revoke
204
+ * it; the revoke slot is cleared (never retried) and the device must be
205
+ * revoked on cleocode.dev.
206
+ */
207
+ export type NexusDeviceEndOutcome = 'confirmed' | 'pending' | 'unconfirmed' | 'signed-out';
208
+
209
+ /** One device row of a {@link NexusDeviceLogoutResult}. */
210
+ export interface NexusDeviceLogoutRow {
211
+ /** Nexus user id of the entry. */
212
+ userId: string;
213
+ /** The device the request ended. */
214
+ deviceId: string;
215
+ /** `sign-out` (E9) or `revoke` (E10). */
216
+ action: 'sign-out' | 'revoke';
217
+ /** `true` for a replaced device's leftover request retried from `retired`. */
218
+ retired: boolean;
219
+ /** Server-side outcome. */
220
+ outcome: NexusDeviceEndOutcome;
221
+ /** `true` when a confirmed revoke removed the (origin, user) entry from `nexus-device.json`. */
222
+ removedLocally: boolean;
223
+ }
224
+
225
+ /** Result of `cleo logout nexus [--revoke]` with device credentials. Holds no secret. */
226
+ export interface NexusDeviceLogoutResult {
227
+ /** API origin. */
228
+ apiUrl: string;
229
+ /** `sign-out` or `revoke` (`--revoke`). */
230
+ action: 'sign-out' | 'revoke';
231
+ /** One row per device request settled or retried in this run, sorted by user then device. */
232
+ devices: NexusDeviceLogoutRow[];
233
+ /** The 9.24 session sign-out, when a leftover session was found for the origin. */
234
+ session: NexusLogoutResult | null;
235
+ /** Non-fatal problems: every non-`confirmed` row is named here. */
236
+ warnings: string[];
237
+ }
238
+
148
239
  /**
149
240
  * The binding of a local CLEO project to its Nexus registration, persisted in
150
241
  * the project's machine-local `.cleo/nexus-link.json`, keyed by API origin.
@@ -164,6 +255,31 @@ export interface NexusProjectLink {
164
255
  streamId: string;
165
256
  /** ISO time of the last successful link. */
166
257
  linkedAt: string;
258
+ /**
259
+ * This store's replica id as attached on the server (device contract
260
+ * §3.6, §3.7). A cache, not the source of truth: the store's active
261
+ * `_sync_replica` row is. Absent before the first device-credential link.
262
+ */
263
+ replicaId?: string;
264
+ /** The Nexus device id that attached {@link NexusProjectLink.replicaId}. */
265
+ nexusDeviceId?: string;
266
+ /** ISO time the replica was last attached or confirmed. */
267
+ attachedAt?: string;
268
+ }
269
+
270
+ /**
271
+ * What `cleo project link` did for this machine's copy of the project with a
272
+ * device credential (contract §3.6 steps 3 to 5). Holds no path or secret.
273
+ */
274
+ export interface NexusReplicaAttachment {
275
+ /** The store's replica id (UUIDv7), now attached on the server. */
276
+ replicaId: string;
277
+ /** The Nexus device that holds it. */
278
+ deviceId: string;
279
+ /** The retired replica id when this link rebound the store (a copy, or a re-enrolled device). */
280
+ reboundFrom: string | null;
281
+ /** Server time the presence report was received, or `null` when sending it failed (see warnings). */
282
+ presenceAt: string | null;
167
283
  }
168
284
 
169
285
  /** Result of `cleo project link`. */
@@ -178,4 +294,17 @@ export interface NexusProjectLinkResult {
178
294
  alreadyLinked: boolean;
179
295
  /** Absolute path of the local binding file. */
180
296
  linkPath: string;
297
+ /**
298
+ * The replica attach and presence report, with device credentials; `null`
299
+ * with the 9.24 session (`CLEO_NEXUS_DEVICE=0`), which cannot attach.
300
+ */
301
+ replica: NexusReplicaAttachment | null;
302
+ /**
303
+ * Why this machine's copy was not attached, when device mode tried and
304
+ * failed (for example `E_NEXUS_REPLICA_COPIED`); `null` otherwise. The same
305
+ * text is also in {@link NexusProjectLinkResult.warnings}.
306
+ */
307
+ attachError: { code: string; message: string; fix: string | null } | null;
308
+ /** Non-fatal problems (for example, presence could not be sent). */
309
+ warnings: string[];
181
310
  }