@observeone/cli 1.0.3 → 1.2.0

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.
Files changed (84) hide show
  1. package/README.md +51 -58
  2. package/dist/README.md +51 -58
  3. package/dist/commands/ai-check.d.ts.map +1 -1
  4. package/dist/commands/ai-check.js +35 -28
  5. package/dist/commands/ai-check.js.map +1 -1
  6. package/dist/commands/apply.d.ts.map +1 -1
  7. package/dist/commands/apply.js +30 -21
  8. package/dist/commands/apply.js.map +1 -1
  9. package/dist/commands/check.d.ts.map +1 -1
  10. package/dist/commands/check.js +30 -225
  11. package/dist/commands/check.js.map +1 -1
  12. package/dist/commands/export.d.ts.map +1 -1
  13. package/dist/commands/export.js +3 -3
  14. package/dist/commands/export.js.map +1 -1
  15. package/dist/commands/heartbeat.d.ts +1 -1
  16. package/dist/commands/heartbeat.d.ts.map +1 -1
  17. package/dist/commands/heartbeat.js +39 -234
  18. package/dist/commands/heartbeat.js.map +1 -1
  19. package/dist/commands/init.d.ts +5 -0
  20. package/dist/commands/init.d.ts.map +1 -0
  21. package/dist/commands/init.js +68 -0
  22. package/dist/commands/init.js.map +1 -0
  23. package/dist/commands/login.d.ts.map +1 -1
  24. package/dist/commands/login.js +10 -58
  25. package/dist/commands/login.js.map +1 -1
  26. package/dist/commands/monitor.d.ts +1 -1
  27. package/dist/commands/monitor.d.ts.map +1 -1
  28. package/dist/commands/monitor.js +32 -235
  29. package/dist/commands/monitor.js.map +1 -1
  30. package/dist/commands/resource-command.factory.d.ts +31 -0
  31. package/dist/commands/resource-command.factory.d.ts.map +1 -0
  32. package/dist/commands/resource-command.factory.js +208 -0
  33. package/dist/commands/resource-command.factory.js.map +1 -0
  34. package/dist/commands/signup.d.ts +9 -0
  35. package/dist/commands/signup.d.ts.map +1 -0
  36. package/dist/commands/signup.js +54 -0
  37. package/dist/commands/signup.js.map +1 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +16 -6
  40. package/dist/index.js.map +1 -1
  41. package/dist/interfaces/api-client.interface.d.ts +9 -6
  42. package/dist/interfaces/api-client.interface.d.ts.map +1 -1
  43. package/dist/interfaces/config.interface.d.ts +5 -10
  44. package/dist/interfaces/config.interface.d.ts.map +1 -1
  45. package/dist/interfaces/output.interface.d.ts +20 -3
  46. package/dist/interfaces/output.interface.d.ts.map +1 -1
  47. package/dist/interfaces/sse-client.interface.d.ts +3 -3
  48. package/dist/interfaces/sse-client.interface.d.ts.map +1 -1
  49. package/dist/package.json +1 -1
  50. package/dist/services/api-client.service.d.ts +7 -4
  51. package/dist/services/api-client.service.d.ts.map +1 -1
  52. package/dist/services/api-client.service.js +46 -20
  53. package/dist/services/api-client.service.js.map +1 -1
  54. package/dist/services/config.service.d.ts +7 -12
  55. package/dist/services/config.service.d.ts.map +1 -1
  56. package/dist/services/config.service.js +47 -18
  57. package/dist/services/config.service.js.map +1 -1
  58. package/dist/services/output.service.d.ts +20 -3
  59. package/dist/services/output.service.d.ts.map +1 -1
  60. package/dist/services/output.service.js +11 -10
  61. package/dist/services/output.service.js.map +1 -1
  62. package/dist/services/sse-client.service.d.ts +1 -1
  63. package/dist/services/sse-client.service.d.ts.map +1 -1
  64. package/dist/services/sse-client.service.js +2 -1
  65. package/dist/services/sse-client.service.js.map +1 -1
  66. package/dist/services/update.service.d.ts +13 -0
  67. package/dist/services/update.service.d.ts.map +1 -0
  68. package/dist/services/update.service.js +57 -0
  69. package/dist/services/update.service.js.map +1 -0
  70. package/dist/types/index.d.ts +37 -35
  71. package/dist/types/index.d.ts.map +1 -1
  72. package/dist/utils/deep-equal.d.ts +2 -2
  73. package/dist/utils/deep-equal.d.ts.map +1 -1
  74. package/dist/utils/deep-equal.js +6 -4
  75. package/dist/utils/deep-equal.js.map +1 -1
  76. package/dist/utils/live-progress.d.ts +10 -1
  77. package/dist/utils/live-progress.d.ts.map +1 -1
  78. package/dist/utils/live-progress.js +5 -5
  79. package/dist/utils/live-progress.js.map +1 -1
  80. package/dist/utils/log-writer.d.ts +15 -2
  81. package/dist/utils/log-writer.d.ts.map +1 -1
  82. package/dist/utils/log-writer.js +1 -1
  83. package/dist/utils/log-writer.js.map +1 -1
  84. package/package.json +1 -1
package/README.md CHANGED
@@ -17,12 +17,18 @@ npm install -g @observeone/cli
17
17
  obs login
18
18
  ```
19
19
 
20
- 2. **Pull your existing configuration**
20
+ 2. **Initialize Workspace**
21
+ ```bash
22
+ # Creates local .obs.config.json
23
+ obs init
24
+ ```
25
+
26
+ 3. **Pull your existing configuration**
21
27
  ```bash
22
28
  obs export
23
29
  ```
24
30
 
25
- 3. **Manage a monitor**
31
+ 4. **Manage a monitor**
26
32
  ```bash
27
33
  obs monitor create --name "My Website" --url "https://example.com" --interval "*/5 * * * *"
28
34
  obs monitor list
@@ -30,7 +36,19 @@ npm install -g @observeone/cli
30
36
 
31
37
  ---
32
38
 
33
- ## 🏗️ Config-as-Code (Declarative Workflow)
39
+ ## Configuration Priority
40
+
41
+ The CLI resolves configuration settings in the following order (highest to lowest priority):
42
+
43
+ 1. **CLI Flags**: `--api-key`, `--api-url` passed directly to a command.
44
+ 2. **Environment Variables**: `OBS_API_KEY`, `OBS_API_URL`.
45
+ 3. **Local Config File**: `.obs.config.json` in the current working directory (created via `obs init`).
46
+ 4. **Global Store**: Global OS configuration (saved after `obs login`).
47
+ 5. **Defaults**: Internal default values.
48
+
49
+ ---
50
+
51
+ ## Config-as-Code (Declarative Workflow)
34
52
 
35
53
  ObserveOne supports an Infrastructure-as-Code (IaC) workflow using JSON. You can define all your monitors, API checks, and heartbeats in a single `obs.json` file and sync them to your account.
36
54
 
@@ -60,6 +78,7 @@ obs apply -f my-stack.json
60
78
  "monitors": [
61
79
  {
62
80
  "name": "Production Website",
81
+ "description": "Main landing page monitor",
63
82
  "url": "https://example.com",
64
83
  "interval": "*/5 * * * *",
65
84
  "alert_on_failure": true
@@ -75,7 +94,8 @@ obs apply -f my-stack.json
75
94
  "heartbeats": [
76
95
  {
77
96
  "name": "Database Backup Job",
78
- "period": 86400
97
+ "period": 86400,
98
+ "grace_period": 3600
79
99
  }
80
100
  ]
81
101
  }
@@ -83,12 +103,11 @@ obs apply -f my-stack.json
83
103
 
84
104
  ---
85
105
 
86
- ## 🛠️ Resource Management (CRUD)
106
+ ## Resource Management (CRUD)
87
107
 
88
108
  You can manually create, read, update, delete, and toggle individual resources directly from the terminal.
89
109
 
90
110
  ### URL Monitors
91
- Manage basic HTTP ping monitors.
92
111
  ```bash
93
112
  obs monitor create --name "Frontend" --url "https://example.com" --interval "*/5 * * * *"
94
113
  obs monitor list
@@ -99,7 +118,6 @@ obs monitor delete <id> -y
99
118
  ```
100
119
 
101
120
  ### API Checks
102
- Manage complex API health checks.
103
121
  ```bash
104
122
  obs check create --name "Auth API" --url "https://api.example.com/auth" --method "POST"
105
123
  obs check list
@@ -109,51 +127,39 @@ obs check delete <id> -y
109
127
  ```
110
128
 
111
129
  ### Heartbeats (Cron Monitoring)
112
- Manage heartbeat checks (for monitoring background jobs or cron tasks).
113
130
  ```bash
114
- obs heartbeat create --name "Daily Backup" --period 86400
131
+ obs heartbeat create --name "Daily Backup" --period 86400 --grace 3600
115
132
  obs heartbeat list
116
133
  obs heartbeat update <id> --period 43200
117
134
  obs heartbeat toggle <id>
118
135
  obs heartbeat delete <id> -y
119
136
  ```
120
137
 
121
- ### AI Browser Checks
138
+ ---
139
+
140
+ ## AI Browser Checks
141
+
122
142
  Manage and execute intelligent Playwright-driven browser tests using natural language prompts.
123
- ```bash
124
- obs ai-check create --name "Login Flow" --url "https://app.com" --prompt "Login with test@example.com"
125
- obs ai-check list
126
- obs ai-check get <id>
127
- obs ai-check delete <id> -y
128
- ```
129
143
 
130
- #### Running AI Checks
131
- You can execute pre-configured checks or run them "ad-hoc" on the fly.
132
144
  ```bash
133
- # Run an existing test by name or ID
134
- obs ai-check run "Login Flow"
135
- obs ai-check run 123
145
+ # Run an existing test and output JUnit report for CI
146
+ obs ai-check run "Login Flow" --reporter junit
136
147
 
137
- # Run multiple tests sequentially
138
- obs ai-check run test1 test2 test3
148
+ # Run multiple tests and output strict JSON for AI Agents
149
+ obs ai-check run test1 test2 --reporter json
139
150
 
140
- # Run an ad-hoc test without saving it to the database
141
- obs ai-check run --adhoc --url https://example.com --prompt "Verify the hero section exists"
151
+ # Run an ad-hoc test without saving it
152
+ obs ai-check run --adhoc --url https://example.com --prompt "Verify login section exists"
142
153
  ```
143
154
 
144
155
  ---
145
156
 
146
- ## 🤖 AI Agent Integration (Headless Mode)
157
+ ## AI Agent Integration (Headless Mode)
147
158
 
148
- The `obs` CLI is explicitly designed to be used by AI coding agents (like Cursor, GitHub Copilot, Claude Code, or custom bots).
159
+ The `obs` CLI is explicitly designed to be used by AI coding agents.
149
160
 
150
161
  ### The `--json` Flag
151
- Append `--json` to **any** command. The CLI will automatically suppress all human-readable output (chalk colors, loading spinners, raw logs) and return a strict, machine-readable `JsonEnvelope`.
152
-
153
- ```bash
154
- obs monitor list --json
155
- obs apply -f my-stack.json --json
156
- ```
162
+ Append `--json` to **any** command. The CLI will automatically suppress all human-readable output and return a strict, machine-readable `JsonEnvelope`.
157
163
 
158
164
  **Guaranteed Agent Response Schema:**
159
165
  ```json
@@ -165,33 +171,28 @@ obs apply -f my-stack.json --json
165
171
  }
166
172
  }
167
173
  ```
168
- *(If an error occurs, `status` will be `"ERROR"` and the envelope will contain a strict `error` object, preventing the agent's JSON parser from crashing).*
169
174
 
170
- ### Headless Authentication
171
- Agents can authenticate securely using environment variables without interactive browser prompts:
175
+ ### Headless Account Setup
172
176
  ```bash
177
+ # Create a secure account for automated bots (Rate-limited)
178
+ obs signup
179
+
180
+ # Headless Login using environment variables
173
181
  export OBS_EMAIL="agent@company.com"
174
182
  export OBS_PASSWORD="secure-password"
175
-
176
- # Automatically provisions and saves an API key to local config
177
183
  obs login --headless
178
184
  ```
179
185
 
180
- Alternatively, inject an existing API key directly into the environment:
181
- ```bash
182
- export OBS_API_KEY="your_api_key_here"
183
- ```
184
-
185
186
  ---
186
187
 
187
- ## ⚙️ Global Configuration
188
+ ## Update Notifications
188
189
 
189
- Available for all commands:
190
- ```bash
191
- obs <command> [options]
192
- ```
190
+ The CLI includes a non-blocking background update service that checks for newer versions on npm. If an update is available, a notification will be displayed at the start of your command output. This check is automatically disabled in `--json` mode.
191
+
192
+ ---
193
+
194
+ ## Global Options
193
195
 
194
- **Options:**
195
196
  - `-v, --verbose` - Enable verbose output and stack traces
196
197
  - `--json` - Output in strict JSON format
197
198
  - `--api-url <url>` - Override API URL
@@ -199,16 +200,8 @@ obs <command> [options]
199
200
  - `--version` - Show version number
200
201
  - `--help` - Show help
201
202
 
202
- ### Environment Variables
203
- ```bash
204
- export OBS_API_URL=https://api.observeone.com
205
- export OBS_API_KEY=your-api-key
206
- export OBS_VERBOSE=true
207
- export OBS_JSON_OUTPUT=true
208
- ```
209
-
210
203
  ## License
211
204
  MIT
212
205
 
213
206
  ---
214
- **Happy Testing! 🚀**
207
+ **Happy Testing!**
package/dist/README.md CHANGED
@@ -17,12 +17,18 @@ npm install -g @observeone/cli
17
17
  obs login
18
18
  ```
19
19
 
20
- 2. **Pull your existing configuration**
20
+ 2. **Initialize Workspace**
21
+ ```bash
22
+ # Creates local .obs.config.json
23
+ obs init
24
+ ```
25
+
26
+ 3. **Pull your existing configuration**
21
27
  ```bash
22
28
  obs export
23
29
  ```
24
30
 
25
- 3. **Manage a monitor**
31
+ 4. **Manage a monitor**
26
32
  ```bash
27
33
  obs monitor create --name "My Website" --url "https://example.com" --interval "*/5 * * * *"
28
34
  obs monitor list
@@ -30,7 +36,19 @@ npm install -g @observeone/cli
30
36
 
31
37
  ---
32
38
 
33
- ## 🏗️ Config-as-Code (Declarative Workflow)
39
+ ## Configuration Priority
40
+
41
+ The CLI resolves configuration settings in the following order (highest to lowest priority):
42
+
43
+ 1. **CLI Flags**: `--api-key`, `--api-url` passed directly to a command.
44
+ 2. **Environment Variables**: `OBS_API_KEY`, `OBS_API_URL`.
45
+ 3. **Local Config File**: `.obs.config.json` in the current working directory (created via `obs init`).
46
+ 4. **Global Store**: Global OS configuration (saved after `obs login`).
47
+ 5. **Defaults**: Internal default values.
48
+
49
+ ---
50
+
51
+ ## Config-as-Code (Declarative Workflow)
34
52
 
35
53
  ObserveOne supports an Infrastructure-as-Code (IaC) workflow using JSON. You can define all your monitors, API checks, and heartbeats in a single `obs.json` file and sync them to your account.
36
54
 
@@ -60,6 +78,7 @@ obs apply -f my-stack.json
60
78
  "monitors": [
61
79
  {
62
80
  "name": "Production Website",
81
+ "description": "Main landing page monitor",
63
82
  "url": "https://example.com",
64
83
  "interval": "*/5 * * * *",
65
84
  "alert_on_failure": true
@@ -75,7 +94,8 @@ obs apply -f my-stack.json
75
94
  "heartbeats": [
76
95
  {
77
96
  "name": "Database Backup Job",
78
- "period": 86400
97
+ "period": 86400,
98
+ "grace_period": 3600
79
99
  }
80
100
  ]
81
101
  }
@@ -83,12 +103,11 @@ obs apply -f my-stack.json
83
103
 
84
104
  ---
85
105
 
86
- ## 🛠️ Resource Management (CRUD)
106
+ ## Resource Management (CRUD)
87
107
 
88
108
  You can manually create, read, update, delete, and toggle individual resources directly from the terminal.
89
109
 
90
110
  ### URL Monitors
91
- Manage basic HTTP ping monitors.
92
111
  ```bash
93
112
  obs monitor create --name "Frontend" --url "https://example.com" --interval "*/5 * * * *"
94
113
  obs monitor list
@@ -99,7 +118,6 @@ obs monitor delete <id> -y
99
118
  ```
100
119
 
101
120
  ### API Checks
102
- Manage complex API health checks.
103
121
  ```bash
104
122
  obs check create --name "Auth API" --url "https://api.example.com/auth" --method "POST"
105
123
  obs check list
@@ -109,51 +127,39 @@ obs check delete <id> -y
109
127
  ```
110
128
 
111
129
  ### Heartbeats (Cron Monitoring)
112
- Manage heartbeat checks (for monitoring background jobs or cron tasks).
113
130
  ```bash
114
- obs heartbeat create --name "Daily Backup" --period 86400
131
+ obs heartbeat create --name "Daily Backup" --period 86400 --grace 3600
115
132
  obs heartbeat list
116
133
  obs heartbeat update <id> --period 43200
117
134
  obs heartbeat toggle <id>
118
135
  obs heartbeat delete <id> -y
119
136
  ```
120
137
 
121
- ### AI Browser Checks
138
+ ---
139
+
140
+ ## AI Browser Checks
141
+
122
142
  Manage and execute intelligent Playwright-driven browser tests using natural language prompts.
123
- ```bash
124
- obs ai-check create --name "Login Flow" --url "https://app.com" --prompt "Login with test@example.com"
125
- obs ai-check list
126
- obs ai-check get <id>
127
- obs ai-check delete <id> -y
128
- ```
129
143
 
130
- #### Running AI Checks
131
- You can execute pre-configured checks or run them "ad-hoc" on the fly.
132
144
  ```bash
133
- # Run an existing test by name or ID
134
- obs ai-check run "Login Flow"
135
- obs ai-check run 123
145
+ # Run an existing test and output JUnit report for CI
146
+ obs ai-check run "Login Flow" --reporter junit
136
147
 
137
- # Run multiple tests sequentially
138
- obs ai-check run test1 test2 test3
148
+ # Run multiple tests and output strict JSON for AI Agents
149
+ obs ai-check run test1 test2 --reporter json
139
150
 
140
- # Run an ad-hoc test without saving it to the database
141
- obs ai-check run --adhoc --url https://example.com --prompt "Verify the hero section exists"
151
+ # Run an ad-hoc test without saving it
152
+ obs ai-check run --adhoc --url https://example.com --prompt "Verify login section exists"
142
153
  ```
143
154
 
144
155
  ---
145
156
 
146
- ## 🤖 AI Agent Integration (Headless Mode)
157
+ ## AI Agent Integration (Headless Mode)
147
158
 
148
- The `obs` CLI is explicitly designed to be used by AI coding agents (like Cursor, GitHub Copilot, Claude Code, or custom bots).
159
+ The `obs` CLI is explicitly designed to be used by AI coding agents.
149
160
 
150
161
  ### The `--json` Flag
151
- Append `--json` to **any** command. The CLI will automatically suppress all human-readable output (chalk colors, loading spinners, raw logs) and return a strict, machine-readable `JsonEnvelope`.
152
-
153
- ```bash
154
- obs monitor list --json
155
- obs apply -f my-stack.json --json
156
- ```
162
+ Append `--json` to **any** command. The CLI will automatically suppress all human-readable output and return a strict, machine-readable `JsonEnvelope`.
157
163
 
158
164
  **Guaranteed Agent Response Schema:**
159
165
  ```json
@@ -165,33 +171,28 @@ obs apply -f my-stack.json --json
165
171
  }
166
172
  }
167
173
  ```
168
- *(If an error occurs, `status` will be `"ERROR"` and the envelope will contain a strict `error` object, preventing the agent's JSON parser from crashing).*
169
174
 
170
- ### Headless Authentication
171
- Agents can authenticate securely using environment variables without interactive browser prompts:
175
+ ### Headless Account Setup
172
176
  ```bash
177
+ # Create a secure account for automated bots (Rate-limited)
178
+ obs signup
179
+
180
+ # Headless Login using environment variables
173
181
  export OBS_EMAIL="agent@company.com"
174
182
  export OBS_PASSWORD="secure-password"
175
-
176
- # Automatically provisions and saves an API key to local config
177
183
  obs login --headless
178
184
  ```
179
185
 
180
- Alternatively, inject an existing API key directly into the environment:
181
- ```bash
182
- export OBS_API_KEY="your_api_key_here"
183
- ```
184
-
185
186
  ---
186
187
 
187
- ## ⚙️ Global Configuration
188
+ ## Update Notifications
188
189
 
189
- Available for all commands:
190
- ```bash
191
- obs <command> [options]
192
- ```
190
+ The CLI includes a non-blocking background update service that checks for newer versions on npm. If an update is available, a notification will be displayed at the start of your command output. This check is automatically disabled in `--json` mode.
191
+
192
+ ---
193
+
194
+ ## Global Options
193
195
 
194
- **Options:**
195
196
  - `-v, --verbose` - Enable verbose output and stack traces
196
197
  - `--json` - Output in strict JSON format
197
198
  - `--api-url <url>` - Override API URL
@@ -199,16 +200,8 @@ obs <command> [options]
199
200
  - `--version` - Show version number
200
201
  - `--help` - Show help
201
202
 
202
- ### Environment Variables
203
- ```bash
204
- export OBS_API_URL=https://api.observeone.com
205
- export OBS_API_KEY=your-api-key
206
- export OBS_VERBOSE=true
207
- export OBS_JSON_OUTPUT=true
208
- ```
209
-
210
203
  ## License
211
204
  MIT
212
205
 
213
206
  ---
214
- **Happy Testing! 🚀**
207
+ **Happy Testing!**
@@ -1 +1 @@
1
- {"version":3,"file":"ai-check.d.ts","sourceRoot":"","sources":["../../src/commands/ai-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAMnE;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,cAAc,EAC7B,SAAS,EAAE,UAAU,EACrB,aAAa,EAAE,cAAc,GAC5B,OAAO,CA+QT"}
1
+ {"version":3,"file":"ai-check.d.ts","sourceRoot":"","sources":["../../src/commands/ai-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAqBnE;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,cAAc,EAC7B,SAAS,EAAE,UAAU,EACrB,aAAa,EAAE,cAAc,GAC5B,OAAO,CAyRT"}
@@ -69,7 +69,9 @@ export function createAiCheckCommand(configService, apiClient, outputService) {
69
69
  .option('-f, --format <format>', 'Output format (table, json)', 'table')
70
70
  .option('-j, --json', 'Output in JSON format')
71
71
  .action(async (options) => {
72
- if (process.env.OBS_JSON_OUTPUT === 'true' || options.format === 'json' || options.json) {
72
+ if (process.env.OBS_JSON_OUTPUT === 'true' ||
73
+ options.format === 'json' ||
74
+ options.json === true) {
73
75
  outputService.enableJsonMode();
74
76
  }
75
77
  try {
@@ -80,7 +82,9 @@ export function createAiCheckCommand(configService, apiClient, outputService) {
80
82
  }
81
83
  outputService.progress('Fetching AI checks...');
82
84
  const tests = await apiClient.getTests();
83
- if (process.env.OBS_JSON_OUTPUT === 'true' || options.format === 'json' || options.json) {
85
+ if (process.env.OBS_JSON_OUTPUT === 'true' ||
86
+ options.format === 'json' ||
87
+ options.json === true) {
84
88
  outputService.formatJsonOutput(tests);
85
89
  }
86
90
  else {
@@ -98,7 +102,7 @@ export function createAiCheckCommand(configService, apiClient, outputService) {
98
102
  .description('Get details of an AI browser check')
99
103
  .option('-j, --json', 'Output in JSON format')
100
104
  .action(async (id, options) => {
101
- if (process.env.OBS_JSON_OUTPUT === 'true' || options.json) {
105
+ if (process.env.OBS_JSON_OUTPUT === 'true' || options.json === true) {
102
106
  outputService.enableJsonMode();
103
107
  }
104
108
  try {
@@ -135,7 +139,7 @@ export function createAiCheckCommand(configService, apiClient, outputService) {
135
139
  .option('-p, --prompt <prompt>', 'Test prompt')
136
140
  .option('-j, --json', 'Output in JSON format')
137
141
  .action(async (options) => {
138
- if (process.env.OBS_JSON_OUTPUT === 'true' || options.json) {
142
+ if (process.env.OBS_JSON_OUTPUT === 'true' || options.json === true) {
139
143
  outputService.enableJsonMode();
140
144
  }
141
145
  try {
@@ -144,7 +148,9 @@ export function createAiCheckCommand(configService, apiClient, outputService) {
144
148
  outputService.error('Not authenticated. Please run "obs login" first.');
145
149
  process.exit(1);
146
150
  }
147
- let { name, url, prompt } = options;
151
+ let name = options.name;
152
+ let url = options.url;
153
+ let prompt = options.prompt;
148
154
  if (!name || !url || !prompt) {
149
155
  const answers = await inquirer.prompt([
150
156
  {
@@ -183,9 +189,9 @@ export function createAiCheckCommand(configService, apiClient, outputService) {
183
189
  }
184
190
  outputService.progress('Creating AI browser check...');
185
191
  const newTest = await apiClient.createTest({
186
- name,
187
- url,
188
- prompt,
192
+ name: name,
193
+ url: url,
194
+ prompt: prompt,
189
195
  description: 'Created via CLI',
190
196
  });
191
197
  if (process.env.OBS_JSON_OUTPUT === 'true') {
@@ -207,7 +213,7 @@ export function createAiCheckCommand(configService, apiClient, outputService) {
207
213
  .option('-y, --yes', 'Skip confirmation prompt')
208
214
  .option('-j, --json', 'Output in JSON format')
209
215
  .action(async (id, options) => {
210
- if (process.env.OBS_JSON_OUTPUT === 'true' || options.json) {
216
+ if (process.env.OBS_JSON_OUTPUT === 'true' || options.json === true) {
211
217
  outputService.enableJsonMode();
212
218
  }
213
219
  try {
@@ -254,7 +260,7 @@ export function createAiCheckCommand(configService, apiClient, outputService) {
254
260
  */
255
261
  async function runAdhocTest(apiClient, outputService, configService, options, timeout, results, shouldWait, isJson) {
256
262
  const spinner = isJson
257
- ? { start: () => { }, succeed: () => { }, fail: () => { } }
263
+ ? { start: () => { }, succeed: (_msg) => { }, fail: (_msg) => { } }
258
264
  : ora('Running ad-hoc test...').start();
259
265
  try {
260
266
  const result = await apiClient.executeAdhocTest({
@@ -278,9 +284,9 @@ async function runAdhocTest(apiClient, outputService, configService, options, ti
278
284
  /**
279
285
  * Run named tests
280
286
  */
281
- async function runNamedTests(apiClient, outputService, configService, testNames, options, timeout, results, shouldWait, isJson) {
287
+ async function runNamedTests(apiClient, _outputService, configService, testNames, options, timeout, results, shouldWait, isJson) {
282
288
  const spinner = isJson
283
- ? { start: () => { }, succeed: () => { }, fail: () => { } }
289
+ ? { start: () => { }, succeed: (_msg) => { }, fail: (_msg) => { } }
284
290
  : ora('Fetching test details...').start();
285
291
  try {
286
292
  const tests = await apiClient.getTests();
@@ -304,7 +310,7 @@ async function runNamedTests(apiClient, outputService, configService, testNames,
304
310
  // Execute each test
305
311
  for (const test of testsToRun) {
306
312
  const testSpinner = isJson
307
- ? { start: () => { }, succeed: () => { }, fail: () => { } }
313
+ ? { start: () => { }, succeed: (_msg) => { }, fail: (_msg) => { } }
308
314
  : ora(`Running test: ${test.name}`).start();
309
315
  try {
310
316
  const result = await apiClient.executeTest(test.id);
@@ -355,7 +361,7 @@ async function streamTestProgress(configService, result, testName, options, time
355
361
  if (message.type === 'step_update' && message.step) {
356
362
  stepCounter++;
357
363
  const step = message.step;
358
- if (!silent) {
364
+ if (!silent && renderer && logger) {
359
365
  if (message.screenshot) {
360
366
  renderer.addScreenshot();
361
367
  logger.writeScreenshot(stepCounter);
@@ -365,14 +371,14 @@ async function streamTestProgress(configService, result, testName, options, time
365
371
  }
366
372
  }
367
373
  else if (message.type === 'screenshot') {
368
- if (!silent) {
374
+ if (!silent && renderer && logger) {
369
375
  renderer.addScreenshot();
370
376
  logger.writeScreenshot(stepCounter);
371
377
  }
372
378
  }
373
379
  else if (message.type === 'complete' || message.type === 'task_completed') {
374
380
  const status = message.status === 'failed' ? 'failed' : 'success';
375
- if (!silent) {
381
+ if (!silent && renderer && logger) {
376
382
  renderer.complete(status, message.message);
377
383
  logger.writeComplete(status, message.message);
378
384
  }
@@ -386,13 +392,13 @@ async function streamTestProgress(configService, result, testName, options, time
386
392
  };
387
393
  completed = true;
388
394
  sseClient.close();
389
- if (!silent) {
395
+ if (!silent && logger) {
390
396
  logger.close();
391
397
  console.log(chalk.gray(`\nDetailed logs: ${logger.getPath()}`));
392
398
  }
393
399
  }
394
400
  else if (message.type === 'error') {
395
- if (!silent) {
401
+ if (!silent && renderer && logger) {
396
402
  renderer.error(message.message || 'Test failed');
397
403
  logger.writeComplete('failed', message.message);
398
404
  }
@@ -403,23 +409,24 @@ async function streamTestProgress(configService, result, testName, options, time
403
409
  };
404
410
  completed = true;
405
411
  sseClient.close();
406
- if (!silent) {
412
+ if (!silent && logger) {
407
413
  logger.close();
408
414
  }
409
415
  }
410
416
  }, (error) => {
411
417
  if (!completed) {
412
- if (!silent) {
413
- renderer.error(`Connection error: ${error.message}`);
414
- logger.writeComplete('failed', `Connection error: ${error.message}`);
418
+ const err = error;
419
+ if (!silent && renderer && logger) {
420
+ renderer.error(`Connection error: ${err.message}`);
421
+ logger.writeComplete('failed', `Connection error: ${err.message}`);
415
422
  }
416
423
  results[results.length - 1] = {
417
424
  ...result,
418
425
  status: 'FAILED',
419
- message: `Connection error: ${error.message}`,
426
+ message: `Connection error: ${err.message}`,
420
427
  };
421
428
  sseClient.close();
422
- if (!silent) {
429
+ if (!silent && logger) {
423
430
  logger.close();
424
431
  }
425
432
  completed = true;
@@ -436,7 +443,7 @@ async function streamTestProgress(configService, result, testName, options, time
436
443
  setTimeout(() => {
437
444
  if (!completed) {
438
445
  clearInterval(checkInterval);
439
- if (!silent) {
446
+ if (!silent && renderer) {
440
447
  renderer.error('Test execution timed out');
441
448
  }
442
449
  results[results.length - 1] = {
@@ -445,7 +452,7 @@ async function streamTestProgress(configService, result, testName, options, time
445
452
  message: 'Test execution timed out',
446
453
  };
447
454
  sseClient.close();
448
- if (!silent) {
455
+ if (!silent && logger) {
449
456
  logger.close();
450
457
  }
451
458
  resolve();
@@ -507,11 +514,11 @@ function generateJUnitReport(results, outputService) {
507
514
  tests: results.length,
508
515
  failures: results.filter((r) => r.status === 'FAILED').length,
509
516
  errors: 0,
510
- time: results.reduce((total, r) => total + (r.duration || 0), 0) / 1000,
517
+ time: (results.reduce((total, r) => total + (r.duration || 0), 0) / 1000).toString(),
511
518
  testCases: results.map((result, index) => ({
512
519
  name: `Test ${index + 1}`,
513
520
  classname: 'observeone.test',
514
- time: (result.duration || 0) / 1000,
521
+ time: ((result.duration || 0) / 1000).toString(),
515
522
  status: result.status === 'SUCCESS' ? 'passed' : 'failed',
516
523
  failure: result.status === 'FAILED'
517
524
  ? {