@deepdockai/cli 1.0.7 → 1.0.9

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.9
4
+
5
+ - The CLI knows `device_learning_only` (exit code 2, refused): the PC runs the Deepdock client for learning only, which runs no actions, so action calls and the systems list on it are refused before anything is sent. It changes only when the Deepdock service is installed on that PC; retrying does not help. The skill's error reference lists it.
6
+
7
+ ## 1.0.8
8
+
9
+ - The CLI knows `system_version_unverified` (exit code 3, retry later): a write on a customer system whose vendor version Deepdock has not verified yet is refused before anything is sent, and works once Deepdock has verified that version (`reason: unverified_version`). A version the API cannot parse (`reason: unparseable`) does not clear by waiting: contact Deepdock. Reads are unaffected.
10
+ - A device's systems carry `writes` (`verified`, `unknown`, `partial`, or `unverified` with a `reason`) in the agent skill's TypeScript client, and the skill's error, idempotency and concepts references describe the refusal.
11
+
3
12
  ## 1.0.7
4
13
 
5
14
  - The CLI knows `device_syncing` and `device_outdated` (exit code 3, retry later) instead of falling back on the HTTP status.
package/README.md CHANGED
@@ -154,14 +154,14 @@ your code will receive; `auth`, `org select` and `keys create` build it from nam
154
154
  failure is one document on stderr, `{ "error": { "code", "message" }, "meta": { "hint" } }`,
155
155
  with the API's error object unchanged. Switch on `code` or on the exit code, never on `message`.
156
156
 
157
- | Exit | Meaning |
158
- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
159
- | 0 | done |
160
- | 1 | something on the command line to fix (`invalid_usage`, `org_required`) |
161
- | 2 | the API refused the request; do not repeat it unchanged (`invalid_request`, `not_found`, `forbidden`, `rate_limited` and the other refusals) |
162
- | 3 | retry later (`device_offline`, `device_syncing`, `device_outdated`, `action_paused`, `access_outdated`, `access_missing`, `system_unavailable`, `target_busy`, `temporarily_unavailable`, `internal_error`, `outcome_unknown`, `connection_lost`) |
163
- | 4 | the CLI is too old for the API (`client_outdated`): run `npx @deepdockai/cli@latest` |
164
- | 5 | sign-in needed (`sign_in_needed`, `approval_denied`, `approval_expired`); `auth status` when nobody is signed in |
157
+ | Exit | Meaning |
158
+ | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
159
+ | 0 | done |
160
+ | 1 | something on the command line to fix (`invalid_usage`, `org_required`) |
161
+ | 2 | the API refused the request; do not repeat it unchanged (`invalid_request`, `not_found`, `forbidden`, `rate_limited` and the other refusals) |
162
+ | 3 | retry later (`device_offline`, `device_syncing`, `device_outdated`, `system_version_unverified`, `action_paused`, `access_outdated`, `access_missing`, `system_unavailable`, `target_busy`, `temporarily_unavailable`, `internal_error`, `outcome_unknown`, `connection_lost`) |
163
+ | 4 | the CLI is too old for the API (`client_outdated`): run `npx @deepdockai/cli@latest` |
164
+ | 5 | sign-in needed (`sign_in_needed`, `approval_denied`, `approval_expired`); `auth status` when nobody is signed in |
165
165
 
166
166
  The CLI never retries on its own: exit 3 says retry, you decide when. `deepdock commands --json`
167
167
  prints the whole command tree.
package/dist/deepdock.js CHANGED
@@ -10859,6 +10859,7 @@ var EXIT_CODES = {
10859
10859
  invalid_input: 2,
10860
10860
  pairing_code_invalid: 2,
10861
10861
  other_partner_build: 2,
10862
+ device_learning_only: 2,
10862
10863
  rate_limited: 2,
10863
10864
  target_rejected: 2,
10864
10865
  check_failed: 2,
@@ -10874,6 +10875,7 @@ var EXIT_CODES = {
10874
10875
  device_offline: 3,
10875
10876
  device_syncing: 3,
10876
10877
  device_outdated: 3,
10878
+ system_version_unverified: 3,
10877
10879
  action_paused: 3,
10878
10880
  access_outdated: 3,
10879
10881
  access_missing: 3,
@@ -11426,7 +11428,7 @@ import { spawn } from "node:child_process";
11426
11428
  import { homedir, hostname } from "node:os";
11427
11429
 
11428
11430
  // src/version.ts
11429
- var VERSION = "1.0.7";
11431
+ var VERSION = "1.0.9";
11430
11432
 
11431
11433
  // src/runtime.ts
11432
11434
  var DEFAULT_BASE_URL = "https://api.deepdock.ai";
@@ -12151,9 +12153,10 @@ var EXIT_CODES_HELP = `Exit codes
12151
12153
  0 done
12152
12154
  1 usage: something on the command line to fix (invalid_usage, org_required)
12153
12155
  2 the API refused the request; do not repeat it unchanged
12154
- 3 retry later (device_offline, device_syncing, device_outdated, action_paused,
12155
- access_outdated, access_missing, system_unavailable, target_busy,
12156
- temporarily_unavailable, internal_error, outcome_unknown, connection_lost)
12156
+ 3 retry later (device_offline, device_syncing, device_outdated,
12157
+ system_version_unverified, action_paused, access_outdated, access_missing,
12158
+ system_unavailable, target_busy, temporarily_unavailable, internal_error,
12159
+ outcome_unknown, connection_lost)
12157
12160
  4 the CLI is too old for the API (client_outdated)
12158
12161
  5 sign-in needed (sign_in_needed, approval_denied, approval_expired; auth status when nobody is signed in)
12159
12162
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepdockai/cli",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Deepdock partner CLI: pair devices, see systems and actions, create the API key your code runs them with.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -84,7 +84,7 @@ A failure is one document on stderr: the API's error object unchanged plus what
84
84
  | 0 | done | |
85
85
  | 1 | something on the command line to fix | `invalid_usage` (a bad flag, an unknown slug, a question with no terminal and no `--yes`, an env file git does not ignore), `org_required` |
86
86
  | 2 | the API refused the request; do not repeat it unchanged | `invalid_request`, `not_found`, `device_not_found`, `pairing_code_invalid`, `other_partner_build`, `rate_limited`, `forbidden`, `conflict` and the other refusals (not `access_outdated` and `access_missing`, see exit 3) |
87
- | 3 | retry later (`access_outdated` and `access_missing`: after the customer repeats "Erneut einrichten" in the Deepdock client) | `device_offline`, `device_syncing`, `device_outdated`, `action_paused`, `access_outdated`, `access_missing`, `system_unavailable`, `target_busy`, `temporarily_unavailable`, `internal_error`, `outcome_unknown`, `connection_lost` |
87
+ | 3 | retry later (`access_outdated` and `access_missing`: after the customer repeats "Erneut einrichten" in the Deepdock client) | `device_offline`, `device_syncing`, `device_outdated`, `system_version_unverified`, `action_paused`, `access_outdated`, `access_missing`, `system_unavailable`, `target_busy`, `temporarily_unavailable`, `internal_error`, `outcome_unknown`, `connection_lost` |
88
88
  | 4 | the CLI is too old for the API: run `npx @deepdockai/cli@latest` | `client_outdated` |
89
89
  | 5 | sign-in needed: run `deepdock auth login` | `sign_in_needed`, `approval_denied`, `approval_expired` |
90
90
 
@@ -19,12 +19,15 @@ class DeepdockError(Exception):
19
19
  """Deepdock answered `{ "error": { "code", ... } }`. Switch on `code`, never on `message`."""
20
20
 
21
21
  def __init__(self, status: int, code: str, message: str, request_id: Optional[str] = None,
22
- systems: Optional[List[str]] = None):
22
+ systems: Optional[List[str]] = None, version: Optional[str] = None,
23
+ reason: Optional[str] = None):
23
24
  super().__init__(message)
24
25
  self.status = status
25
26
  self.code = code
26
27
  self.request_id = request_id
27
28
  self.systems = systems
29
+ self.version = version # system_version_unverified: the version the system last reported
30
+ self.reason = reason # system_version_unverified: unverified_version or unparseable
28
31
 
29
32
 
30
33
  class DeepdockTransportError(Exception):
@@ -63,7 +66,8 @@ class Deepdock:
63
66
  raise DeepdockTransportError(f"non-JSON answer with status {r.status_code}")
64
67
  if isinstance(body, dict) and "error" in body:
65
68
  e = body["error"]
66
- raise DeepdockError(r.status_code, e["code"], e["message"], e.get("requestId"), e.get("systems"))
69
+ raise DeepdockError(r.status_code, e["code"], e["message"], e.get("requestId"), e.get("systems"),
70
+ e.get("version"), e.get("reason"))
67
71
  if not isinstance(body, dict) or "data" not in body:
68
72
  raise DeepdockTransportError(f"unexpected body with status {r.status_code}")
69
73
  return body["data"], r.headers
@@ -122,12 +126,15 @@ class Deepdock:
122
126
  # Pending writes: one attempt against persisted state. Persist the row BEFORE the first send, so a
123
127
  # crash between send and answer cannot produce a second record under a new key. A job retries rows
124
128
  # left in "sent" with backoff (seconds, then minutes, for hours if the device stays offline).
129
+ # For system_version_unverified and device_outdated, poll the device's `writes` / `outdated` before
130
+ # retrying: they take longer than minutes.
125
131
  # --------------------------------------------------------------------------------------------------
126
132
 
127
133
  CONFLICT_RETRIES = 5 # a running write finishes within seconds; beyond this, treat it as unknown
128
134
 
129
- RETRY_SAME_KEY = {"device_offline", "device_syncing", "device_outdated", "target_busy",
130
- "temporarily_unavailable", "internal_error", "action_paused", "system_unavailable"}
135
+ RETRY_SAME_KEY = {"device_offline", "device_syncing", "device_outdated", "system_version_unverified",
136
+ "target_busy", "temporarily_unavailable", "internal_error", "action_paused",
137
+ "system_unavailable"}
131
138
 
132
139
 
133
140
  @dataclass
@@ -13,14 +13,24 @@ export class DeepdockError extends Error {
13
13
  readonly code: string
14
14
  readonly requestId?: string
15
15
  readonly systems?: string[]
16
+ /** system_version_unverified: the version the system last reported. */
17
+ readonly version?: string
18
+ /** system_version_unverified: `unverified_version` or `unparseable`. */
19
+ readonly reason?: string
16
20
 
17
- constructor(status: number, code: string, message: string, requestId?: string, systems?: string[]) {
21
+ constructor(status: number, code: string, message: string, requestId?: string,
22
+ systems?: string[],
23
+ version?: string,
24
+ reason?: string,
25
+ ) {
18
26
  super(message)
19
27
  this.name = 'DeepdockError'
20
28
  this.status = status
21
29
  this.code = code
22
30
  this.requestId = requestId
23
31
  this.systems = systems
32
+ this.version = version
33
+ this.reason = reason
24
34
  }
25
35
  }
26
36
 
@@ -32,7 +42,7 @@ export class DeepdockTransportError extends Error {
32
42
  }
33
43
  }
34
44
 
35
- type ErrorBody = { code: string; message: string; requestId?: string; systems?: string[] }
45
+ type ErrorBody = { code: string; message: string; requestId?: string; systems?: string[]; version?: string; reason?: string }
36
46
  type Envelope<T> = { data: T } | { error: ErrorBody }
37
47
 
38
48
  export type Page<Item> = { items: Item[]; nextCursor: string | null }
@@ -43,6 +53,15 @@ export type SystemStatus = 'running' | 'stopped' | 'missing' | 'unknown'
43
53
  /** The database access the device last reported; `null` while none is known. */
44
54
  export type SystemAccess = 'ok' | 'outdated' | 'missing' | 'not_set_up' | null
45
55
 
56
+ /**
57
+ * Whether writes on the system run. `unverified` makes writes answer system_version_unverified:
58
+ * `unverified_version` clears once Deepdock verifies the version; `unparseable` does not clear by
59
+ * waiting (contact Deepdock).
60
+ */
61
+ export type SystemWrites =
62
+ | { state: 'verified' | 'unknown' | 'partial' }
63
+ | { state: 'unverified'; reason: 'unverified_version' | 'unparseable' }
64
+
46
65
  export type Device = {
47
66
  id: string
48
67
  label: string | null
@@ -55,7 +74,14 @@ export type Device = {
55
74
  /** True when an action assigned to you needs a newer client: that action answers device_outdated. */
56
75
  outdated: boolean
57
76
  updateAvailable?: string
58
- systems: { system: string; version: string | null; status: SystemStatus; access: SystemAccess; reportedAt: string }[]
77
+ systems: {
78
+ system: string
79
+ version: string | null
80
+ status: SystemStatus
81
+ access: SystemAccess
82
+ reportedAt: string
83
+ writes: SystemWrites
84
+ }[]
59
85
  }
60
86
 
61
87
  export type PairBody = { code: string; label?: string }
@@ -130,8 +156,8 @@ export class Deepdock {
130
156
  throw new DeepdockTransportError(`non-JSON answer with status ${res.status}`)
131
157
  }
132
158
  if (body !== null && typeof body === 'object' && 'error' in body) {
133
- const { code, message, requestId, systems } = body.error
134
- throw new DeepdockError(res.status, code, message, requestId, systems)
159
+ const { code, message, requestId, systems, version, reason } = body.error
160
+ throw new DeepdockError(res.status, code, message, requestId, systems, version, reason)
135
161
  }
136
162
  if (body === null || typeof body !== 'object' || !('data' in body)) {
137
163
  throw new DeepdockTransportError(`unexpected body with status ${res.status}`)
@@ -220,6 +246,8 @@ export class Deepdock {
220
246
  * Pending writes: one attempt against persisted state. Persist the row BEFORE the first send, so a
221
247
  * crash between send and answer cannot produce a second record under a new key. A job retries rows
222
248
  * left in `sent` with backoff (seconds, then minutes, for hours if the device stays offline).
249
+ * For system_version_unverified and device_outdated, poll the device's `writes` / `outdated` before
250
+ * retrying: they take longer than minutes.
223
251
  * ---------------------------------------------------------------------------------------------- */
224
252
 
225
253
  export type PendingStatus = 'pending' | 'sent' | 'done' | 'unknown' | 'refused'
@@ -246,6 +274,7 @@ const RETRY_SAME_KEY = new Set([
246
274
  'device_offline',
247
275
  'device_syncing',
248
276
  'device_outdated',
277
+ 'system_version_unverified',
249
278
  'target_busy',
250
279
  'temporarily_unavailable',
251
280
  'internal_error',
@@ -25,7 +25,7 @@ The Deepdock client installed on the customer's Windows PC next to their system.
25
25
  outwards to Deepdock; nothing in the customer's network is opened to the internet. A device is
26
26
  identified by a UUID (`id`), carries a `label`, `hostname`, `os`, `clientVersion`, `status`
27
27
  (`connected`, `offline` or `inactive`), `lastSeenAt`, `claimedAt` (may be `null`), `outdated` (an
28
- assigned action needs a newer client: it answers `device_outdated`) and the `systems` it reported.
28
+ assigned action needs a newer client: it answers `device_outdated`) and the `systems` it reported (each with a `writes` state; reads always work). `verified`: writes run. `unknown`: no version was reported, and writes go through. `partial`: some writes run and some are refused. `unverified`: a write answers `system_version_unverified`; with `reason: unverified_version` it works once Deepdock has verified that version, with `reason: unparseable` retrying does not help and you contact Deepdock.
29
29
 
30
30
  - **Pair**: claim a device for your organisation with the 6-character code it shows while unpaired.
31
31
  - **Release**: `DELETE /v1/devices/{deviceId}` gives the device back; it shows a new code.
@@ -35,6 +35,7 @@ dashboard-only.
35
35
  | `access_missing` | 409 | the device's database access is gone (a removed database account or a lost secret on the PC); every action of that system is refused. Nothing was run. **No `Retry-After`** | as `access_outdated` | as `access_outdated` |
36
36
  | `pairing_code_invalid` | 404 | pairing: the code is unknown, expired, replaced, used, or its device is offline | with a fresh code | "read the code off the device screen again" |
37
37
  | `other_partner_build` | 409 | pairing: the device runs another partner's client build | no | "this device is set up for another provider" |
38
+ | `device_learning_only` | 409 | the PC runs the Deepdock client for learning only, which runs no actions; nothing was sent to it. Reads, writes and the systems list on it all answer this | no; it changes only when the Deepdock service is installed on that PC | "this PC needs the Deepdock service to run actions" |
38
39
 
39
40
  ## Input
40
41
 
@@ -56,6 +57,7 @@ dashboard-only.
56
57
  | `device_offline` | 503 | the device is not connected, is shutting down, or did not answer within 20 s. **A write may still have landed** | yes, with backoff (seconds to minutes); a write only with the same key | "the customer PC is offline; we will retry" |
57
58
  | `device_syncing` | 503 | the device has not reported its Deepdock client yet (just paired, or its report did not come through); Deepdock asks it again. Nothing was written | yes, after `Retry-After` (5 s); a write with the same key | "the customer PC is connecting; retrying" |
58
59
  | `device_outdated` | 409 | the device's Deepdock client is too old for this call. It updates itself when a newer version is released for your organisation, once nobody is signed in on the PC. Nothing was written | after the update (`outdated` on `GET /v1/devices/{deviceId}` turns `false`); retrying before it gets the same answer. A write keeps its key | "the Deepdock client on the customer PC needs an update" |
60
+ | `system_version_unverified` | 409 | a write on a system whose vendor version Deepdock has not verified yet. Nothing was sent to the device; reads still work. `error.version` is the version the system last reported and `error.reason` is `unverified_version`, or `unparseable` when that version is not dotted digits | `unverified_version`: after Deepdock has verified that version (`writes` on the system in `GET /v1/devices/{deviceId}` turns `verified`); retrying before it gets the same answer. `unparseable`: retrying does not help, contact Deepdock; only a different reported version changes it. A write keeps its key | "the customer's system was updated to a version Deepdock has not yet verified; changes will work once it has" |
59
61
  | `action_paused` | 503 | the action is paused on the device (`GET .../systems` shows `reason`); only Deepdock resumes it | later, when `GET .../systems` shows it active; do not loop | "this feature is paused while Deepdock checks the customer system" |
60
62
  | `system_unavailable` | 503 | the customer's program is stopped or missing on the device | later; often resolves when the customer restarts the program | "the customer's software is not running" |
61
63
  | `target_busy` | 503 | the customer's system is busy or unreachable | yes, with backoff | "the customer's system is busy; retrying" |
@@ -86,6 +88,7 @@ const REACTION: Record<string, Reaction> = {
86
88
  action_not_configured: 'stop',
87
89
  pairing_code_invalid: 'fix-input',
88
90
  other_partner_build: 'stop',
91
+ device_learning_only: 'stop',
89
92
  invalid_input: 'fix-input',
90
93
  target_rejected: 'fix-input',
91
94
  unknown_author: 'fix-input',
@@ -99,6 +102,7 @@ const REACTION: Record<string, Reaction> = {
99
102
  device_offline: 'retry-same-key',
100
103
  device_syncing: 'retry-same-key',
101
104
  device_outdated: 'retry-later',
105
+ system_version_unverified: 'retry-later',
102
106
  action_paused: 'wait-paused',
103
107
  system_unavailable: 'retry-later',
104
108
  target_busy: 'retry-same-key',
@@ -70,7 +70,7 @@ input, a status (`pending`, `sent`, `done`, `unknown`, `refused`) and the result
70
70
 
71
71
  ```
72
72
  pending ──send──▶ sent ──2xx (fresh or replayed)──────────────▶ done
73
- │ ──device_offline, device_syncing, device_outdated, timeout, network error, target_busy, temporarily_unavailable, internal_error ▶ sent (retry later, same key)
73
+ │ ──device_offline, device_syncing, device_outdated, system_version_unverified, timeout, network error, target_busy, temporarily_unavailable, internal_error ▶ sent (retry later, same key)
74
74
  │ ──idempotency_conflict, retries left ───▶ sent (retry, same key, same input)
75
75
  │ ──idempotency_conflict, retries spent ──▶ unknown (read back before anything else)
76
76
  │ ──outcome_unknown ──────────────────────▶ unknown (read back before anything else)