chore: initial commit
This commit is contained in:
commit
433471fd24
12 files changed
+1073
No files matched your search
@@ -0,0 +1,21 @@
|
|||||||
|
name: CI
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
jobs:
|
||||||
|
validate-skill:
|
||||||
|
name: Validate Agent Skill
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v7
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
- name: Validate skill specification
|
||||||
|
run: npx skills-ref validate .
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
name: Release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
jobs:
|
||||||
|
publish-release:
|
||||||
|
name: Package and Release Skill
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v7
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
- name: Validate skill specification
|
||||||
|
run: npx skills-ref validate .
|
||||||
|
- name: Package skill archives
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
VERSION="${GITHUB_REF_NAME}"
|
||||||
|
ARCHIVE_NAME="onx-skill-${VERSION}"
|
||||||
|
STAGE_DIR="staging/${ARCHIVE_NAME}"
|
||||||
|
mkdir -p "${STAGE_DIR}"
|
||||||
|
|
||||||
|
cp -r SKILL.md README.md LICENSE.md references scripts "${STAGE_DIR}/"
|
||||||
|
|
||||||
|
tar -czf "${ARCHIVE_NAME}.tar.gz" -C staging "${ARCHIVE_NAME}"
|
||||||
|
sha256sum "${ARCHIVE_NAME}.tar.gz" > "${ARCHIVE_NAME}.tar.gz.sha256"
|
||||||
|
|
||||||
|
zip -r "${ARCHIVE_NAME}.zip" staging/"${ARCHIVE_NAME}"
|
||||||
|
sha256sum "${ARCHIVE_NAME}.zip" > "${ARCHIVE_NAME}.zip.sha256"
|
||||||
|
|
||||||
|
mkdir dist
|
||||||
|
mv "${ARCHIVE_NAME}".* dist/
|
||||||
|
cd dist
|
||||||
|
cat *.sha256 > SHA256SUMS.txt
|
||||||
|
- name: Create GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v3
|
||||||
|
with:
|
||||||
|
name: Release ${{ github.ref_name }}
|
||||||
|
generate_release_notes: true
|
||||||
|
files: |
|
||||||
|
dist/*.tar.gz
|
||||||
|
dist/*.zip
|
||||||
|
dist/*.sha256
|
||||||
|
dist/SHA256SUMS.txt
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
*.tar.gz
|
||||||
|
*.zip
|
||||||
|
*.sha256
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Copyright (c) 2026 Stevan Freeborn
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# onx-skill
|
||||||
|
|
||||||
|
An Agent Skill adhering to the [Agent Skills Specification](https://agentskills.io) enabling AI agents to interact with the Onspring platform via the [`onx`](https://github.com/StevanFreeborn/onx) CLI.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This skill equips agents with the instructions, progressive documentation, and bootstrap scripts necessary to perform Onspring operations.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Using `skills` Package Manager
|
||||||
|
|
||||||
|
Install directly using [`skills`](https://skills.sh) to automatically configure the skill for any of your installed agents:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install to your project
|
||||||
|
npx skills add StevanFreeborn/onx-skill
|
||||||
|
|
||||||
|
# Or install globally for all sessions
|
||||||
|
npx skills add StevanFreeborn/onx-skill -g
|
||||||
|
```
|
||||||
|
|
||||||
|
To update the skill to the latest version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx skills update onx-skill
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Installation (Git Clone or Download)
|
||||||
|
|
||||||
|
Clone or symlink the repository into your agent's skills directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/StevanFreeborn/onx-skill.git <path-to-agent-skills>/onx-skill
|
||||||
|
```
|
||||||
|
|
||||||
|
Packaged `.tar.gz` and `.zip` archives are also available on the [Releases](https://github.com/StevanFreeborn/onx-skill/releases) page.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> The skill includes automated bootstrap scripts in `scripts/` to install the `onx` CLI binary on Windows, Linux, and macOS if it is not already present in `PATH`.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
`onx` authenticates with the Onspring API using credentials resolved in the following priority order:
|
||||||
|
|
||||||
|
1. **Command-line options**: `--api-key <KEY> --base-url <URL>`
|
||||||
|
2. **Configuration file**: `~/.config/onx/config.json` (or via `--config <PATH>`)
|
||||||
|
3. **Environment variables**: `ONSPRING_API_KEY`, `ONSPRING_BASE_URL`
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export ONSPRING_API_KEY="your-api-key"
|
||||||
|
export ONSPRING_BASE_URL="https://api.onspring.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration File (`~/.config/onx/config.json`)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"apiKey": "your-api-key",
|
||||||
|
"baseUrl": "https://api.onspring.com",
|
||||||
|
"pretty": true
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
---
|
||||||
|
name: onx-skill
|
||||||
|
description: Interact with the Onspring platform via the onx CLI. Manage apps, records, fields, files, lists, and reports. Use when querying Onspring records, modifying data, fetching schema metadata, or automating Onspring operations.
|
||||||
|
license: MIT
|
||||||
|
compatibility: Requires onx CLI binary, network access to Onspring API instance, and an Onspring API Key.
|
||||||
|
metadata:
|
||||||
|
author: Stevan Freeborn
|
||||||
|
version: "0.0.0"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Onspring Agent Skill (`onx-skill`)
|
||||||
|
|
||||||
|
Use this skill to interact with the Onspring platform using the `onx` command-line tool.
|
||||||
|
|
||||||
|
All capabilities, options, and JSON payload structures in this skill are grounded directly in the `onx` CLI source and the [Onspring API v2 Specification](https://onspringapidocs.stevanfreeborn.com/).
|
||||||
|
|
||||||
|
## Ground Truth & CLI Introspection
|
||||||
|
|
||||||
|
> **Important**: The `onx` CLI is the ultimate source of truth. Always run `onx <command> --help` to inspect real-time arguments, options, and commands if unsure of syntax:
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> onx --help
|
||||||
|
> onx <subcommand> --help
|
||||||
|
> ```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisites & Installation
|
||||||
|
|
||||||
|
Verify if `onx` is installed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx --version
|
||||||
|
```
|
||||||
|
|
||||||
|
If `onx` is not installed or not in `PATH`, install it using one of the helper scripts in `scripts/`:
|
||||||
|
|
||||||
|
### Windows (PowerShell)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\scripts\install-onx.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Or directly from GitHub:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
irm https://raw.githubusercontent.com/StevanFreeborn/onx/main/scripts/install.ps1 | iex
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux & macOS (Bash)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/install-onx.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Or directly from GitHub:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/StevanFreeborn/onx/main/scripts/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Authentication & Configuration
|
||||||
|
|
||||||
|
`onx` reads credentials using the following precedence:
|
||||||
|
|
||||||
|
1. **Command-line flags**: `--api-key <KEY> --base-url <URL>`
|
||||||
|
2. **Configuration file**: `~/.config/onx/config.json` (or `--config <PATH>`)
|
||||||
|
3. **Environment variables**: `ONSPRING_API_KEY`, `ONSPRING_BASE_URL`
|
||||||
|
|
||||||
|
### Recommended Agent Setup (Environment Variables)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export ONSPRING_API_KEY="your-api-key"
|
||||||
|
export ONSPRING_BASE_URL="https://api.onspring.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows PowerShell:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:ONSPRING_API_KEY = "your-api-key"
|
||||||
|
$env:ONSPRING_BASE_URL = "https://api.onspring.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
For more configuration details and file templates, see [references/configuration.md](references/configuration.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Workflows
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Global flags (e.g. `--pretty`, `--api-key`) must precede subcommands:
|
||||||
|
> `onx --pretty ping` or `onx --pretty apps list`
|
||||||
|
|
||||||
|
### Connectivity Check
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx ping
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schema Discovery (Apps & Fields)
|
||||||
|
|
||||||
|
Before operating on records, discover the target App ID and Field IDs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List all apps
|
||||||
|
onx apps list
|
||||||
|
|
||||||
|
# Get details of a specific app
|
||||||
|
onx apps get --app 195
|
||||||
|
|
||||||
|
# List fields within an app
|
||||||
|
onx fields list --app 195
|
||||||
|
|
||||||
|
# Get field metadata (type, multiplicity, list values, formula output type)
|
||||||
|
onx fields get --field 6983
|
||||||
|
```
|
||||||
|
|
||||||
|
### Querying Records
|
||||||
|
|
||||||
|
Retrieve records matching filter expressions. String values in filters must use single quotes `'`. Date filters must be preceded by `datetime` (e.g., `datetime'2026-01-01T00:00:00Z'`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx records query --json '{"appId": 195, "filter": "6983 eq '\''Active'\''"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
With pagination and specific field IDs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx records query --page-number 1 --page-size 20 --json '{
|
||||||
|
"appId": 195,
|
||||||
|
"filter": "6983 eq '\''Active'\'' and 6987 gt 100",
|
||||||
|
"fieldIds": [6983, 6986, 6987],
|
||||||
|
"dataFormat": "Formatted"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Retrieving Records
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get single record by system Record ID
|
||||||
|
onx records get --app 195 --record 1
|
||||||
|
|
||||||
|
# Batch get records by IDs
|
||||||
|
onx records batch-get --json '{"appId": 195, "recordIds": [1, 2]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating or Updating Records
|
||||||
|
|
||||||
|
Use `records save` with a JSON payload. Pass field values mapped by string Field IDs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create record (omit recordId or set to null)
|
||||||
|
onx records save --json '{
|
||||||
|
"appId": 195,
|
||||||
|
"recordId": null,
|
||||||
|
"fields": {
|
||||||
|
"6983": "New Task",
|
||||||
|
"6986": "4118d53a-9121-4345-8682-07f23d606daa",
|
||||||
|
"6987": [4]
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
|
||||||
|
# Update existing record
|
||||||
|
onx records save --json '{
|
||||||
|
"appId": 195,
|
||||||
|
"recordId": 140,
|
||||||
|
"fields": {
|
||||||
|
"6983": "Updated Task Title"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deleting Records
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Single record
|
||||||
|
onx records delete --app 195 --record 140
|
||||||
|
|
||||||
|
# Batch delete records
|
||||||
|
onx records batch-delete --json '{"appId": 195, "recordIds": [140, 141]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Files, Lists, & Reports
|
||||||
|
|
||||||
|
- **Files**: Inspect metadata (`onx files info --record 1 --field 6989 --file 89`), download content (`onx files get --record 1 --field 6989 --file 89 --output ./download.txt`), upload attachments (`onx files upload --record 140 --field 6989 --input ./doc.pdf`), or delete (`onx files delete --record 140 --field 6989 --file 1904`).
|
||||||
|
- **Lists**: Add or update list options (`onx lists save-item --list 906 --json '{"name": "Reviewed", "numericValue": 1.0}'`), or delete list values (`onx lists delete-item --list 906 --item 4118d53a-9121-4345-8682-07f23d606daa`).
|
||||||
|
- **Reports**: List available reports in an app (`onx reports list --app 195`) or fetch report data (`onx reports get --report 613 --format formatted`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deep-Dive References
|
||||||
|
|
||||||
|
For detailed request schemas, Onspring data types, and full command syntax, consult:
|
||||||
|
|
||||||
|
- [references/cli-reference.md](references/cli-reference.md): Complete list of commands, subcommands, and flags.
|
||||||
|
- [references/record-payloads.md](references/record-payloads.md): Exact schemas, filter operators (`eq`, `ne`, `lt`, `gt`, `contains`, `isnull`, `notnull`), date formatting in UTC, and `Raw` vs `Formatted` responses.
|
||||||
|
- [references/configuration.md](references/configuration.md): Precedence rules and config file examples.
|
||||||
|
- [Onspring API Docs](https://onspringapidocs.stevanfreeborn.com/): Official API v2 reference guide.
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
# Onx CLI Reference
|
||||||
|
|
||||||
|
This reference documents the exact top-level commands, subcommands, arguments, and options provided by the `onx` CLI, grounded in the CLI implementation and the [Onspring API v2 Specification](https://onspringapidocs.stevanfreeborn.com/).
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> **Source of Truth**: Always run `onx <command> --help` to inspect live command options and subcommands in real-time.
|
||||||
|
|
||||||
|
## Global Options
|
||||||
|
|
||||||
|
The following flags are available on the top-level command:
|
||||||
|
|
||||||
|
| Option | Short | Description |
|
||||||
|
| :---------------------- | :---- | :------------------------------------------------------------------------- |
|
||||||
|
| `--api-key <API_KEY>` | `-k` | The API key for the Onspring instance |
|
||||||
|
| `--base-url <BASE_URL>` | `-u` | The base URL for the Onspring API (defaults to `https://api.onspring.com`) |
|
||||||
|
| `--config <CONFIG>` | `-c` | Path to a configuration JSON file |
|
||||||
|
| `--pretty` | `-p` | Pretty-print JSON output |
|
||||||
|
| `--help` | `-h` | Print help |
|
||||||
|
| `--version` | `-V` | Print version |
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Global flags (such as `--pretty`, `--api-key`, `--base-url`, `--config`) must precede the subcommand in invocation:
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> onx --pretty ping
|
||||||
|
> onx --pretty records list --app 195
|
||||||
|
> ```
|
||||||
|
|
||||||
|
## `ping`
|
||||||
|
|
||||||
|
Check connectivity to the Onspring API.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx ping
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output on Success:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `apps`
|
||||||
|
|
||||||
|
Perform operations against the apps in the instance.
|
||||||
|
|
||||||
|
### `onx apps list`
|
||||||
|
|
||||||
|
Get a paged list of apps in the instance.
|
||||||
|
|
||||||
|
- `--page-number <PAGE_NUMBER>`, `-n`: The page number to retrieve (default: 1)
|
||||||
|
- `--page-size <PAGE_SIZE>`, `-s`: The size of the page to retrieve (default: 50, max: 1000)
|
||||||
|
|
||||||
|
**Output:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pageNumber": 1,
|
||||||
|
"pageSize": 50,
|
||||||
|
"totalPages": 1,
|
||||||
|
"totalRecords": 2,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"href": "https://api.onspring.com/apps/id/195",
|
||||||
|
"id": 195,
|
||||||
|
"name": "Projects"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `onx apps get`
|
||||||
|
|
||||||
|
Get information about a specific app by ID.
|
||||||
|
|
||||||
|
- `--app <APP_ID>`, `-a`: App ID to get (required, positive integer)
|
||||||
|
|
||||||
|
### `onx apps batch-get`
|
||||||
|
|
||||||
|
Get information for a batch of apps.
|
||||||
|
|
||||||
|
- `--apps <APP_IDS>`, `-a`: Comma-separated list of app IDs to get (required, e.g. `--apps 195,196`)
|
||||||
|
|
||||||
|
## `fields`
|
||||||
|
|
||||||
|
Perform operations against the fields in the instance.
|
||||||
|
|
||||||
|
### `onx fields list`
|
||||||
|
|
||||||
|
Get a paged list of fields in an app.
|
||||||
|
|
||||||
|
- `--app <APP_ID>`, `-a`: App ID whose fields will be retrieved (required)
|
||||||
|
- `--page-number <PAGE_NUMBER>`, `-n`: Page number
|
||||||
|
- `--page-size <PAGE_SIZE>`, `-s`: Page size
|
||||||
|
|
||||||
|
### `onx fields get`
|
||||||
|
|
||||||
|
Get detailed metadata about a field (type, multiplicity, list values, formula output type).
|
||||||
|
|
||||||
|
- `--field <FIELD_ID>`, `-f`: Field ID to get (required)
|
||||||
|
|
||||||
|
### `onx fields batch-get`
|
||||||
|
|
||||||
|
Get information for a batch of fields by IDs (maximum 100).
|
||||||
|
|
||||||
|
- `--fields <FIELD_IDS>`, `-f`: Comma-separated list of field IDs to get (required, e.g. `--fields 6983,6986`)
|
||||||
|
|
||||||
|
## `records`
|
||||||
|
|
||||||
|
Perform operations against records in the instance.
|
||||||
|
|
||||||
|
### `onx records list`
|
||||||
|
|
||||||
|
Get a paged list of records from an app.
|
||||||
|
|
||||||
|
- `--app <APP_ID>`, `-a`: App ID whose records will be retrieved (required)
|
||||||
|
- `--fields <FIELD_IDS>`, `-f`: Comma-separated list of field IDs to include in the response
|
||||||
|
- `--data-format <raw|formatted>`: Format of data in the response (default: `raw`)
|
||||||
|
- `--page-number <PAGE_NUMBER>`, `-n`: Page number
|
||||||
|
- `--page-size <PAGE_SIZE>`, `-s`: Page size
|
||||||
|
|
||||||
|
### `onx records get`
|
||||||
|
|
||||||
|
Get information for a single record.
|
||||||
|
|
||||||
|
- `--app <APP_ID>`, `-a`: App ID (required)
|
||||||
|
- `--record <RECORD_ID>`, `-r`: System Record ID (required)
|
||||||
|
- `--fields <FIELD_IDS>`, `-f`: Comma-separated list of field IDs to include
|
||||||
|
- `--format <raw|formatted>`, `-d`: Format of data in response (default: `raw`)
|
||||||
|
|
||||||
|
### `onx records save`
|
||||||
|
|
||||||
|
Add or update a record.
|
||||||
|
|
||||||
|
- Input body source (choose one):
|
||||||
|
- `--json <JSON>`, `-j`: Inline JSON request body
|
||||||
|
- `--file <FILE>`, `-f`: Path to a JSON request body file
|
||||||
|
- `--stdin`: Read JSON request body from stdin
|
||||||
|
|
||||||
|
**Request Format:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"appId": 195,
|
||||||
|
"recordId": null,
|
||||||
|
"fields": {
|
||||||
|
"6983": "New Task",
|
||||||
|
"6986": "4118d53a-9121-4345-8682-07f23d606daa"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `onx records query`
|
||||||
|
|
||||||
|
Query for records using a filter expression.
|
||||||
|
|
||||||
|
- Input body source (choose one):
|
||||||
|
- `--json <JSON>`, `-j`: Inline JSON request body
|
||||||
|
- `--file <FILE>`, `-f`: Path to a JSON request body file
|
||||||
|
- `--stdin`: Read JSON request body from stdin
|
||||||
|
- Pagination options:
|
||||||
|
- `--page-number <PAGE_NUMBER>`, `-n`: Page number
|
||||||
|
- `--page-size <PAGE_SIZE>`, `-s`: Page size
|
||||||
|
|
||||||
|
### `onx records delete`
|
||||||
|
|
||||||
|
Delete a single record.
|
||||||
|
|
||||||
|
- `--app <APP_ID>`, `-a`: App ID (required)
|
||||||
|
- `--record <RECORD_ID>`, `-r`: System Record ID (required)
|
||||||
|
|
||||||
|
### `onx records batch-get`
|
||||||
|
|
||||||
|
Get information for a batch of records (maximum 100).
|
||||||
|
|
||||||
|
- `--json <JSON>`, `-j` / `--file <FILE>`, `-f` / `--stdin`: JSON body `{ "appId": 195, "recordIds": [1, 2], "fieldIds": [...], "dataFormat": "Raw" }`
|
||||||
|
|
||||||
|
### `onx records batch-delete`
|
||||||
|
|
||||||
|
Delete a batch of records (maximum 100).
|
||||||
|
|
||||||
|
- `--json <JSON>`, `-j` / `--file <FILE>`, `-f` / `--stdin`: JSON body `{ "appId": 195, "recordIds": [138, 139] }`
|
||||||
|
|
||||||
|
## `files`
|
||||||
|
|
||||||
|
Perform operations against files held in `Attachment` and `Image` fields.
|
||||||
|
|
||||||
|
### `onx files info`
|
||||||
|
|
||||||
|
Get metadata info for a file.
|
||||||
|
|
||||||
|
- `--record <RECORD_ID>`, `-r`: Record ID where the file is held (required)
|
||||||
|
- `--field <FIELD_ID>`, `-f`: Field ID where the file is held (required)
|
||||||
|
- `--file <FILE_ID>`, `-l`: The ID of the file (required)
|
||||||
|
|
||||||
|
### `onx files get`
|
||||||
|
|
||||||
|
Download the content of a file.
|
||||||
|
|
||||||
|
- `--record <RECORD_ID>`, `-r`: Record ID (required)
|
||||||
|
- `--field <FIELD_ID>`, `-f`: Field ID (required)
|
||||||
|
- `--file <FILE_ID>`, `-l`: File ID (required)
|
||||||
|
- `--output <PATH>`, `-o`: Optional output path to write the downloaded file to disk (if omitted, writes binary to stdout)
|
||||||
|
|
||||||
|
### `onx files upload`
|
||||||
|
|
||||||
|
Upload a file to a field on a record.
|
||||||
|
|
||||||
|
- `--record <RECORD_ID>`, `-r`: Record ID (required)
|
||||||
|
- `--field <FIELD_ID>`, `-f`: Field ID (required)
|
||||||
|
- File source (choose one):
|
||||||
|
- `--input <PATH>`, `-i`: Path of local file to upload
|
||||||
|
- `--stdin`, `-s`: Read file data from stdin
|
||||||
|
- Optional metadata:
|
||||||
|
- `--name <NAME>`, `-n`: File name (required if reading from stdin; defaults to filename if `--input` is used)
|
||||||
|
- `--type <MIME>`, `-t`: Content MIME type (e.g. `application/pdf`; inferred if omitted)
|
||||||
|
- `--notes <NOTES>`: Optional notes to attach to the file
|
||||||
|
- `--modified-date <TIMESTAMP>`: Optional last modified date as RFC3339 timestamp (e.g. `2026-10-01T12:00:00Z`)
|
||||||
|
|
||||||
|
### `onx files delete`
|
||||||
|
|
||||||
|
Delete a file from an attachment/image field on a record.
|
||||||
|
|
||||||
|
- `--record <RECORD_ID>`, `-r`: Record ID (required)
|
||||||
|
- `--field <FIELD_ID>`, `-f`: Field ID (required)
|
||||||
|
- `--file <FILE_ID>`, `-l`: File ID (required)
|
||||||
|
|
||||||
|
## `lists`
|
||||||
|
|
||||||
|
Perform operations against custom lists and list values in the instance.
|
||||||
|
|
||||||
|
### `onx lists save-item`
|
||||||
|
|
||||||
|
Add or update an item for a specific list.
|
||||||
|
|
||||||
|
- `--list <LIST_ID>`, `-l`: List ID where the item should be saved (required)
|
||||||
|
- `--json <JSON>`, `-j` / `--file <FILE>`, `-f` / `--stdin`: JSON body:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": null,
|
||||||
|
"name": "In Review",
|
||||||
|
"numericValue": 1.5,
|
||||||
|
"color": "#ffaa00"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
_(Omit `id` or pass `null` to create; provide item GUID to update)_
|
||||||
|
|
||||||
|
### `onx lists delete-item`
|
||||||
|
|
||||||
|
Delete a list item from a list.
|
||||||
|
|
||||||
|
- `--list <LIST_ID>`, `-l`: List ID (required)
|
||||||
|
- `--item <ITEM_ID>`, `-i`: GUID of the item to delete (required, e.g. `4118d53a-9121-4345-8682-07f23d606daa`)
|
||||||
|
|
||||||
|
## `reports`
|
||||||
|
|
||||||
|
Perform operations against reports in an app or survey.
|
||||||
|
|
||||||
|
### `onx reports list`
|
||||||
|
|
||||||
|
List reports available in an app or survey.
|
||||||
|
|
||||||
|
- `--app <APP_ID>`, `-a`: App ID (required)
|
||||||
|
- `--page-number <PAGE_NUMBER>`, `-n`: Page number
|
||||||
|
- `--page-size <PAGE_SIZE>`, `-s`: Page size
|
||||||
|
|
||||||
|
### `onx reports get`
|
||||||
|
|
||||||
|
Get the tabular or chart data for a specific report.
|
||||||
|
|
||||||
|
- `--report <REPORT_ID>`, `-r`: Report ID (required)
|
||||||
|
- `--format <raw|formatted>`, `-f`: Format of report data (`raw` or `formatted`, default: `raw`)
|
||||||
|
- `--type <reportData|chartData>`, `-t`: Type of report data to retrieve (`reportData` or `chartData`, default: `reportData`)
|
||||||
|
- `--page-number <PAGE_NUMBER>`, `-n`: Page number
|
||||||
|
- `--page-size <PAGE_SIZE>`, `-s`: Page size
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# Configuration Reference for `onx`
|
||||||
|
|
||||||
|
`onx` can be configured using command-line arguments, a JSON configuration file, or environment variables.
|
||||||
|
|
||||||
|
## Precedence
|
||||||
|
|
||||||
|
Settings are resolved in the following priority order (highest to lowest):
|
||||||
|
|
||||||
|
1. **Command-line flags** (`--api-key`, `--base-url`, `--pretty`, `--config`)
|
||||||
|
2. **Configuration file** (`~/.config/onx/config.json` or path specified by `--config`)
|
||||||
|
3. **Environment variables** (`ONSPRING_API_KEY`, `ONSPRING_BASE_URL`)
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
Recommended for automated agent sessions, CI/CD, and containers:
|
||||||
|
|
||||||
|
| Variable | Description | Example |
|
||||||
|
| :------------------ | :-------------------------------------------------------------------------- | :------------------------- |
|
||||||
|
| `ONSPRING_API_KEY` | Your Onspring API Key | `abcd-1234-efgh-5678` |
|
||||||
|
| `ONSPRING_BASE_URL` | Base URL of your Onspring instance (defaults to `https://api.onspring.com`) | `https://api.onspring.com` |
|
||||||
|
|
||||||
|
### Setting in Unix (Bash / Zsh)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export ONSPRING_API_KEY="your-api-key"
|
||||||
|
export ONSPRING_BASE_URL="https://api.onspring.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setting in Windows (PowerShell)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:ONSPRING_API_KEY = "your-api-key"
|
||||||
|
$env:ONSPRING_BASE_URL = "https://api.onspring.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuration File
|
||||||
|
|
||||||
|
By default, `onx` checks for a configuration file at:
|
||||||
|
|
||||||
|
- **Unix / macOS**: `~/.config/onx/config.json`
|
||||||
|
- **Windows**: `%USERPROFILE%\.config\onx\config.json`
|
||||||
|
|
||||||
|
### Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"apiKey": "your-api-key",
|
||||||
|
"baseUrl": "https://api.onspring.com",
|
||||||
|
"pretty": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Config Location
|
||||||
|
|
||||||
|
You can supply a custom config file path to any command with `--config`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx apps list --config ./my-onspring-config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Command-Line Options
|
||||||
|
|
||||||
|
Every command supports passing credentials directly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx ping --api-key "your-api-key" --base-url "https://api.onspring.com" --pretty
|
||||||
|
```
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
# Onspring Record Payloads & API Data Types Reference
|
||||||
|
|
||||||
|
This reference describes the exact JSON structures, data formats, and filter syntax used with `onx records save`, `onx records query`, `onx records batch-get`, and `onx records batch-delete`, grounded in the [Onspring API v2 Specification](https://onspringapidocs.stevanfreeborn.com/).
|
||||||
|
|
||||||
|
## `records save` Payload
|
||||||
|
|
||||||
|
Used for creating or updating records:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx records save --json '<JSON_STRING>'
|
||||||
|
# or
|
||||||
|
onx records save --file ./record.json
|
||||||
|
# or
|
||||||
|
cat ./record.json | onx records save --stdin
|
||||||
|
```
|
||||||
|
|
||||||
|
### JSON Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"appId": 195,
|
||||||
|
"recordId": null,
|
||||||
|
"fields": {
|
||||||
|
"6983": "A New Test Task",
|
||||||
|
"6984": "<p>This is a test task.</p>",
|
||||||
|
"6985": "2026-10-01T06:00:00Z",
|
||||||
|
"6986": "4118d53a-9121-4345-8682-07f23d606daa",
|
||||||
|
"6987": [4],
|
||||||
|
"6988": 100.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Input Fields Specification
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| :--------- | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| `appId` | `number` | The ID of the app that contains or will contain the record (required). |
|
||||||
|
| `recordId` | `number \| null` | The ID of the record to update. If `null` or omitted, a new record is created. |
|
||||||
|
| `fields` | `object` | Key-value mapping where each key is the string representation of a **Field ID**, and the value is formatted per the field's data type. |
|
||||||
|
|
||||||
|
### Field Value Types When Saving
|
||||||
|
|
||||||
|
- **Text / Multi-line Text**: `string` (e.g., `"Title"` or HTML `"<p>Description</p>"`).
|
||||||
|
- **Number / Currency**: `number` (e.g., `42`, `100.50`).
|
||||||
|
- **Date / Time**: `string` in UTC ISO 8601 format (e.g., `"2026-10-01T12:00:00Z"`). Dates are always passed back and forth in UTC.
|
||||||
|
- **List (Single-Select)**: `string` containing the GUID of the chosen list value (e.g., `"4118d53a-9121-4345-8682-07f23d606daa"`).
|
||||||
|
- **List (Multi-Select)**: Array of GUID strings `string[]` (e.g., `["4118d53a-...", "1c1c5f7e-..."]`).
|
||||||
|
- **Reference (Single-Select)**: Array with one integer record ID `[140]` or integer `140`.
|
||||||
|
- **Reference (Multi-Select)**: Array of integer record IDs (e.g., `[140, 141]`).
|
||||||
|
- **Attachment / File**: Uploaded separately via `onx files upload`.
|
||||||
|
|
||||||
|
### Output on Success (`onx records save`)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 140,
|
||||||
|
"warnings": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `records query` Payload & Filter Syntax
|
||||||
|
|
||||||
|
Used for filtering and querying records across an app:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx records query --json '<JSON_STRING>'
|
||||||
|
```
|
||||||
|
|
||||||
|
### JSON Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"appId": 195,
|
||||||
|
"filter": "6983 eq 'Test Task' and 6987 gt 50",
|
||||||
|
"fieldIds": [6983, 6986, 6987],
|
||||||
|
"dataFormat": "Formatted"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Request Fields
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| :----------- | :--------- | :------------------------------------------------------------------------------------------- |
|
||||||
|
| `appId` | `number` | App ID containing the records (required). |
|
||||||
|
| `filter` | `string` | Filter expression referencing Field IDs (required). |
|
||||||
|
| `fieldIds` | `number[]` | Optional array of field IDs to include in the response. If omitted, all fields are returned. |
|
||||||
|
| `dataFormat` | `string` | Optional: `"Raw"` or `"Formatted"` (defaults to `"Raw"`). |
|
||||||
|
|
||||||
|
### Query Filter Operators & Rules
|
||||||
|
|
||||||
|
Filter expressions evaluate field values using Field IDs as identifiers.
|
||||||
|
|
||||||
|
| Operator | Description | Applicable Field Types |
|
||||||
|
| :--------- | :----------------------------------- | :----------------------------------------------------------- |
|
||||||
|
| `eq` | Equals | Text, Number, Date, Auto-Number, Formulas (text/number/date) |
|
||||||
|
| `ne` | Not equals | Text, Number, Date, Auto-Number, Formulas (text/number/date) |
|
||||||
|
| `lt` | Less than | Number, Date, Auto-Number, Formulas (number/date) |
|
||||||
|
| `gt` | Greater than | Number, Date, Auto-Number, Formulas (number/date) |
|
||||||
|
| `contains` | List contains item (by name or GUID) | List fields, List formulas |
|
||||||
|
| `isnull` | Field has no value | Text, Number, Date, Auto-Number, Formulas |
|
||||||
|
| `notnull` | Field has a value | Text, Number, Date, Auto-Number, Formulas |
|
||||||
|
|
||||||
|
#### Literal Delimiters
|
||||||
|
|
||||||
|
- **String values**: Must be enclosed in single quotes `'` (e.g., `6983 eq 'Active'`).
|
||||||
|
- **Date values**: Must be enclosed in single quotes `'` preceded by `datetime` (e.g., `6985 gt datetime'2026-01-01T00:00:00Z'`).
|
||||||
|
- **Logical combination**: Combine with `and`, `or`, and negate with `not`. Group expressions using parentheses `( ... )`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
(6983 eq 'Active' or 6983 eq 'Pending') and 6987 gt 100 and 6985 notnull
|
||||||
|
```
|
||||||
|
|
||||||
|
## `records batch-get` Payload
|
||||||
|
|
||||||
|
Used to fetch specific records in bulk (maximum 100 records per request):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx records batch-get --json '{
|
||||||
|
"appId": 195,
|
||||||
|
"recordIds": [1, 2, 3],
|
||||||
|
"fieldIds": [6983, 6986],
|
||||||
|
"dataFormat": "Formatted"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"count": 3,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"appId": 195,
|
||||||
|
"recordId": 1,
|
||||||
|
"fieldData": [
|
||||||
|
{
|
||||||
|
"type": "String",
|
||||||
|
"fieldId": 6983,
|
||||||
|
"value": "Task 1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `records batch-delete` Payload
|
||||||
|
|
||||||
|
Used to delete records in bulk (maximum 100 records per request):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
onx records batch-delete --json '{
|
||||||
|
"appId": 195,
|
||||||
|
"recordIds": [138, 139]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Output on success:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Understanding `dataFormat`: `Raw` vs `Formatted`
|
||||||
|
|
||||||
|
When retrieving records (`list`, `get`, `batch-get`, `query`) or reports, `dataFormat` controls the output format:
|
||||||
|
|
||||||
|
| Field Type | `Raw` Format | `Formatted` Format |
|
||||||
|
| :-------------------- | :------------------------------------------------------------------------ | :--------------------------------------------------------------- |
|
||||||
|
| **AutoNumber** | `number` (e.g. `1`) | Formatted `string` (e.g. `"APP-001"`) |
|
||||||
|
| **Date/Time** | ISO 8601 UTC string (e.g. `"2026-10-01T06:00:00Z"`) | Display string with user formatting (e.g. `"10/1/2026 6:00 AM"`) |
|
||||||
|
| **List** | Value GUID string(s) | Value name string(s) (e.g. `"In Progress"`) |
|
||||||
|
| **Number / Currency** | `number` (e.g. `100.5`) | Display string with symbol (e.g. `"$100.50"`) |
|
||||||
|
| **Text** | HTML string (e.g. `"<p>Sample</p>"`) | Plain string with HTML stripped (e.g. `"Sample"`) |
|
||||||
|
| **TimeSpan** | Object `{ "quantity": 10, "increment": "Minutes", "recurrence": "None" }` | Display string (e.g. `"10 Minutes"`) |
|
||||||
|
|
||||||
|
## Record ID vs Display Field
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> The `recordId` used in `onx` CLI commands (`--record <ID>`) and API routes is the integer **system record ID** (e.g., `140`).
|
||||||
|
> Do not confuse this with the text value formatted by an **AutoNumber** or Display field in the Onspring GUI (e.g., `"INC-1002"`).
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Alias("v")]
|
||||||
|
[string]$Version,
|
||||||
|
|
||||||
|
[Alias("t")]
|
||||||
|
[string]$InstallDir = "$HOME\.onx\bin"
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
$Existing = Get-Command "onx" -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($Existing) {
|
||||||
|
Write-Host "onx is already installed at: $($Existing.Source)" -ForegroundColor Green
|
||||||
|
& onx --version
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "onx CLI not found in PATH. Installing via official installer..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
$InstallerUrl = "https://raw.githubusercontent.com/StevanFreeborn/onx/main/scripts/install.ps1"
|
||||||
|
|
||||||
|
$InstallScript = [scriptblock]::Create((Invoke-RestMethod -Uri $InstallerUrl))
|
||||||
|
|
||||||
|
$Params = @{
|
||||||
|
InstallDir = $InstallDir
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Version) {
|
||||||
|
$Params["Version"] = $Version
|
||||||
|
}
|
||||||
|
|
||||||
|
& $InstallScript @Params
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if command -v onx >/dev/null 2>&1; then
|
||||||
|
echo "onx is already installed at: $(command -v onx)"
|
||||||
|
onx --version
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "onx CLI not found in PATH. Installing via official installer..."
|
||||||
|
|
||||||
|
INSTALLER_URL="https://raw.githubusercontent.com/StevanFreeborn/onx/main/scripts/install.sh"
|
||||||
|
|
||||||
|
if command -v curl >/dev/null 2>&1; then
|
||||||
|
curl -fsSL "${INSTALLER_URL}" | bash -s -- "$@"
|
||||||
|
elif command -v wget >/dev/null 2>&1; then
|
||||||
|
wget -qO- "${INSTALLER_URL}" | bash -s -- "$@"
|
||||||
|
else
|
||||||
|
echo "Error: Neither curl nor wget was found." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[string]$OnxPath
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
function Get-ClapCommands {
|
||||||
|
param(
|
||||||
|
[string]$HelpText
|
||||||
|
)
|
||||||
|
|
||||||
|
$Commands = @()
|
||||||
|
$InCommandsSection = $false
|
||||||
|
|
||||||
|
foreach ($Line in ($HelpText -split "`r?`n")) {
|
||||||
|
if ($Line -match '^Commands:') {
|
||||||
|
$InCommandsSection = $true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($InCommandsSection) {
|
||||||
|
if ($Line -match '^[A-Z][a-zA-Z0-9 ]*:' -or $Line.Trim() -eq "") {
|
||||||
|
|
||||||
|
if ($Line.Trim() -ne "") {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Line -match '^\s{2}([a-z0-9][a-z0-9\-_]*)\s+(.+)$') {
|
||||||
|
$CmdName = $Matches[1].Trim()
|
||||||
|
|
||||||
|
if ($CmdName -ne "help") {
|
||||||
|
$Commands += $CmdName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Commands
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $OnxPath) {
|
||||||
|
$Cmd = Get-Command "onx" -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($Cmd) {
|
||||||
|
$OnxPath = $Cmd.Source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $OnxPath -or -not (Test-Path $OnxPath)) {
|
||||||
|
Write-Error "Could not locate onx executable. Ensure 'onx' is in PATH or provide -OnxPath <path_to_onx>."
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Deriving commands dynamically from onx binary at: $OnxPath" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
$RootHelp = & $OnxPath --help | Out-String
|
||||||
|
$TopCommands = Get-ClapCommands -HelpText $RootHelp
|
||||||
|
|
||||||
|
if ($TopCommands.Count -eq 0) {
|
||||||
|
Write-Error "Failed to dynamically discover any commands from '$OnxPath --help'."
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Discovered top-level commands: $($TopCommands -join ', ')" -ForegroundColor Gray
|
||||||
|
|
||||||
|
$CommandHierarchy = @{}
|
||||||
|
|
||||||
|
foreach ($cmd in $TopCommands) {
|
||||||
|
$CmdHelp = & $OnxPath $cmd --help | Out-String
|
||||||
|
$SubCommands = Get-ClapCommands -HelpText $CmdHelp
|
||||||
|
|
||||||
|
$CommandHierarchy[$cmd] = $SubCommands
|
||||||
|
|
||||||
|
if ($SubCommands.Count -gt 0) {
|
||||||
|
Write-Host " -> ${cmd}: $($SubCommands -join ', ')" -ForegroundColor Gray
|
||||||
|
} else {
|
||||||
|
Write-Host " -> ${cmd} (standalone command)" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$DocFile = Join-Path $PSScriptRoot "..\references\cli-reference.md"
|
||||||
|
|
||||||
|
if (-not (Test-Path $DocFile)) {
|
||||||
|
Write-Error "cli-reference.md not found at $DocFile"
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$DocText = Get-Content $DocFile -Raw
|
||||||
|
$HasErrors = $false
|
||||||
|
|
||||||
|
foreach ($cmd in $CommandHierarchy.Keys) {
|
||||||
|
$SubCommands = $CommandHierarchy[$cmd]
|
||||||
|
|
||||||
|
if ($SubCommands.Count -eq 0) {
|
||||||
|
$Pattern = "onx $cmd"
|
||||||
|
|
||||||
|
if ($DocText -notmatch [regex]::Escape($Pattern)) {
|
||||||
|
Write-Warning "Documentation drift! Command '$Pattern' is not documented in $DocFile"
|
||||||
|
|
||||||
|
$HasErrors = $true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($sub in $SubCommands) {
|
||||||
|
$Pattern = "onx $cmd $sub"
|
||||||
|
|
||||||
|
if ($DocText -notmatch [regex]::Escape($Pattern)) {
|
||||||
|
Write-Warning "Documentation drift! Subcommand '$Pattern' is not documented in $DocFile"
|
||||||
|
|
||||||
|
$HasErrors = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($HasErrors) {
|
||||||
|
Write-Error "CLI docs verification failed due to drift."
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`nAll dynamically derived commands and subcommands from the onx binary are documented in cli-reference.md!" -ForegroundColor Green
|
||||||
Reference in new issue
Block a user