@uluops/cli 0.10.1 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/README.md +18 -69
- package/dist/cli.js +17 -17
- package/dist/cli.js.map +1 -1
- package/dist/commands/analytics.d.ts +1 -1
- package/dist/commands/analytics.d.ts.map +1 -1
- package/dist/commands/analytics.js +135 -32
- package/dist/commands/analytics.js.map +1 -1
- package/dist/commands/auth.d.ts +1 -1
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +86 -21
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/completion.d.ts +1 -1
- package/dist/commands/completion.d.ts.map +1 -1
- package/dist/commands/completion.js +15 -7
- package/dist/commands/completion.js.map +1 -1
- package/dist/commands/definitions.d.ts +1 -1
- package/dist/commands/definitions.d.ts.map +1 -1
- package/dist/commands/definitions.js +68 -16
- package/dist/commands/definitions.js.map +1 -1
- package/dist/commands/deps.d.ts +1 -1
- package/dist/commands/deps.d.ts.map +1 -1
- package/dist/commands/deps.js +14 -4
- package/dist/commands/deps.js.map +1 -1
- package/dist/commands/exec.d.ts +1 -1
- package/dist/commands/exec.d.ts.map +1 -1
- package/dist/commands/exec.js +44 -19
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/executions.d.ts +1 -1
- package/dist/commands/executions.d.ts.map +1 -1
- package/dist/commands/executions.js +11 -4
- package/dist/commands/executions.js.map +1 -1
- package/dist/commands/forks.d.ts +1 -1
- package/dist/commands/forks.d.ts.map +1 -1
- package/dist/commands/forks.js +20 -10
- package/dist/commands/forks.js.map +1 -1
- package/dist/commands/issues.d.ts +1 -1
- package/dist/commands/issues.d.ts.map +1 -1
- package/dist/commands/issues.js +56 -15
- package/dist/commands/issues.js.map +1 -1
- package/dist/commands/languages.d.ts +6 -0
- package/dist/commands/languages.d.ts.map +1 -0
- package/dist/commands/languages.js +72 -0
- package/dist/commands/languages.js.map +1 -0
- package/dist/commands/models.d.ts +1 -1
- package/dist/commands/models.d.ts.map +1 -1
- package/dist/commands/models.js +6 -26
- package/dist/commands/models.js.map +1 -1
- package/dist/commands/projects.d.ts +1 -1
- package/dist/commands/projects.d.ts.map +1 -1
- package/dist/commands/projects.js +62 -14
- package/dist/commands/projects.js.map +1 -1
- package/dist/commands/runs.d.ts +1 -1
- package/dist/commands/runs.d.ts.map +1 -1
- package/dist/commands/runs.js +52 -20
- package/dist/commands/runs.js.map +1 -1
- package/dist/commands/taxonomy.d.ts +1 -1
- package/dist/commands/taxonomy.d.ts.map +1 -1
- package/dist/commands/taxonomy.js +5 -2
- package/dist/commands/taxonomy.js.map +1 -1
- package/dist/commands/translation.d.ts +1 -1
- package/dist/commands/translation.d.ts.map +1 -1
- package/dist/commands/translation.js +16 -5
- package/dist/commands/translation.js.map +1 -1
- package/dist/commands/versions.d.ts +1 -1
- package/dist/commands/versions.d.ts.map +1 -1
- package/dist/commands/versions.js +10 -4
- package/dist/commands/versions.js.map +1 -1
- package/dist/context.d.ts +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +30 -15
- package/dist/context.js.map +1 -1
- package/dist/formatters/core.d.ts +1 -1
- package/dist/formatters/core.d.ts.map +1 -1
- package/dist/formatters/core.js +20 -5
- package/dist/formatters/core.js.map +1 -1
- package/dist/formatters/ops.d.ts +1 -1
- package/dist/formatters/ops.d.ts.map +1 -1
- package/dist/formatters/ops.js +38 -8
- package/dist/formatters/ops.js.map +1 -1
- package/dist/formatters/registry.d.ts +1 -1
- package/dist/formatters/registry.d.ts.map +1 -1
- package/dist/formatters/registry.js +32 -18
- package/dist/formatters/registry.js.map +1 -1
- package/dist/formatters/table.d.ts.map +1 -1
- package/dist/formatters/table.js.map +1 -1
- package/dist/utils.d.ts +3 -5
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +11 -27
- package/dist/utils.js.map +1 -1
- package/package.json +14 -14
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,56 @@ All notable changes to `@uluops/cli` will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## [0.12.1] - 2026-06-01
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Install no longer fails on `ETARGET No matching version found for @uluops/ops-sdk@3.0.0`.** `0.12.0` transitively required `@uluops/core@0.18.0`, which had been published with broken pins to `@uluops/ops-sdk@3.0.0` and `@uluops/registry-sdk@0.30.0` — both subsequently unpublished from the registry. This release pulls in `@uluops/core@0.18.1` which repaired those references, unblocking fresh installs.
|
|
12
|
+
|
|
13
|
+
### Security
|
|
14
|
+
|
|
15
|
+
- **Bump full UluOps dep chain to today's hardened versions.** `@uluops/sdk-core` 0.11.0 → 0.11.1, `@uluops/ops-sdk` 3.0.3 → 3.0.5, `@uluops/registry-sdk` 0.30.1 → 0.30.2, `@uluops/core` 0.18.0 → 0.18.1. All packages now resolve to a single `@uluops/sdk-core@0.11.1` instance in `node_modules` (no duplicate nested copies), so the sdk-core security hardening — `redirect: 'error'` on all fetch sites, `stripControlChars` in error messages, widened `SENSITIVE_KEYS`, `REDACTED_DETAIL_KEYS` `column` fix, and `sanitizeString` URL-userinfo + bare JWT coverage — applies uniformly across every SDK code path the CLI invokes. See `@uluops/sdk-core` CHANGELOG 0.11.1.
|
|
16
|
+
|
|
17
|
+
### Supply chain
|
|
18
|
+
|
|
19
|
+
- **Pin remaining caret deps to exact versions.** `commander`, `ora`, `@biomejs/biome`, `@types/node`, `@vitest/coverage-v8`, `tsx`, `typescript`, `vitest` stripped of caret ranges per the UluOps exact-pinning policy adopted 2026-06-01 in response to the RedHat-class supply-chain attack pattern.
|
|
20
|
+
|
|
21
|
+
## [0.12.0] - 2026-06-01
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Bumps `@uluops/sdk-core` to `0.11.0`, `@uluops/ops-sdk` to `3.0.0`, `@uluops/registry-sdk`
|
|
26
|
+
to `0.30.0`, `@uluops/core` to `0.18.0` (all exact pins). Aligns with the sdk-core
|
|
27
|
+
schema-removal cascade.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- `ulu definitions publish` now correctly destructures the `PublishResult` (registry-sdk
|
|
32
|
+
0.29.0 changed the return type from `Definition` to `{ definition, warnings }`).
|
|
33
|
+
Surfaces non-fatal publish warnings instead of crashing with `Cannot read properties of
|
|
34
|
+
undefined`.
|
|
35
|
+
- `ulu forks lineage` was reading `result.chain` and `result.current` (untyped) through
|
|
36
|
+
the typed `ForkLineage` interface, which only declares `{ isFork, fork, source }`.
|
|
37
|
+
Refactored to use the `asFlexibleResponse` cast it already had imported, with explicit
|
|
38
|
+
inner types for the legacy `chain`/`current` shape.
|
|
39
|
+
|
|
40
|
+
## [0.11.0] - 2026-05-27
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- **`ulu languages` command** (alias: `ulu lang`) — browse definition language schemas. `ulu lang` lists all 4 languages with current versions. `ulu lang adl` shows metadata for a specific language. `ulu lang adl --json` returns full schema content. `ulu lang adl -o schema.json` writes the JSON Schema to a file.
|
|
45
|
+
|
|
46
|
+
## [0.10.2] - 2026-05-27
|
|
47
|
+
|
|
48
|
+
### Removed
|
|
49
|
+
|
|
50
|
+
- **`ulu config` command** — profile-based configuration (`config list`, `config set`, `config get`, `config unset`, `config profiles`, `config use`, `config path`) has been removed. The feature was structurally complete but mostly hollow — only `defaultProject` was consumed at runtime, while `opsBaseUrl`, `registryBaseUrl`, `json`, `quiet`, and `debug` stored in profiles had no effect on CLI behavior. Use environment variables and CLI flags instead.
|
|
51
|
+
- **`defaultProject` profile fallback** — `resolveProject` no longer reads `~/.uluops/profiles.json`. Pass `--project <name>` explicitly.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- **Removed stale `models sync` test** — test referenced a subcommand that was removed from the implementation but not the test suite.
|
|
56
|
+
|
|
7
57
|
## [0.10.1] - 2026-05-27
|
|
8
58
|
|
|
9
59
|
### Fixed
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
Unified CLI for UluOps — validation tracking and registry management from a single command. Wraps both the [ops-sdk](https://www.npmjs.com/package/@uluops/ops-sdk) and [registry-sdk](https://www.npmjs.com/package/@uluops/registry-sdk) into an ergonomic terminal interface.
|
|
13
13
|
|
|
14
|
-
**Current version: 0.
|
|
14
|
+
**Current version: 0.11.0** | [Changelog](./CHANGELOG.md)
|
|
15
15
|
|
|
16
16
|
## Quick Start
|
|
17
17
|
|
|
@@ -41,11 +41,10 @@ ulu exec agent code-validator -t ./src --model sonnet --project my-project
|
|
|
41
41
|
- [Features](#features)
|
|
42
42
|
- [Installation](#installation)
|
|
43
43
|
- [Authentication](#authentication)
|
|
44
|
-
- [Configuration](#configuration)
|
|
44
|
+
- [Configuration](#configuration) — Config files & environment
|
|
45
45
|
- [Global Options](#global-options)
|
|
46
46
|
- [Command Reference](#command-reference)
|
|
47
47
|
- [Auth](#auth) — Authentication & credential management
|
|
48
|
-
- [Config](#config) — CLI configuration & profiles
|
|
49
48
|
- [Projects](#projects) (`ulu p`) — Project lifecycle management
|
|
50
49
|
- [Runs](#runs) (`ulu r`) — Validation run management
|
|
51
50
|
- [Issues](#issues) (`ulu i`) — Issue tracking & management
|
|
@@ -56,6 +55,7 @@ ulu exec agent code-validator -t ./src --model sonnet --project my-project
|
|
|
56
55
|
- [Versions](#versions) — Definition version history
|
|
57
56
|
- [Deps](#deps) — Dependency graphs
|
|
58
57
|
- [Forks](#forks) — Definition forking
|
|
58
|
+
- [Languages](#languages) (`ulu lang`) — Definition language schemas
|
|
59
59
|
- [Models](#models) — AI model catalog
|
|
60
60
|
- [Exec](#exec) (`ulu x`) — Execute agents, commands, workflows, and pipelines
|
|
61
61
|
- [Executions](#executions) — Execution tracking
|
|
@@ -72,7 +72,6 @@ ulu exec agent code-validator -t ./src --model sonnet --project my-project
|
|
|
72
72
|
|
|
73
73
|
- **Unified interface**: Single `ulu` command covers both the validation tracker (ops) and definition registry APIs
|
|
74
74
|
- **Command aliases**: `ulu p` (projects), `ulu r` (runs), `ulu i` (issues), `ulu a` (analytics), `ulu x` (exec), `ulu def` (definitions)
|
|
75
|
-
- **Profile-based configuration**: Multiple environments via named profiles with independent credentials
|
|
76
75
|
- **Flexible authentication**: API key, session token, or email/password — same credential chain as the SDKs
|
|
77
76
|
- **Machine-friendly output**: `--json` flag on every command for scripting and CI/CD integration
|
|
78
77
|
- **Shell completion**: Tab completion for bash, zsh, and fish
|
|
@@ -143,51 +142,11 @@ The CLI resolves credentials in this order:
|
|
|
143
142
|
|
|
144
143
|
## Configuration
|
|
145
144
|
|
|
146
|
-
### Config Files
|
|
147
|
-
|
|
148
145
|
| File | Purpose |
|
|
149
146
|
|------|---------|
|
|
150
|
-
| `~/.uluops/profiles.json` | Profile settings (base URLs, default project, output preferences) |
|
|
151
147
|
| `~/.uluops/credentials.json` | Credentials per profile (API keys, session tokens) |
|
|
152
148
|
| `./.env` | Project-level environment overrides |
|
|
153
149
|
|
|
154
|
-
### Profiles
|
|
155
|
-
|
|
156
|
-
Profiles let you maintain separate configurations for different environments:
|
|
157
|
-
|
|
158
|
-
```bash
|
|
159
|
-
# Set config values on the default profile
|
|
160
|
-
ulu config set opsBaseUrl https://api.uluops.com/api/v1
|
|
161
|
-
ulu config set defaultProject my-project
|
|
162
|
-
|
|
163
|
-
# Create and switch to a new profile
|
|
164
|
-
ulu config use staging
|
|
165
|
-
ulu config set opsBaseUrl https://staging-api.uluops.com/api/v1
|
|
166
|
-
|
|
167
|
-
# Switch back
|
|
168
|
-
ulu config use default
|
|
169
|
-
|
|
170
|
-
# Use a profile for a single command
|
|
171
|
-
ulu projects list --profile staging
|
|
172
|
-
|
|
173
|
-
# View current config
|
|
174
|
-
ulu config list
|
|
175
|
-
|
|
176
|
-
# List all profiles
|
|
177
|
-
ulu config profiles
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### Config Keys
|
|
181
|
-
|
|
182
|
-
| Key | Description | Default |
|
|
183
|
-
|-----|-------------|---------|
|
|
184
|
-
| `opsBaseUrl` | Validation tracker API URL | `http://localhost:3100/api/v1` |
|
|
185
|
-
| `registryBaseUrl` | Registry API URL | `http://localhost:3001/api/v1` |
|
|
186
|
-
| `defaultProject` | Default project for commands that accept `<project>` | - |
|
|
187
|
-
| `json` | Always output JSON | `false` |
|
|
188
|
-
| `quiet` | Suppress spinners | `false` |
|
|
189
|
-
| `debug` | Enable debug output | `false` |
|
|
190
|
-
|
|
191
150
|
## Global Options
|
|
192
151
|
|
|
193
152
|
Every command accepts these flags:
|
|
@@ -243,22 +202,6 @@ ulu auth whoami
|
|
|
243
202
|
|
|
244
203
|
---
|
|
245
204
|
|
|
246
|
-
### Config
|
|
247
|
-
|
|
248
|
-
CLI configuration and profile management.
|
|
249
|
-
|
|
250
|
-
```bash
|
|
251
|
-
ulu config list # Show resolved config for active profile
|
|
252
|
-
ulu config get <key> # Get a config value
|
|
253
|
-
ulu config set <key> <value> # Set a config value
|
|
254
|
-
ulu config unset <key> # Remove a config value
|
|
255
|
-
ulu config profiles # List all profiles
|
|
256
|
-
ulu config use <profile> # Switch active profile
|
|
257
|
-
ulu config path # Show config file locations
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
205
|
### Projects
|
|
263
206
|
|
|
264
207
|
Project lifecycle management. Alias: `p`.
|
|
@@ -578,6 +521,19 @@ ulu forks lineage <type> <name> <version> # Show fork ancestry chain
|
|
|
578
521
|
|
|
579
522
|
---
|
|
580
523
|
|
|
524
|
+
### Languages
|
|
525
|
+
|
|
526
|
+
Definition language schemas. Alias: `lang`.
|
|
527
|
+
|
|
528
|
+
```bash
|
|
529
|
+
ulu lang # List all languages with versions
|
|
530
|
+
ulu lang adl # Get ADL metadata
|
|
531
|
+
ulu lang adl --json # Full output with JSON Schema content
|
|
532
|
+
ulu lang adl -o adl-schema.json # Write JSON Schema to file
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
581
537
|
### Models
|
|
582
538
|
|
|
583
539
|
AI model catalog.
|
|
@@ -588,7 +544,6 @@ ulu models get <provider> <id> # Get model details
|
|
|
588
544
|
ulu models providers # List providers
|
|
589
545
|
ulu models aliases # List model aliases
|
|
590
546
|
ulu models resolve <alias> # Resolve alias to concrete model
|
|
591
|
-
ulu models sync # Sync from providers (admin only)
|
|
592
547
|
```
|
|
593
548
|
|
|
594
549
|
---
|
|
@@ -786,16 +741,13 @@ All errors include the HTTP status code and server error code when available. Us
|
|
|
786
741
|
# Verify your credentials are set
|
|
787
742
|
echo $ULUOPS_API_KEY
|
|
788
743
|
ulu auth whoami
|
|
789
|
-
|
|
790
|
-
# Check which profile is active
|
|
791
|
-
ulu config list
|
|
792
744
|
```
|
|
793
745
|
|
|
794
746
|
### "Connection refused" errors
|
|
795
747
|
|
|
796
748
|
```bash
|
|
797
749
|
# Check the configured base URL
|
|
798
|
-
|
|
750
|
+
echo $ULUOPS_BASE_URL
|
|
799
751
|
|
|
800
752
|
# Test server connectivity
|
|
801
753
|
curl http://localhost:3100/api/v1/health
|
|
@@ -804,11 +756,8 @@ curl http://localhost:3100/api/v1/health
|
|
|
804
756
|
### Commands targeting the wrong environment
|
|
805
757
|
|
|
806
758
|
```bash
|
|
807
|
-
# Check active profile
|
|
808
|
-
ulu config profiles
|
|
809
|
-
|
|
810
759
|
# Override for a single command
|
|
811
|
-
ulu projects list --
|
|
760
|
+
ulu projects list --base-url https://api.uluops.com/api/v1
|
|
812
761
|
```
|
|
813
762
|
|
|
814
763
|
### Shell completion not working
|
package/dist/cli.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command } from 'commander';
|
|
3
2
|
import { readFileSync } from 'node:fs';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
3
|
import { dirname, join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
// Load .env files early so all SDK contexts see them
|
|
6
|
+
import { loadEnvFiles } from '@uluops/ops-sdk';
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import { registerAnalyticsCommands } from './commands/analytics.js';
|
|
6
9
|
// Ops commands
|
|
7
10
|
import { registerAuthCommands } from './commands/auth.js';
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
import { registerIssueCommands } from './commands/issues.js';
|
|
11
|
-
import { registerAnalyticsCommands } from './commands/analytics.js';
|
|
12
|
-
import { registerTaxonomyCommands } from './commands/taxonomy.js';
|
|
11
|
+
// Infrastructure commands
|
|
12
|
+
import { registerCompletionCommands } from './commands/completion.js';
|
|
13
13
|
// Registry commands
|
|
14
14
|
import { registerDefinitionCommands } from './commands/definitions.js';
|
|
15
|
-
import { registerVersionCommands } from './commands/versions.js';
|
|
16
15
|
import { registerDepsCommands } from './commands/deps.js';
|
|
16
|
+
// Core SDK commands
|
|
17
|
+
import { registerExecCommands } from './commands/exec.js';
|
|
18
|
+
import { registerExecutionCommands } from './commands/executions.js';
|
|
17
19
|
import { registerForkCommands } from './commands/forks.js';
|
|
20
|
+
import { registerIssueCommands } from './commands/issues.js';
|
|
21
|
+
import { registerLanguageCommands } from './commands/languages.js';
|
|
18
22
|
import { registerModelCommands } from './commands/models.js';
|
|
19
|
-
import {
|
|
23
|
+
import { registerProjectCommands } from './commands/projects.js';
|
|
24
|
+
import { registerRunCommands } from './commands/runs.js';
|
|
25
|
+
import { registerTaxonomyCommands } from './commands/taxonomy.js';
|
|
20
26
|
import { registerTranslationCommands } from './commands/translation.js';
|
|
21
|
-
|
|
22
|
-
import { registerExecCommands } from './commands/exec.js';
|
|
23
|
-
// Infrastructure commands
|
|
24
|
-
import { registerConfigCommands } from './commands/config.js';
|
|
25
|
-
import { registerCompletionCommands } from './commands/completion.js';
|
|
26
|
-
// Load .env files early so all SDK contexts see them
|
|
27
|
-
import { loadEnvFiles } from '@uluops/ops-sdk';
|
|
27
|
+
import { registerVersionCommands } from './commands/versions.js';
|
|
28
28
|
loadEnvFiles();
|
|
29
29
|
// Handle EPIPE gracefully (e.g., piping to head, or broken pipe)
|
|
30
30
|
process.stdout.on('error', (err) => {
|
|
@@ -97,10 +97,10 @@ registerForkCommands(program);
|
|
|
97
97
|
registerModelCommands(program);
|
|
98
98
|
registerExecutionCommands(program);
|
|
99
99
|
registerTranslationCommands(program);
|
|
100
|
+
registerLanguageCommands(program);
|
|
100
101
|
// Core SDK commands
|
|
101
102
|
registerExecCommands(program);
|
|
102
103
|
// Infrastructure commands
|
|
103
|
-
registerConfigCommands(program);
|
|
104
104
|
registerCompletionCommands(program);
|
|
105
105
|
// Default action when no command is provided
|
|
106
106
|
program.action(() => {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/commands/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/commands/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAczC;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkpBhE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createOpsContext, handleOpsError } from '../context.js';
|
|
2
|
-
import { withSpinner, getFlexibleProperty, parseIntOption, parseFloatOption } from '../utils.js';
|
|
1
|
+
import { createOpsContext, handleOpsError, } from '../context.js';
|
|
3
2
|
import { formatTable } from '../formatters/table.js';
|
|
3
|
+
import { getFlexibleProperty, parseFloatOption, parseIntOption, withSpinner, } from '../utils.js';
|
|
4
4
|
/**
|
|
5
5
|
* Register analytics commands
|
|
6
6
|
*/
|
|
@@ -29,7 +29,10 @@ Examples:
|
|
|
29
29
|
const globalOpts = cmd.optsWithGlobals();
|
|
30
30
|
const ctx = createOpsContext(globalOpts);
|
|
31
31
|
try {
|
|
32
|
-
const data = await withSpinner(ctx, {
|
|
32
|
+
const data = await withSpinner(ctx, {
|
|
33
|
+
start: 'Fetching agent performance...',
|
|
34
|
+
failure: 'Failed to fetch agent performance',
|
|
35
|
+
}, () => ctx.client.analytics.getAgentPerformance({
|
|
33
36
|
project: options.project,
|
|
34
37
|
days: parseIntOption(options.days, '--days'),
|
|
35
38
|
limit: parseIntOption(options.limit, '--limit'),
|
|
@@ -43,9 +46,24 @@ Examples:
|
|
|
43
46
|
else {
|
|
44
47
|
const columns = [
|
|
45
48
|
{ header: 'AGENT', accessor: 'name', width: 25 },
|
|
46
|
-
{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
{
|
|
50
|
+
header: 'RUNS',
|
|
51
|
+
accessor: (v) => String(v.totalRuns),
|
|
52
|
+
width: 8,
|
|
53
|
+
align: 'right',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
header: 'AVG SCORE',
|
|
57
|
+
accessor: (v) => v.averageScore?.toFixed(1) ?? '-',
|
|
58
|
+
width: 10,
|
|
59
|
+
align: 'right',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
header: 'PASS RATE',
|
|
63
|
+
accessor: (v) => `${v.passRate.toFixed(0)}%`,
|
|
64
|
+
width: 10,
|
|
65
|
+
align: 'right',
|
|
66
|
+
},
|
|
49
67
|
];
|
|
50
68
|
console.log(formatTable(data, columns));
|
|
51
69
|
}
|
|
@@ -65,7 +83,10 @@ Examples:
|
|
|
65
83
|
const globalOpts = cmd.optsWithGlobals();
|
|
66
84
|
const ctx = createOpsContext(globalOpts);
|
|
67
85
|
try {
|
|
68
|
-
const data = await withSpinner(ctx, {
|
|
86
|
+
const data = await withSpinner(ctx, {
|
|
87
|
+
start: 'Fetching reliability stats...',
|
|
88
|
+
failure: 'Failed to fetch reliability stats',
|
|
89
|
+
}, () => ctx.client.analytics.getAgentReliability({
|
|
69
90
|
agent: options.agent,
|
|
70
91
|
project: options.project,
|
|
71
92
|
days: parseIntOption(options.days, '--days'),
|
|
@@ -79,18 +100,33 @@ Examples:
|
|
|
79
100
|
else {
|
|
80
101
|
const columns = [
|
|
81
102
|
{ header: 'AGENT', accessor: 'name', width: 25 },
|
|
82
|
-
{
|
|
103
|
+
{
|
|
104
|
+
header: 'FALSE POS',
|
|
105
|
+
accessor: (v) => {
|
|
83
106
|
const rate = getFlexibleProperty(v, 'falsePositiveRate', null);
|
|
84
107
|
return `${rate?.toFixed(1) ?? '-'}%`;
|
|
85
|
-
},
|
|
86
|
-
|
|
108
|
+
},
|
|
109
|
+
width: 10,
|
|
110
|
+
align: 'right',
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
header: 'RESOLUTION',
|
|
114
|
+
accessor: (v) => {
|
|
87
115
|
const rate = getFlexibleProperty(v, 'resolutionRate', null);
|
|
88
116
|
return `${rate?.toFixed(1) ?? '-'}%`;
|
|
89
|
-
},
|
|
90
|
-
|
|
117
|
+
},
|
|
118
|
+
width: 12,
|
|
119
|
+
align: 'right',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
header: 'RELIABILITY',
|
|
123
|
+
accessor: (v) => {
|
|
91
124
|
const score = getFlexibleProperty(v, 'reliabilityScore', null);
|
|
92
125
|
return score?.toFixed(1) ?? '-';
|
|
93
|
-
},
|
|
126
|
+
},
|
|
127
|
+
width: 12,
|
|
128
|
+
align: 'right',
|
|
129
|
+
},
|
|
94
130
|
];
|
|
95
131
|
console.log(formatTable(data.agents, columns));
|
|
96
132
|
}
|
|
@@ -110,7 +146,10 @@ Examples:
|
|
|
110
146
|
const globalOpts = cmd.optsWithGlobals();
|
|
111
147
|
const ctx = createOpsContext(globalOpts);
|
|
112
148
|
try {
|
|
113
|
-
const data = await withSpinner(ctx, {
|
|
149
|
+
const data = await withSpinner(ctx, {
|
|
150
|
+
start: 'Fetching file hotspots...',
|
|
151
|
+
failure: 'Failed to fetch hotspots',
|
|
152
|
+
}, () => ctx.client.analytics.getFileHotspots({
|
|
114
153
|
project: options.project,
|
|
115
154
|
days: parseIntOption(options.days, '--days'),
|
|
116
155
|
limit: parseIntOption(options.limit, '--limit'),
|
|
@@ -123,11 +162,20 @@ Examples:
|
|
|
123
162
|
}
|
|
124
163
|
else {
|
|
125
164
|
const columns = [
|
|
126
|
-
{
|
|
127
|
-
|
|
165
|
+
{
|
|
166
|
+
header: 'FILE',
|
|
167
|
+
accessor: (h) => truncatePath(h.filePath, 45),
|
|
168
|
+
width: 45,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
header: 'ISSUES',
|
|
172
|
+
accessor: (h) => {
|
|
128
173
|
const count = getFlexibleProperty(h, 'issueCount', h.totalIssues ?? 0);
|
|
129
174
|
return String(count);
|
|
130
|
-
},
|
|
175
|
+
},
|
|
176
|
+
width: 8,
|
|
177
|
+
align: 'right',
|
|
178
|
+
},
|
|
131
179
|
];
|
|
132
180
|
console.log(formatTable(data, columns));
|
|
133
181
|
}
|
|
@@ -147,7 +195,10 @@ Examples:
|
|
|
147
195
|
const globalOpts = cmd.optsWithGlobals();
|
|
148
196
|
const ctx = createOpsContext(globalOpts);
|
|
149
197
|
try {
|
|
150
|
-
const data = await withSpinner(ctx, {
|
|
198
|
+
const data = await withSpinner(ctx, {
|
|
199
|
+
start: 'Fetching burndown data...',
|
|
200
|
+
failure: 'Failed to fetch burndown',
|
|
201
|
+
}, () => ctx.client.analytics.getBurndown({
|
|
151
202
|
project: options.project,
|
|
152
203
|
days: parseIntOption(options.days, '--days'),
|
|
153
204
|
granularity: options.granularity,
|
|
@@ -161,7 +212,11 @@ Examples:
|
|
|
161
212
|
for (const domain of ['STR', 'SEM', 'PRA', 'EPI']) {
|
|
162
213
|
const trend = data.trends[domain];
|
|
163
214
|
if (trend) {
|
|
164
|
-
const arrow = trend.trend === 'improving'
|
|
215
|
+
const arrow = trend.trend === 'improving'
|
|
216
|
+
? '↓'
|
|
217
|
+
: trend.trend === 'degrading'
|
|
218
|
+
? '↑'
|
|
219
|
+
: '→';
|
|
165
220
|
console.log(` ${domain}: ${trend.netChange >= 0 ? '+' : ''}${trend.netChange} (${arrow} ${trend.trend})`);
|
|
166
221
|
}
|
|
167
222
|
}
|
|
@@ -186,7 +241,10 @@ Examples:
|
|
|
186
241
|
const globalOpts = cmd.optsWithGlobals();
|
|
187
242
|
const ctx = createOpsContext(globalOpts);
|
|
188
243
|
try {
|
|
189
|
-
const data = await withSpinner(ctx, {
|
|
244
|
+
const data = await withSpinner(ctx, {
|
|
245
|
+
start: 'Fetching velocity metrics...',
|
|
246
|
+
failure: 'Failed to fetch velocity',
|
|
247
|
+
}, () => ctx.client.analytics.getVelocity({
|
|
190
248
|
project: options.project,
|
|
191
249
|
days: parseIntOption(options.days, '--days'),
|
|
192
250
|
alertThreshold: parseFloatOption(options.threshold, '--threshold'),
|
|
@@ -199,7 +257,9 @@ Examples:
|
|
|
199
257
|
if (data.items && data.items.length > 0) {
|
|
200
258
|
for (const item of data.items.slice(0, 10)) {
|
|
201
259
|
const alert = item.alert ? ' ⚠️' : '';
|
|
202
|
-
const velocity = item.velocityPercent >= 0
|
|
260
|
+
const velocity = item.velocityPercent >= 0
|
|
261
|
+
? `+${item.velocityPercent.toFixed(0)}%`
|
|
262
|
+
: `${item.velocityPercent.toFixed(0)}%`;
|
|
203
263
|
console.log(` ${item.failureCode}: ${velocity}${alert}`);
|
|
204
264
|
}
|
|
205
265
|
if (data.items.length > 10) {
|
|
@@ -229,7 +289,10 @@ Examples:
|
|
|
229
289
|
const globalOpts = cmd.optsWithGlobals();
|
|
230
290
|
const ctx = createOpsContext(globalOpts);
|
|
231
291
|
try {
|
|
232
|
-
const data = await withSpinner(ctx, {
|
|
292
|
+
const data = await withSpinner(ctx, {
|
|
293
|
+
start: 'Fetching discovery timeline...',
|
|
294
|
+
failure: 'Failed to fetch discovery data',
|
|
295
|
+
}, () => ctx.client.analytics.getDiscovery({
|
|
233
296
|
project: options.project,
|
|
234
297
|
days: parseIntOption(options.days, '--days'),
|
|
235
298
|
groupBy: options.groupBy,
|
|
@@ -266,7 +329,10 @@ Examples:
|
|
|
266
329
|
const globalOpts = cmd.optsWithGlobals();
|
|
267
330
|
const ctx = createOpsContext(globalOpts);
|
|
268
331
|
try {
|
|
269
|
-
const data = await withSpinner(ctx, {
|
|
332
|
+
const data = await withSpinner(ctx, {
|
|
333
|
+
start: 'Fetching agent matrix...',
|
|
334
|
+
failure: 'Failed to fetch agent matrix',
|
|
335
|
+
}, () => ctx.client.analytics.getAgentMatrix({
|
|
270
336
|
project: options.project,
|
|
271
337
|
days: parseIntOption(options.days, '--days'),
|
|
272
338
|
minIssues: parseIntOption(options.minIssues, '--min-issues'),
|
|
@@ -306,7 +372,10 @@ Examples:
|
|
|
306
372
|
const globalOpts = cmd.optsWithGlobals();
|
|
307
373
|
const ctx = createOpsContext(globalOpts);
|
|
308
374
|
try {
|
|
309
|
-
const data = await withSpinner(ctx, {
|
|
375
|
+
const data = await withSpinner(ctx, {
|
|
376
|
+
start: 'Fetching resolution rates...',
|
|
377
|
+
failure: 'Failed to fetch resolution rates',
|
|
378
|
+
}, () => ctx.client.analytics.getResolutionRates({
|
|
310
379
|
days: parseIntOption(options.days, '--days'),
|
|
311
380
|
limit: parseIntOption(options.limit, '--limit'),
|
|
312
381
|
}));
|
|
@@ -319,9 +388,24 @@ Examples:
|
|
|
319
388
|
else {
|
|
320
389
|
const columns = [
|
|
321
390
|
{ header: 'PROJECT', accessor: 'project', width: 25 },
|
|
322
|
-
{
|
|
323
|
-
|
|
324
|
-
|
|
391
|
+
{
|
|
392
|
+
header: 'RESOLVED',
|
|
393
|
+
accessor: (r) => String(r.resolvedIssues),
|
|
394
|
+
width: 10,
|
|
395
|
+
align: 'right',
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
header: 'TOTAL',
|
|
399
|
+
accessor: (r) => String(r.totalIssues),
|
|
400
|
+
width: 8,
|
|
401
|
+
align: 'right',
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
header: 'RATE',
|
|
405
|
+
accessor: (r) => `${r.resolutionRate.toFixed(1)}%`,
|
|
406
|
+
width: 8,
|
|
407
|
+
align: 'right',
|
|
408
|
+
},
|
|
325
409
|
];
|
|
326
410
|
console.log(formatTable(data, columns));
|
|
327
411
|
}
|
|
@@ -341,7 +425,10 @@ Examples:
|
|
|
341
425
|
const globalOpts = cmd.optsWithGlobals();
|
|
342
426
|
const ctx = createOpsContext(globalOpts);
|
|
343
427
|
try {
|
|
344
|
-
const data = await withSpinner(ctx, {
|
|
428
|
+
const data = await withSpinner(ctx, {
|
|
429
|
+
start: 'Fetching taxonomy distribution...',
|
|
430
|
+
failure: 'Failed to fetch taxonomy distribution',
|
|
431
|
+
}, () => ctx.client.analytics.getTaxonomyDistribution({
|
|
345
432
|
project: options.project,
|
|
346
433
|
days: parseIntOption(options.days, '--days'),
|
|
347
434
|
limit: parseIntOption(options.limit, '--limit'),
|
|
@@ -355,8 +442,18 @@ Examples:
|
|
|
355
442
|
else {
|
|
356
443
|
const columns = [
|
|
357
444
|
{ header: 'DOMAIN', accessor: (d) => d.domain ?? '-', width: 10 },
|
|
358
|
-
{
|
|
359
|
-
|
|
445
|
+
{
|
|
446
|
+
header: 'COUNT',
|
|
447
|
+
accessor: (d) => String(d.count ?? 0),
|
|
448
|
+
width: 8,
|
|
449
|
+
align: 'right',
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
header: '%',
|
|
453
|
+
accessor: (d) => `${d.percentage?.toFixed(1) ?? '-'}%`,
|
|
454
|
+
width: 8,
|
|
455
|
+
align: 'right',
|
|
456
|
+
},
|
|
360
457
|
];
|
|
361
458
|
console.log(formatTable(data, columns));
|
|
362
459
|
}
|
|
@@ -376,7 +473,10 @@ Examples:
|
|
|
376
473
|
const globalOpts = cmd.optsWithGlobals();
|
|
377
474
|
const ctx = createOpsContext(globalOpts);
|
|
378
475
|
try {
|
|
379
|
-
const result = await withSpinner(ctx, {
|
|
476
|
+
const result = await withSpinner(ctx, {
|
|
477
|
+
start: 'Fetching full taxonomy...',
|
|
478
|
+
failure: 'Failed to fetch full taxonomy',
|
|
479
|
+
}, () => ctx.client.analytics.getFullTaxonomy({
|
|
380
480
|
project: options.project,
|
|
381
481
|
days: parseIntOption(options.days, '--days'),
|
|
382
482
|
limit: parseIntOption(options.limit, '--limit'),
|
|
@@ -421,7 +521,10 @@ Examples:
|
|
|
421
521
|
const globalOpts = cmd.optsWithGlobals();
|
|
422
522
|
const ctx = createOpsContext(globalOpts);
|
|
423
523
|
try {
|
|
424
|
-
const data = await withSpinner(ctx, {
|
|
524
|
+
const data = await withSpinner(ctx, {
|
|
525
|
+
start: 'Fetching trend summary...',
|
|
526
|
+
failure: 'Failed to fetch trend summary',
|
|
527
|
+
}, () => ctx.client.analytics.getTrendSummary({
|
|
425
528
|
project: options.project,
|
|
426
529
|
days: parseIntOption(options.days, '--days'),
|
|
427
530
|
limit: parseIntOption(options.limit, '--limit'),
|