libretto 0.6.25 → 0.6.26

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/README.md CHANGED
@@ -95,7 +95,7 @@ All Libretto state lives in a `.libretto/` directory at your project root. See t
95
95
 
96
96
  ## Telemetry
97
97
 
98
- Libretto records anonymous CLI telemetry to help understand CLI usage and help us prioritize improvements. Each resolved command can send only an install id, timestamp, command event name such as `libretto run`, and an error boolean. Libretto does not send command arguments, URLs, project paths, auth state, API keys, error messages or details, or user identity.
98
+ Libretto records anonymous CLI telemetry to help understand CLI usage and help us prioritize improvements. Each resolved command can send only an install id, timestamp, command event name such as `libretto run`, error boolean, package version, and build channel (`node_modules`, `source`, or `unknown`). Libretto does not send command arguments, URLs, project paths, auth state, API keys, error messages or details, or user identity.
99
99
 
100
100
  The install id is stored in the telemetry file at `~/.libretto/telemetry.json`. The implementation lives in [`src/cli/core/telemetry.ts`](src/cli/core/telemetry.ts).
101
101
 
@@ -93,7 +93,7 @@ All Libretto state lives in a `.libretto/` directory at your project root. See t
93
93
 
94
94
  ## Telemetry
95
95
 
96
- Libretto records anonymous CLI telemetry to help understand CLI usage and help us prioritize improvements. Each resolved command can send only an install id, timestamp, command event name such as `libretto run`, and an error boolean. Libretto does not send command arguments, URLs, project paths, auth state, API keys, error messages or details, or user identity.
96
+ Libretto records anonymous CLI telemetry to help understand CLI usage and help us prioritize improvements. Each resolved command can send only an install id, timestamp, command event name such as `libretto run`, error boolean, package version, and build channel (`node_modules`, `source`, or `unknown`). Libretto does not send command arguments, URLs, project paths, auth state, API keys, error messages or details, or user identity.
97
97
 
98
98
  The install id is stored in the telemetry file at `~/.libretto/telemetry.json`. The implementation lives in [`{{LIBRETTO_PATH_PREFIX}}src/cli/core/telemetry.ts`]({{LIBRETTO_PATH_PREFIX}}src/cli/core/telemetry.ts).
99
99
 
@@ -1,11 +1,38 @@
1
1
  import { randomUUID } from "node:crypto";
2
+ import { existsSync, readFileSync } from "node:fs";
2
3
  import { promises as fs } from "node:fs";
3
4
  import { homedir } from "node:os";
4
- import { join } from "node:path";
5
+ import { basename, dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
5
7
  import { resolveHostedApiUrl } from "./auth-fetch.js";
6
8
  const TELEMETRY_FILE_NAME = "telemetry.json";
7
9
  const TELEMETRY_ENDPOINT_PATH = "/v1/telemetry/recordCliEvent";
8
10
  const TELEMETRY_TIMEOUT_MS = 250;
11
+ function packageRoot() {
12
+ return join(dirname(fileURLToPath(import.meta.url)), "../../..");
13
+ }
14
+ function readPackageVersion() {
15
+ try {
16
+ const parsed = JSON.parse(
17
+ readFileSync(join(packageRoot(), "package.json"), "utf8")
18
+ );
19
+ return typeof parsed.version === "string" ? parsed.version : "unknown";
20
+ } catch {
21
+ return "unknown";
22
+ }
23
+ }
24
+ function resolveBuildChannel() {
25
+ const root = packageRoot();
26
+ const workspaceRoot = join(root, "../..");
27
+ if (basename(dirname(root)) === "packages" && existsSync(join(workspaceRoot, "pnpm-workspace.yaml"))) {
28
+ return "source";
29
+ }
30
+ const pathSegments = root.split(/[\\/]+/);
31
+ if (pathSegments.includes("node_modules")) return "node_modules";
32
+ return "unknown";
33
+ }
34
+ const packageVersion = readPackageVersion();
35
+ const buildChannel = resolveBuildChannel();
9
36
  function telemetryDir() {
10
37
  return join(homedir(), ".libretto");
11
38
  }
@@ -39,7 +66,7 @@ function writeTelemetryNotice() {
39
66
  if (!process.stderr.isTTY) return;
40
67
  process.stderr.write(
41
68
  [
42
- "Libretto collects anonymous CLI telemetry: install id, timestamp, command event, and error status only.",
69
+ "Libretto collects anonymous CLI telemetry: install id, timestamp, command event, error status, package version, and build channel only.",
43
70
  "Set LIBRETTO_TELEMETRY_DISABLED=1 or DO_NOT_TRACK=1 to disable it, or set enabled:false in ~/.libretto/telemetry.json."
44
71
  ].join(" ") + "\n"
45
72
  );
@@ -59,7 +86,9 @@ async function recordCliTelemetryEvent(command, error) {
59
86
  installId,
60
87
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
61
88
  event: `libretto ${command.path.join(" ")}`,
62
- error
89
+ error,
90
+ packageVersion,
91
+ buildChannel
63
92
  });
64
93
  }
65
94
  async function sendWithTimeout(payload) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libretto",
3
- "version": "0.6.25",
3
+ "version": "0.6.26",
4
4
  "description": "AI-powered browser automation library and CLI built on Playwright",
5
5
  "license": "MIT",
6
6
  "homepage": "https://libretto.sh",
@@ -4,7 +4,7 @@ description: "Browser automation CLI for building, maintaining, and running brow
4
4
  license: MIT
5
5
  metadata:
6
6
  author: saffron-health
7
- version: "0.6.25"
7
+ version: "0.6.26"
8
8
  ---
9
9
 
10
10
  ## How Libretto Works
@@ -4,7 +4,7 @@ description: "Read-only Libretto workflow for diagnosing live browser state with
4
4
  license: MIT
5
5
  metadata:
6
6
  author: saffron-health
7
- version: "0.6.25"
7
+ version: "0.6.26"
8
8
  ---
9
9
 
10
10
  ## How Libretto Read-Only Works
@@ -1,7 +1,9 @@
1
1
  import { randomUUID } from "node:crypto";
2
+ import { existsSync, readFileSync } from "node:fs";
2
3
  import { promises as fs } from "node:fs";
3
4
  import { homedir } from "node:os";
4
- import { join } from "node:path";
5
+ import { basename, dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
5
7
  import type { SimpleCLICommandMeta, SimpleCLIMiddleware } from "affordance";
6
8
  import { resolveHostedApiUrl } from "./auth-fetch.js";
7
9
 
@@ -9,6 +11,8 @@ const TELEMETRY_FILE_NAME = "telemetry.json";
9
11
  const TELEMETRY_ENDPOINT_PATH = "/v1/telemetry/recordCliEvent";
10
12
  const TELEMETRY_TIMEOUT_MS = 250;
11
13
 
14
+ type BuildChannel = "node_modules" | "source" | "unknown";
15
+
12
16
  type StoredTelemetryState = {
13
17
  installId?: string;
14
18
  enabled?: boolean;
@@ -19,8 +23,48 @@ type CliTelemetryPayload = {
19
23
  timestamp: string;
20
24
  event: string;
21
25
  error: boolean;
26
+ packageVersion: string;
27
+ buildChannel: BuildChannel;
28
+ };
29
+
30
+ type PackageJson = {
31
+ version?: unknown;
22
32
  };
23
33
 
34
+ function packageRoot(): string {
35
+ return join(dirname(fileURLToPath(import.meta.url)), "../../..");
36
+ }
37
+
38
+ function readPackageVersion(): string {
39
+ try {
40
+ const parsed = JSON.parse(
41
+ readFileSync(join(packageRoot(), "package.json"), "utf8"),
42
+ ) as PackageJson;
43
+ return typeof parsed.version === "string" ? parsed.version : "unknown";
44
+ } catch {
45
+ return "unknown";
46
+ }
47
+ }
48
+
49
+ function resolveBuildChannel(): BuildChannel {
50
+ const root = packageRoot();
51
+ const workspaceRoot = join(root, "../..");
52
+ if (
53
+ basename(dirname(root)) === "packages" &&
54
+ existsSync(join(workspaceRoot, "pnpm-workspace.yaml"))
55
+ ) {
56
+ return "source";
57
+ }
58
+
59
+ const pathSegments = root.split(/[\\/]+/);
60
+ if (pathSegments.includes("node_modules")) return "node_modules";
61
+
62
+ return "unknown";
63
+ }
64
+
65
+ const packageVersion = readPackageVersion();
66
+ const buildChannel = resolveBuildChannel();
67
+
24
68
  function telemetryDir(): string {
25
69
  return join(homedir(), ".libretto");
26
70
  }
@@ -65,7 +109,7 @@ function writeTelemetryNotice(): void {
65
109
  if (!process.stderr.isTTY) return;
66
110
  process.stderr.write(
67
111
  [
68
- "Libretto collects anonymous CLI telemetry: install id, timestamp, command event, and error status only.",
112
+ "Libretto collects anonymous CLI telemetry: install id, timestamp, command event, error status, package version, and build channel only.",
69
113
  "Set LIBRETTO_TELEMETRY_DISABLED=1 or DO_NOT_TRACK=1 to disable it, or set enabled:false in ~/.libretto/telemetry.json.",
70
114
  ].join(" ") + "\n",
71
115
  );
@@ -92,6 +136,8 @@ async function recordCliTelemetryEvent(
92
136
  timestamp: new Date().toISOString(),
93
137
  event: `libretto ${command.path.join(" ")}`,
94
138
  error,
139
+ packageVersion,
140
+ buildChannel,
95
141
  });
96
142
  }
97
143