@rotifer/playground 0.22.1 → 0.23.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.
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.telemetryCommand = void 0;
37
+ const commander_1 = require("commander");
38
+ const display = __importStar(require("../utils/display.js"));
39
+ const palette_js_1 = require("../utils/palette.js");
40
+ const config_js_1 = require("../telemetry/config.js");
41
+ function describeDecision(d) {
42
+ switch (d) {
43
+ case "off-env":
44
+ return "off — DO_NOT_TRACK or ROTIFER_TELEMETRY in this shell";
45
+ case "on-env":
46
+ return "on — ROTIFER_TELEMETRY in this shell";
47
+ case "off-stored":
48
+ return "off — your stored choice (rotifer telemetry off)";
49
+ case "on-stored":
50
+ return "on — your stored choice (rotifer telemetry on)";
51
+ case "on-default":
52
+ return "on — default (ADR-329); nobody has chosen otherwise yet";
53
+ }
54
+ }
55
+ exports.telemetryCommand = new commander_1.Command("telemetry")
56
+ .description("Show or change the anonymous usage heartbeat")
57
+ .action(() => {
58
+ // `rotifer telemetry` with no subcommand — same shape as `codegraph
59
+ // telemetry` with no argument, which this project measured its
60
+ // telemetry design against (ADR-329). Aliases `status`.
61
+ reportStatus();
62
+ })
63
+ .addCommand(new commander_1.Command("status")
64
+ .description("Show the current heartbeat state and why")
65
+ .action(() => reportStatus()))
66
+ .addCommand(new commander_1.Command("on")
67
+ .description("Turn the anonymous heartbeat on")
68
+ .action(() => {
69
+ const config = (0, config_js_1.setHeartbeatEnabled)(true);
70
+ display.success("Anonymous usage heartbeat: on");
71
+ display.kv("Machine ID", config.machine_id);
72
+ display.hint("No code, no identity — just \"this machine ran something today\".");
73
+ }))
74
+ .addCommand(new commander_1.Command("off")
75
+ .description("Turn the anonymous heartbeat off")
76
+ .action(() => {
77
+ (0, config_js_1.setHeartbeatEnabled)(false);
78
+ display.success("Anonymous usage heartbeat: off");
79
+ display.hint("Nothing is sent — not even an opted-out notice.");
80
+ }));
81
+ function reportStatus() {
82
+ const config = (0, config_js_1.loadOrInitHeartbeatConfig)();
83
+ const decision = (0, config_js_1.resolveHeartbeatDecision)(config);
84
+ const isEnabled = (0, config_js_1.heartbeatDecisionEnabled)(decision);
85
+ display.header("Telemetry");
86
+ display.kv("Anonymous heartbeat", isEnabled ? palette_js_1.c.success("on") : palette_js_1.c.muted("off"));
87
+ display.kv("Reason", describeDecision(decision));
88
+ display.kv("Machine ID", config.machine_id);
89
+ console.log();
90
+ display.hint("Details: https://rotifer.dev/telemetry");
91
+ display.hint("`rotifer telemetry off` / ROTIFER_TELEMETRY=0 / DO_NOT_TRACK=1 all disable it.");
92
+ }
93
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/commands/telemetry.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yCAAoC;AACpC,6DAA+C;AAC/C,oDAAwC;AACxC,sDAMgC;AAEhC,SAAS,gBAAgB,CAAC,CAAoB;IAC5C,QAAQ,CAAC,EAAE,CAAC;QACV,KAAK,SAAS;YACZ,OAAO,uDAAuD,CAAC;QACjE,KAAK,QAAQ;YACX,OAAO,sCAAsC,CAAC;QAChD,KAAK,YAAY;YACf,OAAO,kDAAkD,CAAC;QAC5D,KAAK,WAAW;YACd,OAAO,gDAAgD,CAAC;QAC1D,KAAK,YAAY;YACf,OAAO,yDAAyD,CAAC;IACrE,CAAC;AACH,CAAC;AAEY,QAAA,gBAAgB,GAAG,IAAI,mBAAO,CAAC,WAAW,CAAC;KACrD,WAAW,CAAC,8CAA8C,CAAC;KAC3D,MAAM,CAAC,GAAG,EAAE;IACX,oEAAoE;IACpE,+DAA+D;IAC/D,wDAAwD;IACxD,YAAY,EAAE,CAAC;AACjB,CAAC,CAAC;KACD,UAAU,CACT,IAAI,mBAAO,CAAC,QAAQ,CAAC;KAClB,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAChC;KACA,UAAU,CACT,IAAI,mBAAO,CAAC,IAAI,CAAC;KACd,WAAW,CAAC,iCAAiC,CAAC;KAC9C,MAAM,CAAC,GAAG,EAAE;IACX,MAAM,MAAM,GAAG,IAAA,+BAAmB,EAAC,IAAI,CAAC,CAAC;IACzC,OAAO,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5C,OAAO,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;AACpF,CAAC,CAAC,CACL;KACA,UAAU,CACT,IAAI,mBAAO,CAAC,KAAK,CAAC;KACf,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,GAAG,EAAE;IACX,IAAA,+BAAmB,EAAC,KAAK,CAAC,CAAC;IAC3B,OAAO,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;AAClE,CAAC,CAAC,CACL,CAAC;AAEJ,SAAS,YAAY;IACnB,MAAM,MAAM,GAAG,IAAA,qCAAyB,GAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAA,oCAAwB,EAAC,MAAM,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAA,oCAAwB,EAAC,QAAQ,CAAC,CAAC;IAErD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAAC,CAAC,cAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,cAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAChF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAC;AACjG,CAAC"}
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ const whoami_js_1 = require("./commands/whoami.js");
33
33
  const stats_js_1 = require("./commands/stats.js");
34
34
  const compare_js_1 = require("./commands/compare.js");
35
35
  const network_js_1 = require("./commands/network.js");
36
+ const telemetry_js_1 = require("./commands/telemetry.js");
36
37
  const vg_js_1 = require("./commands/vg.js");
37
38
  const hello_js_1 = require("./commands/hello.js");
38
39
  const self_update_js_1 = require("./commands/self-update.js");
@@ -100,6 +101,7 @@ agent.addCommand(agent_list_js_1.agentListCommand);
100
101
  agent.addCommand(agent_run_js_1.agentRunCommand);
101
102
  program.addCommand(hello_js_1.helloCommand);
102
103
  program.addCommand(network_js_1.networkCommand);
104
+ program.addCommand(telemetry_js_1.telemetryCommand);
103
105
  program.addCommand(vg_js_1.vgCommand);
104
106
  program.addCommand(self_update_js_1.selfUpdateCommand);
105
107
  program.addCommand(user_config_js_1.userConfigCommand);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ export type ConsentSource = "installer" | "cli" | "default-notice";
2
+ export interface HeartbeatConfig {
3
+ /** The user's stored choice. Irrelevant when an env var overrides it. */
4
+ enabled: boolean;
5
+ /** Random UUIDv4, minted once. Never derived from hardware, paths, or identity. */
6
+ machine_id: string;
7
+ consent_source: ConsentSource;
8
+ /** Gates the one-line notice — see maybeAnnounceFirstRun below. */
9
+ first_run_notice_shown: boolean;
10
+ updated_at: string;
11
+ }
12
+ /**
13
+ * Reads the stored config, minting one (with a fresh machine_id) on first
14
+ * ever call. This is the read path every reporting call goes through — it
15
+ * is cheap (one small JSON file) and idempotent, so there is no reason to
16
+ * cache it across calls within a process; a concurrent `rotifer telemetry
17
+ * off` in another terminal should be picked up by the next report, not
18
+ * shadowed by a stale in-memory copy.
19
+ */
20
+ export declare function loadOrInitHeartbeatConfig(): HeartbeatConfig;
21
+ /** Backs `rotifer telemetry on|off`. Keeps the existing machine_id. */
22
+ export declare function setHeartbeatEnabled(isEnabled: boolean): HeartbeatConfig;
23
+ export declare function resetHeartbeatIdentity(): void;
24
+ export type HeartbeatDecision = "off-env" | "on-env" | "off-stored" | "on-stored" | "on-default";
25
+ /**
26
+ * Resolution order, mirrored in TELEMETRY.md and kept in sync deliberately:
27
+ * DO_NOT_TRACK / ROTIFER_TELEMETRY (env, either direction) > stored choice
28
+ * > default on.
29
+ *
30
+ * The heartbeat's default is the opposite of gene_invocation_log's
31
+ * (ADR-316 D1 default-off) on purpose — see the migration header on
32
+ * usage_heartbeat for why: this table carries no per-row accountability to
33
+ * protect, and default-off here would just reproduce the blind spot
34
+ * ADR-329 exists to close.
35
+ */
36
+ export declare function resolveHeartbeatDecision(config: HeartbeatConfig, env?: NodeJS.ProcessEnv): HeartbeatDecision;
37
+ export declare function heartbeatDecisionEnabled(d: HeartbeatDecision): boolean;
38
+ /**
39
+ * Marks the first-run notice as shown and persists it — separated from
40
+ * printing the notice itself (in heartbeat.ts) so the persistence, which
41
+ * must happen exactly once and survive even if the network call that
42
+ * follows fails, is not tangled up with I/O to stderr.
43
+ */
44
+ export declare function markFirstRunNoticeShown(config: HeartbeatConfig): void;
45
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/telemetry/config.ts"],"names":[],"mappings":"AA8BA,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,KAAK,GAAG,gBAAgB,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,OAAO,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,aAAa,CAAC;IAC9B,mEAAmE;IACnE,sBAAsB,EAAE,OAAO,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAmCD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,IAAI,eAAe,CAa3D;AAED,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,OAAO,GAAG,eAAe,CAavE;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAQ7C;AAED,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,QAAQ,GACR,YAAY,GACZ,WAAW,GACX,YAAY,CAAC;AAEjB;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,iBAAiB,CAKnB;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAEtE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAGrE"}
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadOrInitHeartbeatConfig = loadOrInitHeartbeatConfig;
4
+ exports.setHeartbeatEnabled = setHeartbeatEnabled;
5
+ exports.resetHeartbeatIdentity = resetHeartbeatIdentity;
6
+ exports.resolveHeartbeatDecision = resolveHeartbeatDecision;
7
+ exports.heartbeatDecisionEnabled = heartbeatDecisionEnabled;
8
+ exports.markFirstRunNoticeShown = markFirstRunNoticeShown;
9
+ /**
10
+ * Storage and consent state for the anonymous usage heartbeat (ADR-329).
11
+ *
12
+ * Lives in ~/.rotifer/telemetry.json, the same directory (and the same
13
+ * private-mode convention — see private-fs.ts) as credentials.json and
14
+ * cloud.json. Deliberately the same shape as codegraph's
15
+ * ~/.codegraph/telemetry.json (ADR-329's Context section names it as the
16
+ * design this is measured against): `enabled`, `machine_id`,
17
+ * `consent_source`, `first_run_notice_shown`, `updated_at`.
18
+ *
19
+ * This file is shared, in practice, with rotifer-mcp-server: both processes
20
+ * read and write ~/.rotifer/telemetry.json on the same machine, so a
21
+ * machine_id minted by one is picked up by the other rather than each
22
+ * inventing its own. mcp-server carries its own copy of this module (no
23
+ * cross-package import — they are separate npm packages) but the on-disk
24
+ * shape must stay identical, or one process's write would look like
25
+ * corruption to the other's reader.
26
+ */
27
+ const node_fs_1 = require("node:fs");
28
+ const node_path_1 = require("node:path");
29
+ const node_crypto_1 = require("node:crypto");
30
+ const private_fs_js_1 = require("../utils/private-fs.js");
31
+ const consent_js_1 = require("./consent.js");
32
+ const ROTIFER_HOME = (0, node_path_1.join)(process.env.HOME || process.env.USERPROFILE || "/tmp", ".rotifer");
33
+ const TELEMETRY_CONFIG_FILE = "telemetry.json";
34
+ function telemetryConfigPath() {
35
+ return (0, node_path_1.join)(ROTIFER_HOME, TELEMETRY_CONFIG_FILE);
36
+ }
37
+ function readStoredConfig() {
38
+ const p = telemetryConfigPath();
39
+ if (!(0, node_fs_1.existsSync)(p))
40
+ return null;
41
+ try {
42
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(p, "utf-8"));
43
+ if (typeof parsed.machine_id !== "string" || !parsed.machine_id)
44
+ return null;
45
+ return {
46
+ enabled: parsed.enabled !== false,
47
+ machine_id: parsed.machine_id,
48
+ consent_source: parsed.consent_source ?? "default-notice",
49
+ first_run_notice_shown: parsed.first_run_notice_shown === true,
50
+ updated_at: parsed.updated_at ?? new Date(0).toISOString(),
51
+ };
52
+ }
53
+ catch {
54
+ // A corrupt file is treated the same as a missing one: a fresh
55
+ // machine_id is minted below. Losing continuity on a corrupt file is a
56
+ // acceptable one-time cost; refusing to run telemetry at all until a
57
+ // human fixes the file is not — this is opt-out telemetry, not a wallet.
58
+ return null;
59
+ }
60
+ }
61
+ function writeStoredConfig(config) {
62
+ (0, private_fs_js_1.ensurePrivateDir)(ROTIFER_HOME);
63
+ const p = telemetryConfigPath();
64
+ (0, node_fs_1.writeFileSync)(p, JSON.stringify(config, null, 2) + "\n", { mode: 0o600 });
65
+ (0, private_fs_js_1.tightenPrivateFile)(p);
66
+ }
67
+ /**
68
+ * Reads the stored config, minting one (with a fresh machine_id) on first
69
+ * ever call. This is the read path every reporting call goes through — it
70
+ * is cheap (one small JSON file) and idempotent, so there is no reason to
71
+ * cache it across calls within a process; a concurrent `rotifer telemetry
72
+ * off` in another terminal should be picked up by the next report, not
73
+ * shadowed by a stale in-memory copy.
74
+ */
75
+ function loadOrInitHeartbeatConfig() {
76
+ const existing = readStoredConfig();
77
+ if (existing)
78
+ return existing;
79
+ const fresh = {
80
+ enabled: true,
81
+ machine_id: (0, node_crypto_1.randomUUID)(),
82
+ consent_source: "default-notice",
83
+ first_run_notice_shown: false,
84
+ updated_at: new Date().toISOString(),
85
+ };
86
+ writeStoredConfig(fresh);
87
+ return fresh;
88
+ }
89
+ /** Backs `rotifer telemetry on|off`. Keeps the existing machine_id. */
90
+ function setHeartbeatEnabled(isEnabled) {
91
+ const current = loadOrInitHeartbeatConfig();
92
+ const updated = {
93
+ ...current,
94
+ enabled: isEnabled,
95
+ consent_source: "cli",
96
+ // Explicitly setting the choice via the CLI counts as having seen
97
+ // whatever notice there was to see — this must not print again.
98
+ first_run_notice_shown: true,
99
+ updated_at: new Date().toISOString(),
100
+ };
101
+ writeStoredConfig(updated);
102
+ return updated;
103
+ }
104
+ function resetHeartbeatIdentity() {
105
+ const p = telemetryConfigPath();
106
+ if ((0, node_fs_1.existsSync)(p)) {
107
+ (0, node_fs_1.writeFileSync)(p, "", { mode: 0o600 });
108
+ }
109
+ // Deleting would also work; overwriting with an empty file and letting the
110
+ // next loadOrInitHeartbeatConfig() call treat it as corrupt-and-remint is
111
+ // simpler than importing unlinkSync for a rarely-used reset path.
112
+ }
113
+ /**
114
+ * Resolution order, mirrored in TELEMETRY.md and kept in sync deliberately:
115
+ * DO_NOT_TRACK / ROTIFER_TELEMETRY (env, either direction) > stored choice
116
+ * > default on.
117
+ *
118
+ * The heartbeat's default is the opposite of gene_invocation_log's
119
+ * (ADR-316 D1 default-off) on purpose — see the migration header on
120
+ * usage_heartbeat for why: this table carries no per-row accountability to
121
+ * protect, and default-off here would just reproduce the blind spot
122
+ * ADR-329 exists to close.
123
+ */
124
+ function resolveHeartbeatDecision(config, env = process.env) {
125
+ if ((0, consent_js_1.telemetryOptedOutByEnv)(env))
126
+ return "off-env";
127
+ if ((0, consent_js_1.telemetryExplicitlyOnByEnv)(env))
128
+ return "on-env";
129
+ if (!config.enabled)
130
+ return "off-stored";
131
+ return config.consent_source === "default-notice" ? "on-default" : "on-stored";
132
+ }
133
+ function heartbeatDecisionEnabled(d) {
134
+ return d === "on-env" || d === "on-stored" || d === "on-default";
135
+ }
136
+ /**
137
+ * Marks the first-run notice as shown and persists it — separated from
138
+ * printing the notice itself (in heartbeat.ts) so the persistence, which
139
+ * must happen exactly once and survive even if the network call that
140
+ * follows fails, is not tangled up with I/O to stderr.
141
+ */
142
+ function markFirstRunNoticeShown(config) {
143
+ if (config.first_run_notice_shown)
144
+ return;
145
+ writeStoredConfig({ ...config, first_run_notice_shown: true, updated_at: new Date().toISOString() });
146
+ }
147
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/telemetry/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The one environment-variable check both telemetry paths share.
3
+ *
4
+ * ADR-329's decision is explicit: "ROTIFER_TELEMETRY=0 同时关闭匿名信号与
5
+ * 登录上报——「关掉」意味着全部,与 316 的语义一致." Before this module
6
+ * existed, `ROTIFER_TELEMETRY` was checked in exactly one place
7
+ * (cloud/invocation.ts, for the signed-in Gene invocation report). Adding
8
+ * the anonymous heartbeat with its own copy of that check would have been
9
+ * the easy path and the wrong one: two copies of "is telemetry off" drift
10
+ * the moment either one changes, and the failure mode is silent — a user
11
+ * who set ROTIFER_TELEMETRY=0 expecting it to mean everything would keep
12
+ * being counted by whichever path didn't get updated.
13
+ *
14
+ * DO_NOT_TRACK is the cross-tool convention (https://consoledonottrack.com/)
15
+ * and is new here — ADR-316 predates it. It outranks ROTIFER_TELEMETRY
16
+ * because it is a stance the user took before ever hearing of this project.
17
+ */
18
+ export declare function telemetryOptedOutByEnv(env?: NodeJS.ProcessEnv): boolean;
19
+ /**
20
+ * True when the environment explicitly asked for telemetry (as opposed to
21
+ * "unset, so whatever the default is"). Distinguishing "explicitly on" from
22
+ * "unset" matters for the heartbeat: an explicit ROTIFER_TELEMETRY=1 should
23
+ * win even over a stored "disabled" choice, the same way `codegraph
24
+ * TELEMETRY=1` does — a per-shell override should not require first running
25
+ * a separate command to change stored state.
26
+ */
27
+ export declare function telemetryExplicitlyOnByEnv(env?: NodeJS.ProcessEnv): boolean;
28
+ //# sourceMappingURL=consent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../../src/telemetry/consent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAMpF;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAIxF"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.telemetryOptedOutByEnv = telemetryOptedOutByEnv;
4
+ exports.telemetryExplicitlyOnByEnv = telemetryExplicitlyOnByEnv;
5
+ /**
6
+ * The one environment-variable check both telemetry paths share.
7
+ *
8
+ * ADR-329's decision is explicit: "ROTIFER_TELEMETRY=0 同时关闭匿名信号与
9
+ * 登录上报——「关掉」意味着全部,与 316 的语义一致." Before this module
10
+ * existed, `ROTIFER_TELEMETRY` was checked in exactly one place
11
+ * (cloud/invocation.ts, for the signed-in Gene invocation report). Adding
12
+ * the anonymous heartbeat with its own copy of that check would have been
13
+ * the easy path and the wrong one: two copies of "is telemetry off" drift
14
+ * the moment either one changes, and the failure mode is silent — a user
15
+ * who set ROTIFER_TELEMETRY=0 expecting it to mean everything would keep
16
+ * being counted by whichever path didn't get updated.
17
+ *
18
+ * DO_NOT_TRACK is the cross-tool convention (https://consoledonottrack.com/)
19
+ * and is new here — ADR-316 predates it. It outranks ROTIFER_TELEMETRY
20
+ * because it is a stance the user took before ever hearing of this project.
21
+ */
22
+ function telemetryOptedOutByEnv(env = process.env) {
23
+ const dnt = (env.DO_NOT_TRACK || "").trim().toLowerCase();
24
+ if (dnt !== "" && dnt !== "0" && dnt !== "false")
25
+ return true;
26
+ const flag = (env.ROTIFER_TELEMETRY || "").trim().toLowerCase();
27
+ return flag === "0" || flag === "false" || flag === "off";
28
+ }
29
+ /**
30
+ * True when the environment explicitly asked for telemetry (as opposed to
31
+ * "unset, so whatever the default is"). Distinguishing "explicitly on" from
32
+ * "unset" matters for the heartbeat: an explicit ROTIFER_TELEMETRY=1 should
33
+ * win even over a stored "disabled" choice, the same way `codegraph
34
+ * TELEMETRY=1` does — a per-shell override should not require first running
35
+ * a separate command to change stored state.
36
+ */
37
+ function telemetryExplicitlyOnByEnv(env = process.env) {
38
+ if (telemetryOptedOutByEnv(env))
39
+ return false;
40
+ const flag = (env.ROTIFER_TELEMETRY || "").trim().toLowerCase();
41
+ return flag !== "" && flag !== "0" && flag !== "false" && flag !== "off";
42
+ }
43
+ //# sourceMappingURL=consent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent.js","sourceRoot":"","sources":["../../src/telemetry/consent.ts"],"names":[],"mappings":";;AAiBA,wDAMC;AAUD,gEAIC;AArCD;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,sBAAsB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACzE,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1D,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAE9D,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAChE,OAAO,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,KAAK,CAAC;AAC5D,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,0BAA0B,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7E,IAAI,sBAAsB,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9C,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAChE,OAAO,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,KAAK,CAAC;AAC3E,CAAC"}
@@ -0,0 +1,20 @@
1
+ /** Longest a caller will wait for a heartbeat to settle before exiting anyway. */
2
+ export declare const FLUSH_TIMEOUT_MS = 2000;
3
+ /**
4
+ * Wait for any in-flight heartbeat report to settle. Call this before
5
+ * `process.exit()` — and before returning from a command that is about to let
6
+ * the process exit on its own, since that path turned out not to be safe
7
+ * either (see this file's top comment). A run must never hang on telemetry,
8
+ * so it gives up after timeoutMs and resolves regardless.
9
+ */
10
+ export declare function flushHeartbeat(timeoutMs?: number): Promise<void>;
11
+ /**
12
+ * Reports one Gene invocation's worth of activity for this machine, today,
13
+ * on the given channel. Fire-and-forget; every failure mode is silence,
14
+ * same contract as recordGeneInvocation. Safe to call unconditionally from
15
+ * every call site that already calls recordGeneInvocation — this function
16
+ * does its own consent and test-run checks. The request it sends is tracked
17
+ * in `inFlight` until it settles — see flushHeartbeat.
18
+ */
19
+ export declare function recordHeartbeat(): void;
20
+ //# sourceMappingURL=heartbeat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../src/telemetry/heartbeat.ts"],"names":[],"mappings":"AA0EA,kFAAkF;AAClF,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAErC;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,SAAS,GAAE,MAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CASxF;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAkFtC"}
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FLUSH_TIMEOUT_MS = void 0;
4
+ exports.flushHeartbeat = flushHeartbeat;
5
+ exports.recordHeartbeat = recordHeartbeat;
6
+ /**
7
+ * Anonymous usage heartbeat (ADR-329).
8
+ *
9
+ * Answers a narrower question than gene_invocation_log: not "who called
10
+ * what", just "did this machine run something today, and through which
11
+ * channel". No identity, on by default, and — unlike the invocation report
12
+ * — it costs nothing to lose one. It is not §33.4 input; a dropped
13
+ * heartbeat is not a hole in an audited ledger, it is one machine's "active
14
+ * today" signal that will show up again tomorrow if the machine is still in
15
+ * use.
16
+ *
17
+ * This file used to not track in-flight requests at all, on the theory that
18
+ * "Node drains the pending request before the event loop empties" (the same
19
+ * assumption cloud/invocation.ts's success path relies on) made it
20
+ * unnecessary here. A real end-to-end run against production — `rotifer run`
21
+ * on a freshly-provisioned machine, 2026-08-30 — showed that assumption does
22
+ * not hold for this fetch: the CLI printed the first-run notice (proof the
23
+ * request was sent) and exited 0, and the row never arrived. A manual POST
24
+ * with the same body against the same machine_id landed immediately, which
25
+ * rules out the RPC, the grant, and the endpoint — the only thing different
26
+ * was that the CLI process existed for a few hundred more milliseconds. So
27
+ * this now tracks in-flight requests the same way cloud/invocation.ts does,
28
+ * and every call site that can exit soon after calling recordHeartbeat()
29
+ * must await flushHeartbeat() first, exactly like flushInvocationReports().
30
+ */
31
+ const node_fs_1 = require("node:fs");
32
+ const node_path_1 = require("node:path");
33
+ const client_js_1 = require("../cloud/client.js");
34
+ const invocation_js_1 = require("../cloud/invocation.js");
35
+ const config_js_1 = require("./config.js");
36
+ // __dirname is CommonJS's own global here (see tsconfig's "module": "NodeNext"
37
+ // targeting CJS output) — no fileURLToPath(import.meta.url) needed, and that
38
+ // ESM-only syntax would fail to compile in this build target anyway.
39
+ let cachedVersion = null;
40
+ function packageVersion() {
41
+ if (cachedVersion !== null)
42
+ return cachedVersion;
43
+ try {
44
+ const pkg = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, "..", "..", "package.json"), "utf-8"));
45
+ cachedVersion = typeof pkg.version === "string" ? pkg.version : null;
46
+ }
47
+ catch {
48
+ cachedVersion = null;
49
+ }
50
+ return cachedVersion;
51
+ }
52
+ /**
53
+ * The one-line disclosure, printed to stderr exactly once, before the first
54
+ * heartbeat this machine ever actually sends — never before, so a machine
55
+ * whose heartbeat is off (env or stored choice) never sees a notice about
56
+ * data that is never leaving it. Mirrors codegraph's wording pattern
57
+ * (ADR-329 measured its design against codegraph's, verified against its
58
+ * compiled output) but says MCP explicitly, because stderr is where CLI
59
+ * users look and exactly where MCP hosts do not — the MCP side of this
60
+ * (rotifer-mcp-server) carries the notice in a tool response instead, for
61
+ * that reason.
62
+ */
63
+ function printFirstRunNotice() {
64
+ process.stderr.write("[rotifer] Anonymous usage heartbeat is on by default — no code, no identity, just " +
65
+ "\"this machine ran something today\". `rotifer telemetry off`, ROTIFER_TELEMETRY=0, " +
66
+ "or DO_NOT_TRACK=1 disables it. Details: https://rotifer.dev/telemetry\n");
67
+ }
68
+ /** Heartbeat reports still in flight. Emptied as each settles; see flushHeartbeat. */
69
+ const inFlight = new Set();
70
+ /** Longest a caller will wait for a heartbeat to settle before exiting anyway. */
71
+ exports.FLUSH_TIMEOUT_MS = 2000;
72
+ /**
73
+ * Wait for any in-flight heartbeat report to settle. Call this before
74
+ * `process.exit()` — and before returning from a command that is about to let
75
+ * the process exit on its own, since that path turned out not to be safe
76
+ * either (see this file's top comment). A run must never hang on telemetry,
77
+ * so it gives up after timeoutMs and resolves regardless.
78
+ */
79
+ async function flushHeartbeat(timeoutMs = exports.FLUSH_TIMEOUT_MS) {
80
+ if (inFlight.size === 0)
81
+ return;
82
+ let timer;
83
+ const deadline = new Promise((resolve) => {
84
+ timer = setTimeout(resolve, timeoutMs);
85
+ timer.unref?.();
86
+ });
87
+ await Promise.race([Promise.allSettled([...inFlight]).then(() => undefined), deadline]);
88
+ if (timer)
89
+ clearTimeout(timer);
90
+ }
91
+ /**
92
+ * Reports one Gene invocation's worth of activity for this machine, today,
93
+ * on the given channel. Fire-and-forget; every failure mode is silence,
94
+ * same contract as recordGeneInvocation. Safe to call unconditionally from
95
+ * every call site that already calls recordGeneInvocation — this function
96
+ * does its own consent and test-run checks. The request it sends is tracked
97
+ * in `inFlight` until it settles — see flushHeartbeat.
98
+ */
99
+ function recordHeartbeat() {
100
+ // The whole body is one try/catch, deliberately wider than the network
101
+ // call. loadOrInitHeartbeatConfig()/markFirstRunNoticeShown() write to
102
+ // ~/.rotifer/telemetry.json — config.ts does not swallow that failure
103
+ // (rotifer telemetry on/off should surface a write error to the user who
104
+ // ran it), but a Gene execution silently failing because this
105
+ // fire-and-forget signal couldn't touch the filesystem would be a much
106
+ // worse trade. Every failure mode here is silence, same contract as the
107
+ // network call below.
108
+ try {
109
+ if ((0, invocation_js_1.runningUnderTest)())
110
+ return;
111
+ const channel = (0, invocation_js_1.resolveInvocationChannel)();
112
+ if (channel === null)
113
+ return; // unattributable declared channel — see resolveInvocationChannel
114
+ const config = (0, config_js_1.loadOrInitHeartbeatConfig)();
115
+ const decision = (0, config_js_1.resolveHeartbeatDecision)(config);
116
+ if (!(0, config_js_1.heartbeatDecisionEnabled)(decision))
117
+ return;
118
+ // Only reached once we know a report is actually about to leave the
119
+ // process — see printFirstRunNotice's doc comment for why the ordering
120
+ // matters. Persisted synchronously so a crash in the fetch below can
121
+ // never cause the notice to reprint on the next run.
122
+ if (!config.first_run_notice_shown) {
123
+ printFirstRunNotice();
124
+ (0, config_js_1.markFirstRunNoticeShown)(config);
125
+ }
126
+ const cloudConfig = (0, client_js_1.loadCloudConfig)();
127
+ const url = `${cloudConfig.endpoint.replace(/\/+$/, "")}/rest/v1/rpc/record_heartbeat`;
128
+ // flushHeartbeat() giving up after FLUSH_TIMEOUT_MS only stops the
129
+ // *caller* from waiting — it does not by itself end this fetch. A
130
+ // request that never gets a response (the fake-timeout regression test
131
+ // in tests/e2e/telemetry-heartbeat-delivery.test.ts exercises exactly
132
+ // this) leaves its socket open as an active handle, and Node does not
133
+ // exit while one exists — so without this abort, a stalled telemetry
134
+ // endpoint would hang every `rotifer run` for however long the OS's own
135
+ // TCP timeout takes, which is far worse than the bug this file was
136
+ // rewritten to fix. Aborting on the same deadline is what actually lets
137
+ // the process exit on schedule instead of merely stopping user code
138
+ // from waiting on it.
139
+ const controller = new AbortController();
140
+ const abortTimer = setTimeout(() => controller.abort(), exports.FLUSH_TIMEOUT_MS);
141
+ abortTimer.unref?.();
142
+ // No Authorization header: record_heartbeat is anon-callable by design
143
+ // (migration 20260830010000) — that grant is the entire point of ADR-329.
144
+ // Sending credentials here would be pointless (the RPC does not use them)
145
+ // and would defeat the "no identity" promise for a user who happens to be
146
+ // signed in but has not opted into the signed-in invocation report.
147
+ const settled = fetch(url, {
148
+ method: "POST",
149
+ headers: { "Content-Type": "application/json", apikey: cloudConfig.anonKey },
150
+ body: JSON.stringify({
151
+ p_machine_id: config.machine_id,
152
+ p_channel: channel,
153
+ p_client_version: packageVersion(),
154
+ p_invocation_delta: 1,
155
+ }),
156
+ signal: controller.signal,
157
+ })
158
+ .then((res) => {
159
+ if (!res.ok && process.env.ROTIFER_DEBUG) {
160
+ process.stderr.write(`[rotifer] record_heartbeat failed (${res.status})\n`);
161
+ }
162
+ })
163
+ .catch((err) => {
164
+ if (process.env.ROTIFER_DEBUG) {
165
+ process.stderr.write(`[rotifer] record_heartbeat error: ${err?.message ?? err}\n`);
166
+ }
167
+ })
168
+ .finally(() => {
169
+ clearTimeout(abortTimer);
170
+ inFlight.delete(settled);
171
+ });
172
+ inFlight.add(settled);
173
+ }
174
+ catch (err) {
175
+ if (process.env.ROTIFER_DEBUG) {
176
+ process.stderr.write(`[rotifer] record_heartbeat setup error: ${err?.message ?? err}\n`);
177
+ }
178
+ }
179
+ }
180
+ //# sourceMappingURL=heartbeat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../../src/telemetry/heartbeat.ts"],"names":[],"mappings":"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"}