From 3c03c6866f9da988e67a961e72734671351453f0 Mon Sep 17 00:00:00 2001 From: Boris Dinkevich Date: Thu, 24 Sep 2026 18:25:33 +0300 Subject: [PATCH 1/4] DEV-6922: getDevices filters and connector block --- CHANGELOG.md | 14 +++++++ README.md | 2 +- docs/commands.md | 4 +- docs/flows/agent-ops.md | 4 +- package-lock.json | 4 +- package.json | 2 +- skills/xyte-cli/data/public-endpoints.json | 21 +++++++--- skills/xyte-cli/references/endpoints.md | 2 +- skills/xyte-cli/references/flow-recipes.md | 2 +- src/api-catalog/public-endpoints.json | 21 +++++++--- src/workflows/flow-catalog.ts | 2 +- tests/cli.test.ts | 46 ++++++++++++++++++++++ tests/endpoints.test.ts | 17 +++++++- tests/skills-edge-params-guidance.test.ts | 4 +- 14 files changed, 122 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 973b170..28b83df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,20 @@ The format is inspired by Keep a Changelog and this project follows SemVer for ` ## [Unreleased] +## [0.15.0] - 2026-09-24 + +### Added +- `organization.devices.getDevices` now lists the hub's device filters: `name` (case-insensitive substring), `status`, `effective_status`, `model_id`, `connection_method` (`native`/`c2c`/`edge`) and `connector_id`. Pass several statuses as a comma-separated string, e.g. `--query-json '{"status":"online,error"}'`. +- Device responses from `getDevices`, `getDevice` and `claimDevice` document the new `connector: { type, id, name }` block. + +### Changed +- The hub now rejects any other `getDevices` query parameter, and invalid filter values, with `422`. +- Device pagination guidance now names `next_page` only; the API docs were corrected from `has_next_page`. +- Bumped package metadata and lockfile to `0.15.0`. + +### Upgrade notes +- Run `xyte-cli skills refresh` after upgrading so installed skill bundles pick up the new filters. + ## [0.14.0] - 2026-08-03 ### Added diff --git a/README.md b/README.md index eea2ff3..f730e03 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ Key params: - `--tenant ` - `--output-mode envelope` for contract output - `--strict-json` for machine parsing -- For `organization.devices.getDevices`, increment `page` until `next_page` is null/absent or the response reports `has_next_page=false`. +- For `organization.devices.getDevices`, increment `page` until `next_page` is null/absent. Filters: `space_id`, `name`, `status`, `effective_status`, `model_id`, `connection_method`, `connector_id` (comma-separated for multiple statuses); any other query param returns 422. ### 2b) Device or space notes diff --git a/docs/commands.md b/docs/commands.md index b8ae35a..06d277d 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -144,7 +144,9 @@ xyte-cli api endpoints describe organization.groups.addUsers xyte-cli api endpoints describe partner.organizations.createOrganization xyte-cli api call organization.devices.getDevices --tenant --query-json '{"page":1,"per_page":100}' xyte-cli api call organization.devices.getDevices --tenant --query-json '{"page":1,"per_page":100}' --output-mode envelope --strict-json [--note ] -# For complete device inventories, increment page until the envelope response reports no continuation (`next_page` is null/absent, or `has_next_page=false` on tenants that return that field). +xyte-cli api call organization.devices.getDevices --tenant --query-json '{"name":"lobby","status":"offline,error","connection_method":"c2c"}' +# Filters: space_id, name, status, effective_status, model_id, connection_method, connector_id. Multi-value status/effective_status is a comma-separated string. Any other query param returns 422. +# For complete device inventories, increment page until the envelope response reports no continuation (`next_page` is null/absent). xyte-cli api call organization.devices.mergeDevice --tenant --path-json '{"device_id":""}' --body-json '{"with_device_ids":[""]}' --note "approved merge" xyte-cli api call organization.devices.splitDevice --tenant --path-json '{"device_id":""}' --body-json '{"shadow_device_id":""}' --note "approved split" xyte-cli api call organization.notes.getDeviceNotes --tenant --path-json '{"device_id":""}' --query-json '{"page":1,"per_page":100}' diff --git a/docs/flows/agent-ops.md b/docs/flows/agent-ops.md index a558c12..a84fd0e 100644 --- a/docs/flows/agent-ops.md +++ b/docs/flows/agent-ops.md @@ -254,7 +254,7 @@ xyte-cli api call organization.commands.getCommands \ ```bash mkdir -p ./artifacts ./reports xyte-cli api call organization.devices.getDevices --tenant --query-json '{"space_id":"","page":1,"per_page":100}' --output-mode envelope --output json > ./artifacts/source-devices.page-1.json -# Repeat page 2, 3, ... until the response reports no continuation (`next_page` is null/absent, or `has_next_page=false` on tenants that return that field), then combine items into ./artifacts/source-devices.json. +# Repeat page 2, 3, ... until the response reports no continuation (`next_page` is null/absent), then combine items into ./artifacts/source-devices.json. xyte-cli api call organization.spaces.getSpaces --tenant --query path_includes= --output json > ./artifacts/target-spaces.json xyte-cli util match --tenant --source ./artifacts/source-devices.json --target ./artifacts/target-spaces.json --source-field name --target-field name --out ./artifacts/device-moves.csv xyte-cli ops report generate --tenant --input ./artifacts/device-moves.csv.summary.json --out ./reports/device-migration-pre.md --render markdown @@ -264,7 +264,7 @@ xyte-cli ops inspect fleet --tenant --output json --out ./artifacts/ ``` - Expected artifacts: - - complete source device inventory JSON, collected across all `getDevices` pages until no `next_page` / `has_next_page` continuation remains, and target space inventory JSON. + - complete source device inventory JSON, collected across all `getDevices` pages until no `next_page` continuation remains, and target space inventory JSON. - deterministic move CSV at `./artifacts/device-moves.csv` plus summary JSON sidecar. - pre-migration markdown report at `./reports/device-migration-pre.md`. - dry-run and apply NDJSON row reports for move execution. diff --git a/package-lock.json b/package-lock.json index 7b5dd0d..4fe6025 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@xyteai/cli", - "version": "0.14.0", + "version": "0.15.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@xyteai/cli", - "version": "0.14.0", + "version": "0.15.0", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api": "^1.9.0", diff --git a/package.json b/package.json index ec83d04..116d5ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@xyteai/cli", - "version": "0.14.0", + "version": "0.15.0", "description": "Xyte CLI, TUI, skills, and headless contracts for zero-friction AI operations", "license": "Apache-2.0", "repository": { diff --git a/skills/xyte-cli/data/public-endpoints.json b/skills/xyte-cli/data/public-endpoints.json index ea946be..68a434c 100644 --- a/skills/xyte-cli/data/public-endpoints.json +++ b/skills/xyte-cli/data/public-endpoints.json @@ -105,7 +105,8 @@ "Docs page: https://docs.xyte.io/reference/claim-device", "Docs category: /branches/2.0/categories/reference/API Access", "Docs parent: /branches/2.0/reference/devices-2", - "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status." + "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status.", + "Response includes connector: { type: native|c2c|edge, id: uuid|null, name: string|null }." ] }, { @@ -296,7 +297,8 @@ "Docs category: /branches/2.0/categories/reference/API Access", "Docs parent: /branches/2.0/reference/devices-2", "Docs raw path params: device_id", - "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status." + "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status.", + "Response includes connector: { type: native|c2c|edge, id: uuid|null, name: string|null }." ] }, { @@ -312,7 +314,13 @@ "queryParams": [ "page", "per_page", - "space_id" + "space_id", + "name", + "status", + "effective_status", + "model_id", + "connection_method", + "connector_id" ], "authScope": "organization", "bodyType": "none", @@ -322,8 +330,11 @@ "Docs page: https://docs.xyte.io/reference/get-devices", "Docs category: /branches/2.0/categories/reference/API Access", "Docs parent: /branches/2.0/reference/devices-2", - "Paginated response includes items plus a continuation field. Shared docs describe has_next_page; live Verve/Playground responses on 2026-07-06 returned next_page. Handle either field. page starts at 1; per_page defaults to 100 and is capped at 100.", - "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status." + "Paginated response includes items plus next_page (null/absent on the last page). Docs previously described has_next_page and were corrected to next_page. page starts at 1; per_page defaults to 100 and values above 100 are rejected.", + "Filters combine with AND: name is a case-insensitive substring match; status is one or more of online, offline, unavailable, error; effective_status is one or more of ok, warning, error, offline, disconnected, never_seen; model_id is a device model UUID; connection_method is one of native, c2c, edge; connector_id is the UUID of a C2C integration or edge (a device's connector.id). Pass multi-value status/effective_status as a comma-separated string, e.g. {\"status\":\"online,error\"}.", + "Any other query parameter returns 422 Unsupported query parameter(s). Invalid enum values or non-UUID model_id/connector_id return 422.", + "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status.", + "Each device includes connector: { type: native|c2c|edge, id: uuid|null, name: string|null }." ] }, { diff --git a/skills/xyte-cli/references/endpoints.md b/skills/xyte-cli/references/endpoints.md index cdde7fb..02fc3d5 100644 --- a/skills/xyte-cli/references/endpoints.md +++ b/skills/xyte-cli/references/endpoints.md @@ -42,7 +42,7 @@ Derived from the bundled public endpoint spec. | Endpoint Key | Query Fields | Pagination Fields | Notes | | --- | --- | --- | --- | | `organization.spaces.getSpaces` | `id`, `name`, `parent_id`, `space_type`, `created_before`, `created_after`, `path_includes` | none | Main listing endpoint with server-side filtering | -| `organization.devices.getDevices` | `page`, `per_page`, `space_id` | `page`, `per_page` | Filter devices by one space; shared docs mention `has_next_page`, live Verve/Playground responses returned `next_page`; handle either continuation field | +| `organization.devices.getDevices` | `page`, `per_page`, `space_id`, `name`, `status`, `effective_status`, `model_id`, `connection_method`, `connector_id` | `page`, `per_page` | Filters combine with AND; `name` is a case-insensitive substring; `status` (online/offline/unavailable/error) and `effective_status` (ok/warning/error/offline/disconnected/never_seen) take a comma-separated list; `connection_method` is native/c2c/edge; `model_id`/`connector_id` are UUIDs (`connector_id` = a device's `connector.id`). Unknown params and invalid values return 422. Continue while `next_page` is set. Each device carries `connector: {type, id, name}` | | `organization.devices.getHistories` | `status`, `from`, `to`, `device_id`, `space_id`, `name` | none | Filtered history lookup; can be time-windowed | | `organization.commands.getCommands` | `status`, `page`, `per_page` | `page`, `per_page` | Command history pagination and status filter | | `organization.incidents.getIncidents` | `from`, `to`, `status`, `priority`, `title`, `description`, `issue`, `device_model`, `partner_name`, `sub_model`, `space_id`, `page`, `per_page` | `page`, `per_page` | Incident filtering matrix. Use integer `from` and `to`; for reliable active-incident fetches use both (`from=0`, `to=`). | diff --git a/skills/xyte-cli/references/flow-recipes.md b/skills/xyte-cli/references/flow-recipes.md index 5ce9498..7b342c0 100644 --- a/skills/xyte-cli/references/flow-recipes.md +++ b/skills/xyte-cli/references/flow-recipes.md @@ -118,7 +118,7 @@ xyte-cli api call organization.commands.getCommands \ ```bash mkdir -p ./artifacts ./reports xyte-cli api call organization.devices.getDevices --tenant --query-json '{"space_id":"","page":1,"per_page":100}' --output-mode envelope --output json > ./artifacts/source-devices.page-1.json -# Repeat page 2, 3, ... until the response reports no continuation (`next_page` is null/absent, or `has_next_page=false` on tenants that return that field), then combine items into ./artifacts/source-devices.json. +# Repeat page 2, 3, ... until the response reports no continuation (`next_page` is null/absent), then combine items into ./artifacts/source-devices.json. xyte-cli api call organization.spaces.getSpaces --tenant --query path_includes= --output json > ./artifacts/target-spaces.json xyte-cli util match --tenant --source ./artifacts/source-devices.json --target ./artifacts/target-spaces.json --source-field name --target-field name --out ./artifacts/device-moves.csv xyte-cli ops report generate --tenant --input ./artifacts/device-moves.csv.summary.json --out ./reports/device-migration-pre.md --render markdown diff --git a/src/api-catalog/public-endpoints.json b/src/api-catalog/public-endpoints.json index ea946be..68a434c 100644 --- a/src/api-catalog/public-endpoints.json +++ b/src/api-catalog/public-endpoints.json @@ -105,7 +105,8 @@ "Docs page: https://docs.xyte.io/reference/claim-device", "Docs category: /branches/2.0/categories/reference/API Access", "Docs parent: /branches/2.0/reference/devices-2", - "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status." + "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status.", + "Response includes connector: { type: native|c2c|edge, id: uuid|null, name: string|null }." ] }, { @@ -296,7 +297,8 @@ "Docs category: /branches/2.0/categories/reference/API Access", "Docs parent: /branches/2.0/reference/devices-2", "Docs raw path params: device_id", - "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status." + "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status.", + "Response includes connector: { type: native|c2c|edge, id: uuid|null, name: string|null }." ] }, { @@ -312,7 +314,13 @@ "queryParams": [ "page", "per_page", - "space_id" + "space_id", + "name", + "status", + "effective_status", + "model_id", + "connection_method", + "connector_id" ], "authScope": "organization", "bodyType": "none", @@ -322,8 +330,11 @@ "Docs page: https://docs.xyte.io/reference/get-devices", "Docs category: /branches/2.0/categories/reference/API Access", "Docs parent: /branches/2.0/reference/devices-2", - "Paginated response includes items plus a continuation field. Shared docs describe has_next_page; live Verve/Playground responses on 2026-07-06 returned next_page. Handle either field. page starts at 1; per_page defaults to 100 and is capped at 100.", - "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status." + "Paginated response includes items plus next_page (null/absent on the last page). Docs previously described has_next_page and were corrected to next_page. page starts at 1; per_page defaults to 100 and values above 100 are rejected.", + "Filters combine with AND: name is a case-insensitive substring match; status is one or more of online, offline, unavailable, error; effective_status is one or more of ok, warning, error, offline, disconnected, never_seen; model_id is a device model UUID; connection_method is one of native, c2c, edge; connector_id is the UUID of a C2C integration or edge (a device's connector.id). Pass multi-value status/effective_status as a comma-separated string, e.g. {\"status\":\"online,error\"}.", + "Any other query parameter returns 422 Unsupported query parameter(s). Invalid enum values or non-UUID model_id/connector_id return 422.", + "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status.", + "Each device includes connector: { type: native|c2c|edge, id: uuid|null, name: string|null }." ] }, { diff --git a/src/workflows/flow-catalog.ts b/src/workflows/flow-catalog.ts index 1b073e7..baf3a77 100644 --- a/src/workflows/flow-catalog.ts +++ b/src/workflows/flow-catalog.ts @@ -668,7 +668,7 @@ const FLOWS: Record = { recipeCommands: [ 'mkdir -p ./artifacts ./reports', `xyte-cli api call organization.devices.getDevices --tenant --query-json '{"space_id":"","page":1,"per_page":100}' --output-mode envelope --output json > ./artifacts/source-devices.page-1.json`, - '# Repeat page 2, 3, ... until the response reports no continuation (`next_page` is null/absent, or `has_next_page=false` on tenants that return that field), then combine items into ./artifacts/source-devices.json.', + '# Repeat page 2, 3, ... until the response reports no continuation (`next_page` is null/absent), then combine items into ./artifacts/source-devices.json.', 'xyte-cli api call organization.spaces.getSpaces --tenant --query path_includes= --output json > ./artifacts/target-spaces.json', 'xyte-cli util match --tenant --source ./artifacts/source-devices.json --target ./artifacts/target-spaces.json --source-field name --target-field name --out ./artifacts/device-moves.csv', 'xyte-cli ops report generate --tenant --input ./artifacts/device-moves.csv.summary.json --out ./reports/device-migration-pre.md --render markdown', diff --git a/tests/cli.test.ts b/tests/cli.test.ts index adcc746..44bb4c0 100644 --- a/tests/cli.test.ts +++ b/tests/cli.test.ts @@ -2158,6 +2158,52 @@ describe('cli integration', () => { expect(parsed.response.status).toBe(200); }); + it('serializes getDevices filters as scalar query params with comma lists', async () => { + const profileStore = new MemoryProfileStore(); + await profileStore.upsertTenant({ id: 'acme' }); + await profileStore.setActiveTenant('acme'); + const secretStore = new MemorySecretStore(); + await secretStore.setSecret('acme', 'xyte-org', 'org-key'); + const stdout = { write: vi.fn() }; + const stderr = { write: vi.fn() }; + const program = createCli({ profileStore, secretStore, stdout, stderr }); + + const fetchMock = vi.fn().mockResolvedValue( + new Response(JSON.stringify({ items: [], next_page: null }), { + status: 200, + headers: { 'content-type': 'application/json' } + }) + ); + vi.stubGlobal('fetch', fetchMock); + + await program.parseAsync([ + 'node', + 'xyte-cli', + 'api', + 'call', + 'organization.devices.getDevices', + '--tenant', + 'acme', + '--query-json', + '{"name":"lobby","status":"online,error","effective_status":"warning","connection_method":"c2c","connector_id":"5b1f0c2e-7a4d-4c1e-9f3a-2d6b8e1c0a11","page":1,"per_page":100}' + ]); + + const [requestUrl, init] = fetchMock.mock.calls[0] as [string, RequestInit]; + const url = new URL(String(requestUrl)); + expect(init.method).toBe('GET'); + expect(init.body).toBeUndefined(); + expect(url.pathname).toBe('/core/v1/organization/devices'); + expect(Object.fromEntries(url.searchParams)).toEqual({ + name: 'lobby', + status: 'online,error', + effective_status: 'warning', + connection_method: 'c2c', + connector_id: '5b1f0c2e-7a4d-4c1e-9f3a-2d6b8e1c0a11', + page: '1', + per_page: '100' + }); + }); + it('rejects invalid output-mode values for api call', async () => { const profileStore = new MemoryProfileStore(); await profileStore.upsertTenant({ id: 'acme' }); diff --git a/tests/endpoints.test.ts b/tests/endpoints.test.ts index 7312b78..b6b17fe 100644 --- a/tests/endpoints.test.ts +++ b/tests/endpoints.test.ts @@ -143,9 +143,22 @@ describe('public endpoint catalog', () => { it('includes documented filter params for key read endpoints', () => { const getDevices = endpoints.find((item) => item.key === 'organization.devices.getDevices'); - expect(getDevices?.queryParams).toEqual(['page', 'per_page', 'space_id']); - expect(getDevices?.notes?.join(' ')).toContain('has_next_page'); + expect(getDevices?.queryParams).toEqual([ + 'page', + 'per_page', + 'space_id', + 'name', + 'status', + 'effective_status', + 'model_id', + 'connection_method', + 'connector_id' + ]); expect(getDevices?.notes?.join(' ')).toContain('next_page'); + expect(getDevices?.notes?.join(' ')).toContain('Unsupported query parameter'); + for (const key of ['organization.devices.getDevices', 'organization.devices.getDevice', 'organization.devices.claimDevice']) { + expect(endpoints.find((item) => item.key === key)?.notes?.join(' ')).toContain('connector: { type: native|c2c|edge'); + } const getHistories = endpoints.find((item) => item.key === 'organization.devices.getHistories'); expect(getHistories?.queryParams).toEqual(['status', 'from', 'to', 'device_id', 'space_id', 'name']); diff --git a/tests/skills-edge-params-guidance.test.ts b/tests/skills-edge-params-guidance.test.ts index d17cfc8..7ad3104 100644 --- a/tests/skills-edge-params-guidance.test.ts +++ b/tests/skills-edge-params-guidance.test.ts @@ -46,7 +46,9 @@ describe('edge custom params docs and skill guidance', () => { for (const content of [readme, commands]) { expect(content).toContain('organization.devices.getDevices'); expect(content).toContain('"page":1,"per_page":100'); - expect(content).toContain('has_next_page=false'); + expect(content).toContain('`next_page` is null/absent'); + expect(content).not.toContain('has_next_page'); + expect(content).toContain('connector_id'); } }); From 5215a77cf109cabce7911601469acafe2fa9d8ee Mon Sep 17 00:00:00 2001 From: Boris Dinkevich Date: Thu, 1 Oct 2026 22:33:55 +0300 Subject: [PATCH 2/4] DEV-6922: note that status filters can trail live status by up to a minute (review 4153771956) --- skills/xyte-cli/data/public-endpoints.json | 2 +- skills/xyte-cli/references/endpoints.md | 2 +- src/api-catalog/public-endpoints.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/skills/xyte-cli/data/public-endpoints.json b/skills/xyte-cli/data/public-endpoints.json index 0de2480..b79c9b0 100644 --- a/skills/xyte-cli/data/public-endpoints.json +++ b/skills/xyte-cli/data/public-endpoints.json @@ -331,7 +331,7 @@ "Docs category: /branches/2.0/categories/reference/API Access", "Docs parent: /branches/2.0/reference/devices-2", "Paginated response includes items plus next_page (null/absent on the last page). Docs previously described has_next_page and were corrected to next_page. page starts at 1; per_page defaults to 100 and values above 100 are rejected.", - "Filters combine with AND: name is a case-insensitive substring match; status is one or more of online, offline, unavailable, error; effective_status is one or more of ok, warning, error, offline, disconnected, never_seen; model_id is a device model UUID; connection_method is one of native, c2c, edge; connector_id is the UUID of a C2C integration or edge (a device's connector.id). Pass multi-value status/effective_status as a comma-separated string, e.g. {\"status\":\"online,error\"}.", + "Filters combine with AND: name is a case-insensitive substring match; status is one or more of online, offline, unavailable, error; effective_status is one or more of ok, warning, error, offline, disconnected, never_seen; model_id is a device model UUID; connection_method is one of native, c2c, edge; connector_id is the UUID of a C2C integration or edge (a device's connector.id). Pass multi-value status/effective_status as a comma-separated string, e.g. {\"status\":\"online,error\"}. Status filters can trail the live status by up to a minute, so a returned device's status may not match the filter yet.", "Any other query parameter returns 422 Unsupported query parameter(s). Invalid enum values or non-UUID model_id/connector_id return 422.", "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status.", "Each device includes connector: { type: native|c2c|edge, id: uuid|null, name: string|null }." diff --git a/skills/xyte-cli/references/endpoints.md b/skills/xyte-cli/references/endpoints.md index b71995f..b0065fa 100644 --- a/skills/xyte-cli/references/endpoints.md +++ b/skills/xyte-cli/references/endpoints.md @@ -42,7 +42,7 @@ Derived from the bundled public endpoint spec. | Endpoint Key | Query Fields | Pagination Fields | Notes | | --- | --- | --- | --- | | `organization.spaces.getSpaces` | `id`, `name`, `parent_id`, `space_type`, `created_before`, `created_after`, `path_includes` | none | Main listing endpoint with server-side filtering | -| `organization.devices.getDevices` | `page`, `per_page`, `space_id`, `name`, `status`, `effective_status`, `model_id`, `connection_method`, `connector_id` | `page`, `per_page` | Filters combine with AND; `name` is a case-insensitive substring; `status` (online/offline/unavailable/error) and `effective_status` (ok/warning/error/offline/disconnected/never_seen) take a comma-separated list; `connection_method` is native/c2c/edge; `model_id`/`connector_id` are UUIDs (`connector_id` = a device's `connector.id`). Unknown params and invalid values return 422. Continue while `next_page` is set. Each device carries `connector: {type, id, name}` | +| `organization.devices.getDevices` | `page`, `per_page`, `space_id`, `name`, `status`, `effective_status`, `model_id`, `connection_method`, `connector_id` | `page`, `per_page` | Filters combine with AND; `name` is a case-insensitive substring; `status` (online/offline/unavailable/error) and `effective_status` (ok/warning/error/offline/disconnected/never_seen) take a comma-separated list and can trail the live `status` by up to a minute; `connection_method` is native/c2c/edge; `model_id`/`connector_id` are UUIDs (`connector_id` = a device's `connector.id`). Unknown params and invalid values return 422. Continue while `next_page` is set. Each device carries `connector: {type, id, name}` | | `organization.devices.getHistories` | `status`, `from`, `to`, `device_id`, `space_id`, `name`, `page`, `per_page` | `page`, `per_page` | Filtered history lookup. `from`/`to` window must not exceed 31 days (422 otherwise); defaults: `from` = 1 week ago, `to` = now, applied independently — send both. `status` filters the device's *current* status. | | `organization.commands.getCommands` | `status`, `page`, `per_page` | `page`, `per_page` | Command history pagination and status filter | | `organization.incidents.getIncidents` | `from`, `to`, `status`, `priority`, `title`, `description`, `issue`, `device_model`, `partner_name`, `sub_model`, `space_id`, `page`, `per_page` | `page`, `per_page` | Incident filtering matrix. Use integer `from` and `to`; for reliable active-incident fetches use both (`from=0`, `to=`). | diff --git a/src/api-catalog/public-endpoints.json b/src/api-catalog/public-endpoints.json index 0de2480..b79c9b0 100644 --- a/src/api-catalog/public-endpoints.json +++ b/src/api-catalog/public-endpoints.json @@ -331,7 +331,7 @@ "Docs category: /branches/2.0/categories/reference/API Access", "Docs parent: /branches/2.0/reference/devices-2", "Paginated response includes items plus next_page (null/absent on the last page). Docs previously described has_next_page and were corrected to next_page. page starts at 1; per_page defaults to 100 and values above 100 are rejected.", - "Filters combine with AND: name is a case-insensitive substring match; status is one or more of online, offline, unavailable, error; effective_status is one or more of ok, warning, error, offline, disconnected, never_seen; model_id is a device model UUID; connection_method is one of native, c2c, edge; connector_id is the UUID of a C2C integration or edge (a device's connector.id). Pass multi-value status/effective_status as a comma-separated string, e.g. {\"status\":\"online,error\"}.", + "Filters combine with AND: name is a case-insensitive substring match; status is one or more of online, offline, unavailable, error; effective_status is one or more of ok, warning, error, offline, disconnected, never_seen; model_id is a device model UUID; connection_method is one of native, c2c, edge; connector_id is the UUID of a C2C integration or edge (a device's connector.id). Pass multi-value status/effective_status as a comma-separated string, e.g. {\"status\":\"online,error\"}. Status filters can trail the live status by up to a minute, so a returned device's status may not match the filter yet.", "Any other query parameter returns 422 Unsupported query parameter(s). Invalid enum values or non-UUID model_id/connector_id return 422.", "Response includes effective_status (nullable string): one of ok, warning, error, offline, disconnected, never_seen. Computed device status reflecting incident priority, connectivity, telemetry-seen state, and raw device status.", "Each device includes connector: { type: native|c2c|edge, id: uuid|null, name: string|null }." From de40e0ada73d66f11bd812ed845e5e449153da36 Mon Sep 17 00:00:00 2001 From: Boris Dinkevich Date: Thu, 1 Oct 2026 22:33:55 +0300 Subject: [PATCH 3/4] DEV-6922: drop the whole-file has_next_page negative check (review 4153771948) --- tests/skills-edge-params-guidance.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/skills-edge-params-guidance.test.ts b/tests/skills-edge-params-guidance.test.ts index 7ad3104..8579d94 100644 --- a/tests/skills-edge-params-guidance.test.ts +++ b/tests/skills-edge-params-guidance.test.ts @@ -47,7 +47,6 @@ describe('edge custom params docs and skill guidance', () => { expect(content).toContain('organization.devices.getDevices'); expect(content).toContain('"page":1,"per_page":100'); expect(content).toContain('`next_page` is null/absent'); - expect(content).not.toContain('has_next_page'); expect(content).toContain('connector_id'); } }); From 5dfcedd381b59ad654de37fbf0358d243bdb0421 Mon Sep 17 00:00:00 2001 From: Boris Dinkevich Date: Thu, 1 Oct 2026 22:33:55 +0300 Subject: [PATCH 4/4] DEV-6922: changelog tip names effective_status too (review 4153771942) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9979d7c..0bb309c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ The format is inspired by Keep a Changelog and this project follows SemVer for ` ## [0.15.0] - 2026-09-24 ### Added -- `organization.devices.getDevices` now lists the hub's device filters: `name` (case-insensitive substring), `status`, `effective_status`, `model_id`, `connection_method` (`native`/`c2c`/`edge`) and `connector_id`. Pass several statuses as a comma-separated string, e.g. `--query-json '{"status":"online,error"}'`. +- `organization.devices.getDevices` now lists the hub's device filters: `name` (case-insensitive substring), `status`, `effective_status`, `model_id`, `connection_method` (`native`/`c2c`/`edge`) and `connector_id`. Pass several `status` / `effective_status` values as a comma-separated string, e.g. `--query-json '{"status":"online,error"}'`. - Device responses from `getDevices`, `getDevice` and `claimDevice` document the new `connector: { type, id, name }` block. ### Changed