@owlmetry/cli 0.1.11 → 0.1.13
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/dist/index.cjs
CHANGED
|
@@ -6359,6 +6359,9 @@ var METRIC_PHASES = ["start", "complete", "fail", "cancel", "record"];
|
|
|
6359
6359
|
// ../../packages/shared/dist/audit.js
|
|
6360
6360
|
init_cjs_shims();
|
|
6361
6361
|
|
|
6362
|
+
// ../../packages/shared/dist/time.js
|
|
6363
|
+
init_cjs_shims();
|
|
6364
|
+
|
|
6362
6365
|
// src/commands/apps.ts
|
|
6363
6366
|
var appsCommand = new Command("apps").description("Manage apps");
|
|
6364
6367
|
appsCommand.command("list").description("List apps").option("--project-id <id>", "Filter by project ID").action(async (opts, cmd) => {
|
|
@@ -6492,33 +6495,6 @@ function resolveJsonArray(inline, filePath, opts) {
|
|
|
6492
6495
|
return parsed;
|
|
6493
6496
|
}
|
|
6494
6497
|
|
|
6495
|
-
// src/utils/time.ts
|
|
6496
|
-
init_cjs_shims();
|
|
6497
|
-
var RELATIVE_PATTERN = /^(\d+)([smhdw])$/;
|
|
6498
|
-
var MULTIPLIERS = {
|
|
6499
|
-
s: 1e3,
|
|
6500
|
-
m: 6e4,
|
|
6501
|
-
h: 36e5,
|
|
6502
|
-
d: 864e5,
|
|
6503
|
-
w: 6048e5
|
|
6504
|
-
};
|
|
6505
|
-
function parseTimeInput(input) {
|
|
6506
|
-
const match = input.match(RELATIVE_PATTERN);
|
|
6507
|
-
if (match) {
|
|
6508
|
-
const amount = parseInt(match[1], 10);
|
|
6509
|
-
const unit = match[2];
|
|
6510
|
-
const ms = amount * MULTIPLIERS[unit];
|
|
6511
|
-
return new Date(Date.now() - ms).toISOString();
|
|
6512
|
-
}
|
|
6513
|
-
const date = new Date(input);
|
|
6514
|
-
if (isNaN(date.getTime())) {
|
|
6515
|
-
throw new Error(
|
|
6516
|
-
`Invalid time input: "${input}". Use relative (e.g. 1h, 30m, 7d) or ISO 8601 format.`
|
|
6517
|
-
);
|
|
6518
|
-
}
|
|
6519
|
-
return date.toISOString();
|
|
6520
|
-
}
|
|
6521
|
-
|
|
6522
6498
|
// src/utils/pagination.ts
|
|
6523
6499
|
init_cjs_shims();
|
|
6524
6500
|
function paginationHint(result) {
|
|
@@ -6538,8 +6514,8 @@ var eventsCommand = new Command("events").description("Query events").option("--
|
|
|
6538
6514
|
new Option("--data-mode <mode>", "Data mode: production, development, or all").choices(["production", "development", "all"]).default("production")
|
|
6539
6515
|
).action(async (opts, cmd) => {
|
|
6540
6516
|
const { client, globals } = createClient(cmd);
|
|
6541
|
-
const since = opts.since
|
|
6542
|
-
const until = opts.until
|
|
6517
|
+
const since = opts.since ?? (!opts.until ? "24h" : void 0);
|
|
6518
|
+
const until = opts.until;
|
|
6543
6519
|
const result = await client.queryEvents({
|
|
6544
6520
|
project_id: opts.projectId,
|
|
6545
6521
|
app_id: opts.appId,
|
|
@@ -6797,8 +6773,8 @@ metricsCommand.command("events <slug>").description("Query raw metric events for
|
|
|
6797
6773
|
new Option("--data-mode <mode>", "Data mode: production, development, or all").choices(["production", "development", "all"]).default("production")
|
|
6798
6774
|
).action(async (slug, opts, cmd) => {
|
|
6799
6775
|
const { client, globals } = createClient(cmd);
|
|
6800
|
-
const since = opts.since
|
|
6801
|
-
const until = opts.until
|
|
6776
|
+
const since = opts.since ?? (!opts.until ? "24h" : void 0);
|
|
6777
|
+
const until = opts.until;
|
|
6802
6778
|
const result = await client.queryMetricEvents(slug, opts.projectId, {
|
|
6803
6779
|
phase: opts.phase,
|
|
6804
6780
|
tracking_id: opts.trackingId,
|
|
@@ -6840,7 +6816,7 @@ metricsCommand.command("create").description("Create a new metric definition").r
|
|
|
6840
6816
|
});
|
|
6841
6817
|
output(globals.format, metric, () => formatMetricDetail(metric));
|
|
6842
6818
|
});
|
|
6843
|
-
metricsCommand.command("query <slug>").description("Query metric aggregation").requiredOption("--project-id <id>", "Project ID").option("--since <date>", "Start
|
|
6819
|
+
metricsCommand.command("query <slug>").description("Query metric aggregation").requiredOption("--project-id <id>", "Project ID").option("--since <date>", "Start time (e.g. 1h, 30m, 7d, or ISO 8601)").option("--until <date>", "End time (e.g. 1h, 30m, 7d, or ISO 8601)").option("--app-id <id>", "Filter by app ID").option("--app-version <version>", "Filter by app version").option("--device-model <model>", "Filter by device model").option("--os-version <version>", "Filter by OS version").option("--user-id <id>", "Filter by user ID").option("--environment <env>", "Filter by environment (ios, ipados, macos, android, web, backend)").option("--group-by <field>", "Group by: app_id, app_version, device_model, os_version, environment, time:hour, time:day, time:week").addOption(
|
|
6844
6820
|
new Option("--data-mode <mode>", "Data mode: production, development, or all").choices(["production", "development", "all"]).default("production")
|
|
6845
6821
|
).action(async (slug, opts, cmd) => {
|
|
6846
6822
|
const { client, globals } = createClient(cmd);
|
|
@@ -6899,7 +6875,7 @@ ${funnel.description}`);
|
|
|
6899
6875
|
const step = funnel.steps[i];
|
|
6900
6876
|
const filter = step.event_filter;
|
|
6901
6877
|
const filterParts = [];
|
|
6902
|
-
if (filter.
|
|
6878
|
+
if (filter.step_name) filterParts.push(`step=${filter.step_name}`);
|
|
6903
6879
|
if (filter.screen_name) filterParts.push(`screen=${filter.screen_name}`);
|
|
6904
6880
|
lines.push(` ${i + 1}. ${step.name} ${source_default.dim(filterParts.join(", "))}`);
|
|
6905
6881
|
}
|
|
@@ -7010,7 +6986,7 @@ funnelsCommand.command("delete <slug>").description("Delete a funnel definition"
|
|
|
7010
6986
|
await client.deleteFunnel(slug, opts.projectId);
|
|
7011
6987
|
console.log(source_default.green(`Funnel "${slug}" deleted.`));
|
|
7012
6988
|
});
|
|
7013
|
-
funnelsCommand.command("query <slug>").description("Query funnel analytics").requiredOption("--project-id <id>", "Project ID").option("--since <date>", "Start
|
|
6989
|
+
funnelsCommand.command("query <slug>").description("Query funnel analytics").requiredOption("--project-id <id>", "Project ID").option("--since <date>", "Start time (e.g. 1h, 30m, 7d, or ISO 8601)").option("--until <date>", "End time (e.g. 1h, 30m, 7d, or ISO 8601)").option("--open", "Make this an open funnel. In an open funnel, users don't have to complete a previous step in order to be included in a subsequent step.").option("--app-version <version>", "Filter by app version").option("--environment <env>", "Filter by environment (ios, ipados, macos, android, web, backend)").option("--experiment <name:variant>", "Filter by experiment (format: name:variant)").option("--group-by <field>", "Group by: environment, app_version, or experiment:<name>").addOption(
|
|
7014
6990
|
new Option("--data-mode <mode>", "Data mode: production, development, or all").choices(["production", "development", "all"]).default("production")
|
|
7015
6991
|
).action(async (slug, opts, cmd) => {
|
|
7016
6992
|
const { client, globals } = createClient(cmd);
|
|
@@ -7036,15 +7012,13 @@ auditLogCommand.command("list").description("List audit log entries").requiredOp
|
|
|
7036
7012
|
new Option("--limit <n>", "Max entries to return").argParser((v) => parsePositiveInt(v, "--limit"))
|
|
7037
7013
|
).option("--cursor <cursor>", "Pagination cursor").action(async (opts, cmd) => {
|
|
7038
7014
|
const { client, globals } = createClient(cmd);
|
|
7039
|
-
const since = opts.since ? parseTimeInput(opts.since) : void 0;
|
|
7040
|
-
const until = opts.until ? parseTimeInput(opts.until) : void 0;
|
|
7041
7015
|
const result = await client.queryAuditLogs(opts.teamId, {
|
|
7042
7016
|
resource_type: opts.resourceType,
|
|
7043
7017
|
resource_id: opts.resourceId,
|
|
7044
7018
|
actor_id: opts.actorId,
|
|
7045
7019
|
action: opts.action,
|
|
7046
|
-
since,
|
|
7047
|
-
until,
|
|
7020
|
+
since: opts.since,
|
|
7021
|
+
until: opts.until,
|
|
7048
7022
|
cursor: opts.cursor,
|
|
7049
7023
|
limit: opts.limit
|
|
7050
7024
|
});
|
|
@@ -7198,7 +7172,7 @@ var switchCommand = new Command("switch").description("Switch active team profil
|
|
|
7198
7172
|
});
|
|
7199
7173
|
|
|
7200
7174
|
// src/index.ts
|
|
7201
|
-
var program2 = new Command().name("owlmetry").version("0.1.
|
|
7175
|
+
var program2 = new Command().name("owlmetry").version("0.1.13").description("OwlMetry CLI \u2014 query metrics and manage your apps from the terminal").addOption(
|
|
7202
7176
|
new Option("--format <format>", "Output format").choices(["table", "json", "log"]).default("table")
|
|
7203
7177
|
).option("--endpoint <url>", "OwlMetry API server URL").option("--api-key <key>", "API key").option("--ingest-endpoint <url>", "OwlMetry ingest endpoint URL (for SDKs; defaults to API endpoint for self-hosted)").option("--team <name-or-id>", "Use a specific team profile for this command");
|
|
7204
7178
|
program2.addCommand(authCommand);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: owlmetry-cli
|
|
3
|
-
version: 0.1.
|
|
3
|
+
version: 0.1.13
|
|
4
4
|
description: >-
|
|
5
5
|
Install the OwlMetry CLI, sign up, and manage projects, apps, metrics,
|
|
6
6
|
funnels, and events. Use when adding OwlMetry to a project, querying
|
|
@@ -106,6 +106,15 @@ Use the `client_key` from Step 3 to configure the appropriate SDK:
|
|
|
106
106
|
|
|
107
107
|
Pass the **ingest endpoint** and client key to the SDK's `configure()` call. Read `~/.owlmetry/config.json` for the `ingest_endpoint` value (set during auth). For the hosted platform it's `https://ingest.owlmetry.com`. For self-hosted it defaults to the API endpoint.
|
|
108
108
|
|
|
109
|
+
### Step 5 — Add to project's CLAUDE.md
|
|
110
|
+
|
|
111
|
+
Add this to the project's `CLAUDE.md` so future sessions know OwlMetry is integrated and load the right skills:
|
|
112
|
+
|
|
113
|
+
```markdown
|
|
114
|
+
### OwlMetry
|
|
115
|
+
Load the `/owlmetry-cli` skill before running any `owlmetry` CLI commands or doing analytics work — it links to the appropriate SDK skill for your platform.
|
|
116
|
+
```
|
|
117
|
+
|
|
109
118
|
## Resource Hierarchy
|
|
110
119
|
|
|
111
120
|
OwlMetry organises resources in a `Team → Project → Apps` hierarchy:
|
|
@@ -155,7 +164,7 @@ owlmetry metrics create --project-id <id> --name <name> --slug <slug> [--lifecyc
|
|
|
155
164
|
owlmetry metrics update <slug> --project-id <id> [--name <name>] [--status active|paused] --format json
|
|
156
165
|
owlmetry metrics delete <slug> --project-id <id>
|
|
157
166
|
owlmetry metrics events <slug> --project-id <id> [--phase <phase>] [--user-id <id>] [--since <time>] [--until <time>] --format json
|
|
158
|
-
owlmetry metrics query <slug> --project-id <id> [--since <
|
|
167
|
+
owlmetry metrics query <slug> --project-id <id> [--since <time>] [--until <time>] [--app-id <id>] [--user-id <id>] [--group-by <field>] --format json
|
|
159
168
|
|
|
160
169
|
# Funnels
|
|
161
170
|
owlmetry funnels list --project-id <id> --format json
|
|
@@ -163,7 +172,7 @@ owlmetry funnels view <slug> --project-id <id> --format json
|
|
|
163
172
|
owlmetry funnels create --project-id <id> --name <name> --slug <slug> --steps-file <path> [--description <desc>] --format json
|
|
164
173
|
owlmetry funnels update <slug> --project-id <id> --steps-file <path> --format json
|
|
165
174
|
owlmetry funnels delete <slug> --project-id <id>
|
|
166
|
-
owlmetry funnels query <slug> --project-id <id> [--since <
|
|
175
|
+
owlmetry funnels query <slug> --project-id <id> [--since <time>] [--until <time>] [--open] [--group-by <field>] --format json
|
|
167
176
|
|
|
168
177
|
# Events
|
|
169
178
|
owlmetry events [--project-id <id>] [--app-id <id>] [--level <level>] [--user-id <id>] [--session-id <id>] [--since <time>] [--limit <n>] --format json
|
|
@@ -227,9 +236,9 @@ Slugs: lowercase letters, numbers, hyphens only (`/^[a-z0-9-]+$/`).
|
|
|
227
236
|
|
|
228
237
|
### Funnel Definitions
|
|
229
238
|
|
|
230
|
-
Funnels measure how users progress through a multi-step flow and where they drop off. Each funnel has an ordered list of steps, and each step has an `event_filter` that matches
|
|
239
|
+
Funnels measure how users progress through a multi-step flow and where they drop off. Each funnel has an ordered list of steps, and each step has an `event_filter` that matches on `step_name` and/or `screen_name`.
|
|
231
240
|
|
|
232
|
-
|
|
241
|
+
Step definitions match directly on the step name passed to `track()` in the SDK — no prefix or transformation needed.
|
|
233
242
|
|
|
234
243
|
Funnels support two analysis modes:
|
|
235
244
|
- **Closed mode** (default): sequential — a user must complete steps in order (step 2 only counts if step 1 was completed first). Use for linear flows like onboarding or checkout.
|
|
@@ -249,8 +258,8 @@ owlmetry funnels delete <slug> --project-id <id>
|
|
|
249
258
|
# 1. Write steps to a JSON file
|
|
250
259
|
cat > /tmp/funnel-steps.json << 'EOF'
|
|
251
260
|
[
|
|
252
|
-
{"name": "Step Name", "event_filter": {"
|
|
253
|
-
{"name": "Next Step", "event_filter": {"
|
|
261
|
+
{"name": "Step Name", "event_filter": {"step_name": "step-name"}},
|
|
262
|
+
{"name": "Next Step", "event_filter": {"step_name": "next-step"}}
|
|
254
263
|
]
|
|
255
264
|
EOF
|
|
256
265
|
|
|
@@ -266,7 +275,7 @@ owlmetry funnels update <slug> --project-id <id> --steps-file /tmp/updated-steps
|
|
|
266
275
|
|
|
267
276
|
Inline `--steps '<json>'` also works but is error-prone in shell environments due to JSON quoting. Prefer `--steps-file`.
|
|
268
277
|
|
|
269
|
-
Steps JSON format: `[{"name":"Step Name","event_filter":{"
|
|
278
|
+
Steps JSON format: `[{"name":"Step Name","event_filter":{"step_name":"step-name"}}]`
|
|
270
279
|
|
|
271
280
|
## Querying
|
|
272
281
|
|
|
@@ -308,7 +317,7 @@ There are two ways to look at metric data:
|
|
|
308
317
|
|
|
309
318
|
```bash
|
|
310
319
|
owlmetry metrics events <slug> --project-id <id> [--phase start|complete|fail|cancel|record] [--tracking-id <id>] [--user-id <id>] [--since <time>] [--until <time>] [--environment <env>] [--data-mode <mode>] --format json
|
|
311
|
-
owlmetry metrics query <slug> --project-id <id> [--since <
|
|
320
|
+
owlmetry metrics query <slug> --project-id <id> [--since <time>] [--until <time>] [--app-id <id>] [--app-version <v>] [--environment <env>] [--user-id <id>] [--group-by app_id|app_version|device_model|os_version|environment|time:hour|time:day|time:week] [--data-mode <mode>] --format json
|
|
312
321
|
```
|
|
313
322
|
|
|
314
323
|
### Funnel Analytics
|
|
@@ -316,7 +325,7 @@ owlmetry metrics query <slug> --project-id <id> [--since <date>] [--until <date>
|
|
|
316
325
|
Funnel queries return conversion rates and drop-off between steps. The output shows how many users entered each step and what percentage continued to the next. Use `--group-by` to segment results and compare conversion across environments, app versions, or A/B experiment variants.
|
|
317
326
|
|
|
318
327
|
```bash
|
|
319
|
-
owlmetry funnels query <slug> --project-id <id> [--since <
|
|
328
|
+
owlmetry funnels query <slug> --project-id <id> [--since <time>] [--until <time>] [--open] [--app-version <v>] [--environment <env>] [--experiment <name:variant>] [--group-by environment|app_version|experiment:<name>] [--data-mode <mode>] --format json
|
|
320
329
|
```
|
|
321
330
|
|
|
322
331
|
`--open` = open funnel mode (steps evaluated independently, not sequentially).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: owlmetry-node
|
|
3
|
-
version: 0.1.
|
|
3
|
+
version: 0.1.13
|
|
4
4
|
description: >-
|
|
5
5
|
Integrate the OwlMetry Node.js SDK into a backend service for server-side
|
|
6
6
|
analytics, event tracking, metrics, funnels, and A/B experiments. Use when
|
|
@@ -175,7 +175,7 @@ const owl = Owl.withUser(userId);
|
|
|
175
175
|
owl.track('checkout-completed', { item_count: '3' });
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
The step name you pass to `track()` must match the `step_name` in the funnel definition's `event_filter`. For example, if the step filter is `{"step_name": "signup-started"}`, then call `Owl.track('signup-started')`. Define matching funnels via `/owlmetry-cli`.
|
|
179
179
|
|
|
180
180
|
**Note:** `track()` attributes must be `Record<string, string>` (string values only).
|
|
181
181
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: owlmetry-swift
|
|
3
|
-
version: 0.1.
|
|
3
|
+
version: 0.1.13
|
|
4
4
|
description: >-
|
|
5
5
|
Integrate the OwlMetry Swift SDK into an iOS or macOS app for analytics,
|
|
6
6
|
event tracking, metrics, funnels, and A/B experiments. Use when
|
|
@@ -256,10 +256,17 @@ Owl.clearUser(newAnonymousId: true)
|
|
|
256
256
|
Funnels measure how users progress through a multi-step flow (onboarding, checkout, activation) and where they drop off. The system has three parts:
|
|
257
257
|
|
|
258
258
|
1. **Define** the funnel server-side (via CLI or API) with ordered steps and event filters.
|
|
259
|
-
2. **Track** steps client-side with `Owl.track("step-name")
|
|
259
|
+
2. **Track** steps client-side with `Owl.track("step-name")`.
|
|
260
260
|
3. **Query** analytics to see conversion rates and drop-off between steps.
|
|
261
261
|
|
|
262
|
-
|
|
262
|
+
The step name you pass to `Owl.track()` must match the `step_name` in the funnel definition's `event_filter`. For example, if the step filter is `{"step_name": "welcome-screen"}`, then call `Owl.track("welcome-screen")`.
|
|
263
|
+
|
|
264
|
+
**Funnel design rules:**
|
|
265
|
+
- Each step must be a point that **every user in the funnel passes through** on the way to the goal. If a step is conditional (e.g., paywall only shown to free users), it breaks the chain — users who skip it show as 0% conversion from that point.
|
|
266
|
+
- Keep funnels focused on **one flow**. Don't combine "import a model" + "explore features" into one funnel — those are separate journeys with separate goals.
|
|
267
|
+
- **Optional interactions are not steps.** Toggling a setting, viewing info, or using a tool are engagement events (log with `Owl.info()`), not funnel progression. A funnel step should represent the user moving closer to the goal.
|
|
268
|
+
- Split alternative paths into **separate funnels**. If users can take a screenshot OR record a video, create two funnels — don't put both paths in one.
|
|
269
|
+
- Aim for **3-6 steps** per funnel. Too few = no drop-off insight. Too many = noise.
|
|
263
270
|
|
|
264
271
|
Use `attributes` when you need to segment funnel analytics later (e.g., by signup method or referral source).
|
|
265
272
|
|
|
@@ -270,15 +277,15 @@ Owl.track("complete-profile")
|
|
|
270
277
|
Owl.track("first-post")
|
|
271
278
|
```
|
|
272
279
|
|
|
273
|
-
|
|
280
|
+
Define matching funnel definitions via `/owlmetry-cli`:
|
|
274
281
|
```bash
|
|
275
282
|
# Write steps to a JSON file (avoids shell quoting issues)
|
|
276
283
|
cat > /tmp/funnel-steps.json << 'EOF'
|
|
277
284
|
[
|
|
278
|
-
{"name": "Welcome", "event_filter": {"
|
|
279
|
-
{"name": "Account", "event_filter": {"
|
|
280
|
-
{"name": "Profile", "event_filter": {"
|
|
281
|
-
{"name": "First Post", "event_filter": {"
|
|
285
|
+
{"name": "Welcome", "event_filter": {"step_name": "welcome-screen"}},
|
|
286
|
+
{"name": "Account", "event_filter": {"step_name": "create-account"}},
|
|
287
|
+
{"name": "Profile", "event_filter": {"step_name": "complete-profile"}},
|
|
288
|
+
{"name": "First Post", "event_filter": {"step_name": "first-post"}}
|
|
282
289
|
]
|
|
283
290
|
EOF
|
|
284
291
|
|
|
@@ -388,13 +395,27 @@ Owl.clearExperiments()
|
|
|
388
395
|
- All events automatically include an `experiments` field with current assignments.
|
|
389
396
|
- Query funnel analytics segmented by variant via CLI: `owlmetry funnels query <slug> --project <id> --group-by experiment:checkout-redesign`
|
|
390
397
|
|
|
398
|
+
## What the SDK Tracks Automatically
|
|
399
|
+
|
|
400
|
+
Do not re-implement any of these — they are built into the SDK and emitted without any code:
|
|
401
|
+
|
|
402
|
+
- **`sdk:configured`** — emitted on `Owl.configure()`
|
|
403
|
+
- **`sdk:backgrounded`** / **`sdk:foregrounded`** — app state transitions
|
|
404
|
+
- **`sdk:shutdown`** — on `Owl.shutdown()`
|
|
405
|
+
- **`session_id`** — fresh UUID per `configure()` call, included on every event
|
|
406
|
+
- **`_launch_time_ms`** — app launch time, included in the `session_started` event
|
|
407
|
+
- **`_connection`** — network type (wifi, cellular, etc.), included on every event
|
|
408
|
+
- **Device model, OS version, locale** — included on every event
|
|
409
|
+
- **`is_dev`** — automatically `true` in DEBUG builds
|
|
410
|
+
|
|
411
|
+
You do NOT need to manually track app launch, app foreground/background, session start, network type, or device info. These are already covered.
|
|
412
|
+
|
|
391
413
|
## Instrumentation Strategy
|
|
392
414
|
|
|
393
415
|
When instrumenting a new app, follow this priority:
|
|
394
416
|
|
|
395
417
|
**Always instrument (events — no CLI setup needed):**
|
|
396
418
|
- Screen views (`.owlScreen("ScreenName")` on every distinct screen)
|
|
397
|
-
- App launch / cold start (`info` in `init()` or `didFinishLaunching`)
|
|
398
419
|
- Authentication events (login, logout, signup)
|
|
399
420
|
- Caught exceptions (`error` in `catch` blocks, error handlers)
|
|
400
421
|
- Validation failures and pre-checks (`warn` for bad input, missing optional data, fallback paths)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmetry/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "OwlMetry CLI — manage projects, apps, metrics, funnels, and events from the terminal. Includes AI skill files for agent-assisted development.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|