@rotifer/playground 0.22.0 → 0.23.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 (45) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +1 -1
  3. package/dist/cloud/client.d.ts +1 -6
  4. package/dist/cloud/client.d.ts.map +1 -1
  5. package/dist/cloud/client.js +0 -37
  6. package/dist/cloud/client.js.map +1 -1
  7. package/dist/cloud/invocation.d.ts +29 -0
  8. package/dist/cloud/invocation.d.ts.map +1 -1
  9. package/dist/cloud/invocation.js +58 -7
  10. package/dist/cloud/invocation.js.map +1 -1
  11. package/dist/cloud/types.d.ts +0 -5
  12. package/dist/cloud/types.d.ts.map +1 -1
  13. package/dist/cloud/types.js.map +1 -1
  14. package/dist/commands/arena-watch.d.ts.map +1 -1
  15. package/dist/commands/arena-watch.js +43 -26
  16. package/dist/commands/arena-watch.js.map +1 -1
  17. package/dist/commands/run.d.ts.map +1 -1
  18. package/dist/commands/run.js +7 -0
  19. package/dist/commands/run.js.map +1 -1
  20. package/dist/commands/telemetry.d.ts +3 -0
  21. package/dist/commands/telemetry.d.ts.map +1 -0
  22. package/dist/commands/telemetry.js +93 -0
  23. package/dist/commands/telemetry.js.map +1 -0
  24. package/dist/index.js +2 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/telemetry/config.d.ts +45 -0
  27. package/dist/telemetry/config.d.ts.map +1 -0
  28. package/dist/telemetry/config.js +147 -0
  29. package/dist/telemetry/config.js.map +1 -0
  30. package/dist/telemetry/consent.d.ts +28 -0
  31. package/dist/telemetry/consent.d.ts.map +1 -0
  32. package/dist/telemetry/consent.js +43 -0
  33. package/dist/telemetry/consent.js.map +1 -0
  34. package/dist/telemetry/heartbeat.d.ts +9 -0
  35. package/dist/telemetry/heartbeat.d.ts.map +1 -0
  36. package/dist/telemetry/heartbeat.js +122 -0
  37. package/dist/telemetry/heartbeat.js.map +1 -0
  38. package/dist/utils/leaderboard-watch.d.ts +44 -0
  39. package/dist/utils/leaderboard-watch.d.ts.map +1 -0
  40. package/dist/utils/leaderboard-watch.js +73 -0
  41. package/dist/utils/leaderboard-watch.js.map +1 -0
  42. package/dist/utils/run-logger.d.ts.map +1 -1
  43. package/dist/utils/run-logger.js +12 -0
  44. package/dist/utils/run-logger.js.map +1 -1
  45. package/package.json +5 -5
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.recordHeartbeat = recordHeartbeat;
4
+ /**
5
+ * Anonymous usage heartbeat (ADR-329).
6
+ *
7
+ * Answers a narrower question than gene_invocation_log: not "who called
8
+ * what", just "did this machine run something today, and through which
9
+ * channel". No identity, on by default, and — unlike the invocation report
10
+ * — it costs nothing to lose one. It is not §33.4 input; a dropped
11
+ * heartbeat is not a hole in an audited ledger, it is one machine's "active
12
+ * today" signal that will show up again tomorrow if the machine is still in
13
+ * use. That is why this file, unlike cloud/invocation.ts, does not track
14
+ * in-flight requests for a caller to await before process.exit() — the
15
+ * reliability engineering that report needs would be pure overhead here.
16
+ */
17
+ const node_fs_1 = require("node:fs");
18
+ const node_path_1 = require("node:path");
19
+ const client_js_1 = require("../cloud/client.js");
20
+ const invocation_js_1 = require("../cloud/invocation.js");
21
+ const config_js_1 = require("./config.js");
22
+ // __dirname is CommonJS's own global here (see tsconfig's "module": "NodeNext"
23
+ // targeting CJS output) — no fileURLToPath(import.meta.url) needed, and that
24
+ // ESM-only syntax would fail to compile in this build target anyway.
25
+ let cachedVersion = null;
26
+ function packageVersion() {
27
+ if (cachedVersion !== null)
28
+ return cachedVersion;
29
+ try {
30
+ const pkg = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, "..", "..", "package.json"), "utf-8"));
31
+ cachedVersion = typeof pkg.version === "string" ? pkg.version : null;
32
+ }
33
+ catch {
34
+ cachedVersion = null;
35
+ }
36
+ return cachedVersion;
37
+ }
38
+ /**
39
+ * The one-line disclosure, printed to stderr exactly once, before the first
40
+ * heartbeat this machine ever actually sends — never before, so a machine
41
+ * whose heartbeat is off (env or stored choice) never sees a notice about
42
+ * data that is never leaving it. Mirrors codegraph's wording pattern
43
+ * (ADR-329 measured its design against codegraph's, verified against its
44
+ * compiled output) but says MCP explicitly, because stderr is where CLI
45
+ * users look and exactly where MCP hosts do not — the MCP side of this
46
+ * (rotifer-mcp-server) carries the notice in a tool response instead, for
47
+ * that reason.
48
+ */
49
+ function printFirstRunNotice() {
50
+ process.stderr.write("[rotifer] Anonymous usage heartbeat is on by default — no code, no identity, just " +
51
+ "\"this machine ran something today\". `rotifer telemetry off`, ROTIFER_TELEMETRY=0, " +
52
+ "or DO_NOT_TRACK=1 disables it. Details: https://rotifer.dev/telemetry\n");
53
+ }
54
+ /**
55
+ * Reports one Gene invocation's worth of activity for this machine, today,
56
+ * on the given channel. Fire-and-forget; every failure mode is silence,
57
+ * same contract as recordGeneInvocation. Safe to call unconditionally from
58
+ * every call site that already calls recordGeneInvocation — this function
59
+ * does its own consent and test-run checks.
60
+ */
61
+ function recordHeartbeat() {
62
+ // The whole body is one try/catch, deliberately wider than the network
63
+ // call. loadOrInitHeartbeatConfig()/markFirstRunNoticeShown() write to
64
+ // ~/.rotifer/telemetry.json — config.ts does not swallow that failure
65
+ // (rotifer telemetry on/off should surface a write error to the user who
66
+ // ran it), but a Gene execution silently failing because this
67
+ // fire-and-forget signal couldn't touch the filesystem would be a much
68
+ // worse trade. Every failure mode here is silence, same contract as the
69
+ // network call below.
70
+ try {
71
+ if ((0, invocation_js_1.runningUnderTest)())
72
+ return;
73
+ const channel = (0, invocation_js_1.resolveInvocationChannel)();
74
+ if (channel === null)
75
+ return; // unattributable declared channel — see resolveInvocationChannel
76
+ const config = (0, config_js_1.loadOrInitHeartbeatConfig)();
77
+ const decision = (0, config_js_1.resolveHeartbeatDecision)(config);
78
+ if (!(0, config_js_1.heartbeatDecisionEnabled)(decision))
79
+ return;
80
+ // Only reached once we know a report is actually about to leave the
81
+ // process — see printFirstRunNotice's doc comment for why the ordering
82
+ // matters. Persisted synchronously so a crash in the fetch below can
83
+ // never cause the notice to reprint on the next run.
84
+ if (!config.first_run_notice_shown) {
85
+ printFirstRunNotice();
86
+ (0, config_js_1.markFirstRunNoticeShown)(config);
87
+ }
88
+ const cloudConfig = (0, client_js_1.loadCloudConfig)();
89
+ const url = `${cloudConfig.endpoint.replace(/\/+$/, "")}/rest/v1/rpc/record_heartbeat`;
90
+ // No Authorization header: record_heartbeat is anon-callable by design
91
+ // (migration 20260830010000) — that grant is the entire point of ADR-329.
92
+ // Sending credentials here would be pointless (the RPC does not use them)
93
+ // and would defeat the "no identity" promise for a user who happens to be
94
+ // signed in but has not opted into the signed-in invocation report.
95
+ fetch(url, {
96
+ method: "POST",
97
+ headers: { "Content-Type": "application/json", apikey: cloudConfig.anonKey },
98
+ body: JSON.stringify({
99
+ p_machine_id: config.machine_id,
100
+ p_channel: channel,
101
+ p_client_version: packageVersion(),
102
+ p_invocation_delta: 1,
103
+ }),
104
+ })
105
+ .then((res) => {
106
+ if (!res.ok && process.env.ROTIFER_DEBUG) {
107
+ process.stderr.write(`[rotifer] record_heartbeat failed (${res.status})\n`);
108
+ }
109
+ })
110
+ .catch((err) => {
111
+ if (process.env.ROTIFER_DEBUG) {
112
+ process.stderr.write(`[rotifer] record_heartbeat error: ${err?.message ?? err}\n`);
113
+ }
114
+ });
115
+ }
116
+ catch (err) {
117
+ if (process.env.ROTIFER_DEBUG) {
118
+ process.stderr.write(`[rotifer] record_heartbeat setup error: ${err?.message ?? err}\n`);
119
+ }
120
+ }
121
+ }
122
+ //# sourceMappingURL=heartbeat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../../src/telemetry/heartbeat.ts"],"names":[],"mappings":";;AAkEA,0CA6DC;AA/HD;;;;;;;;;;;;GAYG;AACH,qCAAuC;AACvC,yCAAiC;AACjC,kDAAqD;AACrD,0DAAoF;AACpF,2CAMqB;AAErB,+EAA+E;AAC/E,6EAA6E;AAC7E,qEAAqE;AACrE,IAAI,aAAa,GAAkB,IAAI,CAAC;AACxC,SAAS,cAAc;IACrB,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,aAAa,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAA,gBAAI,EAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QAC3F,aAAa,GAAG,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,mBAAmB;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,oFAAoF;QAClF,sFAAsF;QACtF,yEAAyE,CAC5E,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,eAAe;IAC7B,uEAAuE;IACvE,uEAAuE;IACvE,sEAAsE;IACtE,yEAAyE;IACzE,8DAA8D;IAC9D,uEAAuE;IACvE,wEAAwE;IACxE,sBAAsB;IACtB,IAAI,CAAC;QACH,IAAI,IAAA,gCAAgB,GAAE;YAAE,OAAO;QAE/B,MAAM,OAAO,GAAG,IAAA,wCAAwB,GAAE,CAAC;QAC3C,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,CAAC,iEAAiE;QAE/F,MAAM,MAAM,GAAoB,IAAA,qCAAyB,GAAE,CAAC;QAC5D,MAAM,QAAQ,GAAG,IAAA,oCAAwB,EAAC,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,IAAA,oCAAwB,EAAC,QAAQ,CAAC;YAAE,OAAO;QAEhD,oEAAoE;QACpE,uEAAuE;QACvE,qEAAqE;QACrE,qDAAqD;QACrD,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,CAAC;YACnC,mBAAmB,EAAE,CAAC;YACtB,IAAA,mCAAuB,EAAC,MAAM,CAAC,CAAC;QAClC,CAAC;QAED,MAAM,WAAW,GAAG,IAAA,2BAAe,GAAE,CAAC;QACtC,MAAM,GAAG,GAAG,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,+BAA+B,CAAC;QAEvF,uEAAuE;QACvE,0EAA0E;QAC1E,0EAA0E;QAC1E,0EAA0E;QAC1E,oEAAoE;QACpE,KAAK,CAAC,GAAG,EAAE;YACT,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,EAAE;YAC5E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,YAAY,EAAE,MAAM,CAAC,UAAU;gBAC/B,SAAS,EAAE,OAAO;gBAClB,gBAAgB,EAAE,cAAc,EAAE;gBAClC,kBAAkB,EAAE,CAAC;aACtB,CAAC;SACH,CAAC;aACC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACZ,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACtB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qCAAsC,GAAa,EAAE,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC;YAChG,CAAC;QACH,CAAC,CAAC,CAAC;IACP,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA4C,GAAa,EAAE,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC;QACtG,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { LeaderboardRow } from "../cloud/client.js";
2
+ /**
3
+ * Stable identity of a leaderboard row across polls. The board folds to one
4
+ * row per logical gene, so the logical name (owner + name) is the key — the
5
+ * shown version (and with it the gene_id) legitimately changes when an author
6
+ * publishes, and that must not read as a disappearance plus an arrival.
7
+ */
8
+ export declare function leaderboardKey(row: LeaderboardRow): string;
9
+ export type LeaderboardChange = {
10
+ kind: "new";
11
+ key: string;
12
+ row: LeaderboardRow;
13
+ } | {
14
+ kind: "tier";
15
+ key: string;
16
+ from: LeaderboardRow["tier"];
17
+ to: LeaderboardRow["tier"];
18
+ } | {
19
+ kind: "up" | "down";
20
+ key: string;
21
+ from: number;
22
+ to: number;
23
+ };
24
+ /**
25
+ * Diff two polls of the tiered leaderboard.
26
+ *
27
+ * Rank moves only exist inside a ranked tier: `tier_rank` is null for
28
+ * `not_evaluated` rows, and a null on either side is a tier story, not a rank
29
+ * story. A tier change is reported as such and suppresses the rank comparison
30
+ * for that row — "#3 → #1" across two different ladders compares nothing.
31
+ */
32
+ export declare function diffLeaderboard(prev: LeaderboardRow[], curr: LeaderboardRow[]): LeaderboardChange[];
33
+ /**
34
+ * What the score column may show for a row. A `not_evaluated` row never shows
35
+ * a number, even when the ledger stores one — printing a stored value next to
36
+ * the words "not evaluated" is how a hash-derived number got read as a
37
+ * measurement in the first place (ADR-319 D4 display decision).
38
+ */
39
+ export declare function fitnessCell(row: LeaderboardRow): string;
40
+ /** Same rule for V(g): no numbers on an unevaluated row. */
41
+ export declare function safetyCell(row: LeaderboardRow): string;
42
+ /** Position column: `not_evaluated` rows have no position, not position zero. */
43
+ export declare function rankCell(row: LeaderboardRow): string;
44
+ //# sourceMappingURL=leaderboard-watch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaderboard-watch.d.ts","sourceRoot":"","sources":["../../src/utils/leaderboard-watch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAE1D;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,cAAc,CAAA;CAAE,GACjD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC7B,EAAE,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;CAC5B,GACD;IAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,cAAc,EAAE,EACtB,IAAI,EAAE,cAAc,EAAE,GACrB,iBAAiB,EAAE,CA8BrB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAGvD;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAGtD;AAED,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAEpD"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.leaderboardKey = leaderboardKey;
4
+ exports.diffLeaderboard = diffLeaderboard;
5
+ exports.fitnessCell = fitnessCell;
6
+ exports.safetyCell = safetyCell;
7
+ exports.rankCell = rankCell;
8
+ /**
9
+ * Stable identity of a leaderboard row across polls. The board folds to one
10
+ * row per logical gene, so the logical name (owner + name) is the key — the
11
+ * shown version (and with it the gene_id) legitimately changes when an author
12
+ * publishes, and that must not read as a disappearance plus an arrival.
13
+ */
14
+ function leaderboardKey(row) {
15
+ return `${row.owner_username}/${row.gene_name}`;
16
+ }
17
+ /**
18
+ * Diff two polls of the tiered leaderboard.
19
+ *
20
+ * Rank moves only exist inside a ranked tier: `tier_rank` is null for
21
+ * `not_evaluated` rows, and a null on either side is a tier story, not a rank
22
+ * story. A tier change is reported as such and suppresses the rank comparison
23
+ * for that row — "#3 → #1" across two different ladders compares nothing.
24
+ */
25
+ function diffLeaderboard(prev, curr) {
26
+ const prevMap = new Map(prev.map((r) => [leaderboardKey(r), r]));
27
+ const changes = [];
28
+ for (const row of curr) {
29
+ const key = leaderboardKey(row);
30
+ const before = prevMap.get(key);
31
+ if (!before) {
32
+ changes.push({ kind: "new", key, row });
33
+ continue;
34
+ }
35
+ if (before.tier !== row.tier) {
36
+ changes.push({ kind: "tier", key, from: before.tier, to: row.tier });
37
+ continue;
38
+ }
39
+ if (before.tier_rank != null &&
40
+ row.tier_rank != null &&
41
+ before.tier_rank !== row.tier_rank) {
42
+ changes.push({
43
+ kind: row.tier_rank < before.tier_rank ? "up" : "down",
44
+ key,
45
+ from: before.tier_rank,
46
+ to: row.tier_rank,
47
+ });
48
+ }
49
+ }
50
+ return changes;
51
+ }
52
+ /**
53
+ * What the score column may show for a row. A `not_evaluated` row never shows
54
+ * a number, even when the ledger stores one — printing a stored value next to
55
+ * the words "not evaluated" is how a hash-derived number got read as a
56
+ * measurement in the first place (ADR-319 D4 display decision).
57
+ */
58
+ function fitnessCell(row) {
59
+ if (row.tier === "not_evaluated" || row.fitness_value == null)
60
+ return "—";
61
+ return row.fitness_value.toFixed(4);
62
+ }
63
+ /** Same rule for V(g): no numbers on an unevaluated row. */
64
+ function safetyCell(row) {
65
+ if (row.tier === "not_evaluated" || row.safety_score == null)
66
+ return "—";
67
+ return row.safety_score.toFixed(4);
68
+ }
69
+ /** Position column: `not_evaluated` rows have no position, not position zero. */
70
+ function rankCell(row) {
71
+ return row.tier_rank == null ? "—" : String(row.tier_rank);
72
+ }
73
+ //# sourceMappingURL=leaderboard-watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaderboard-watch.js","sourceRoot":"","sources":["../../src/utils/leaderboard-watch.ts"],"names":[],"mappings":";;AAQA,wCAEC;AAoBD,0CAiCC;AAQD,kCAGC;AAGD,gCAGC;AAGD,4BAEC;AAnFD;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,GAAmB;IAChD,OAAO,GAAG,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;AAClD,CAAC;AAYD;;;;;;;GAOG;AACH,SAAgB,eAAe,CAC7B,IAAsB,EACtB,IAAsB;IAEtB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,MAAM,OAAO,GAAwB,EAAE,CAAC;IAExC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YACxC,SAAS;QACX,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACrE,SAAS;QACX,CAAC;QACD,IACE,MAAM,CAAC,SAAS,IAAI,IAAI;YACxB,GAAG,CAAC,SAAS,IAAI,IAAI;YACrB,MAAM,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS,EAClC,CAAC;YACD,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;gBACtD,GAAG;gBACH,IAAI,EAAE,MAAM,CAAC,SAAS;gBACtB,EAAE,EAAE,GAAG,CAAC,SAAS;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,WAAW,CAAC,GAAmB;IAC7C,IAAI,GAAG,CAAC,IAAI,KAAK,eAAe,IAAI,GAAG,CAAC,aAAa,IAAI,IAAI;QAAE,OAAO,GAAG,CAAC;IAC1E,OAAO,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,4DAA4D;AAC5D,SAAgB,UAAU,CAAC,GAAmB;IAC5C,IAAI,GAAG,CAAC,IAAI,KAAK,eAAe,IAAI,GAAG,CAAC,YAAY,IAAI,IAAI;QAAE,OAAO,GAAG,CAAC;IACzE,OAAO,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,iFAAiF;AACjF,SAAgB,QAAQ,CAAC,GAAmB;IAC1C,OAAO,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC7D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-logger.d.ts","sourceRoot":"","sources":["../../src/utils/run-logger.ts"],"names":[],"mappings":"AASA,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAsC9D;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAiB3D"}
1
+ {"version":3,"file":"run-logger.d.ts","sourceRoot":"","sources":["../../src/utils/run-logger.ts"],"names":[],"mappings":"AAUA,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAkD9D;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAiB3D"}
@@ -8,9 +8,21 @@ const node_path_1 = require("node:path");
8
8
  const node_os_1 = require("node:os");
9
9
  const private_fs_js_1 = require("./private-fs.js");
10
10
  const invocation_js_1 = require("../cloud/invocation.js");
11
+ const heartbeat_js_1 = require("../telemetry/heartbeat.js");
11
12
  const MAX_LOG_SIZE = 10 * 1024 * 1024; // 10MB rotation
12
13
  const LOG_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".rotifer", "run-logs");
13
14
  function logGeneExecution(meta) {
15
+ // Unconditional — unlike the recordGeneInvocation call below this one,
16
+ // which only fires when meta.geneDir names a Cloud-installed Gene. The
17
+ // heartbeat (ADR-329) doesn't need a resolvable Cloud identity: "this
18
+ // machine ran something today" is true whether meta.geneDir is set,
19
+ // unset, or points at a local, never-published Gene. Gating it on the
20
+ // same condition as the identity-carrying report would silently drop the
21
+ // heartbeat for exactly the callers (locally-authored Genes, composed
22
+ // agents without one obvious geneDir) that most need the anonymous signal
23
+ // to be counted at all. No try/catch needed here — recordHeartbeat()
24
+ // guarantees it never throws.
25
+ (0, heartbeat_js_1.recordHeartbeat)();
14
26
  try {
15
27
  (0, private_fs_js_1.ensurePrivateDir)(LOG_DIR);
16
28
  const logFile = (0, node_path_1.join)(LOG_DIR, `${meta.geneName}.jsonl`);
@@ -1 +1 @@
1
- {"version":3,"file":"run-logger.js","sourceRoot":"","sources":["../../src/utils/run-logger.ts"],"names":[],"mappings":";;AA0BA,4CAsCC;AAED,8BAEC;AAaD,kCAiBC;AAlGD,qCAA2E;AAC3E,yCAAiC;AACjC,qCAAkC;AAClC,mDAAuE;AACvE,0DAA8D;AAE9D,MAAM,YAAY,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,gBAAgB;AACvD,MAAM,OAAO,GAAG,IAAA,gBAAI,EAAC,IAAA,iBAAO,GAAE,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAmBxD,SAAgB,gBAAgB,CAAC,IAAuB;IACtD,IAAI,CAAC;QACH,IAAA,gCAAgB,EAAC,OAAO,CAAC,CAAC;QAE1B,MAAM,OAAO,GAAG,IAAA,gBAAI,EAAC,OAAO,EAAE,GAAG,IAAI,CAAC,QAAQ,QAAQ,CAAC,CAAC;QAExD,IAAI,IAAA,oBAAU,EAAC,OAAO,CAAC,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,IAAA,kBAAQ,EAAC,OAAO,CAAC,CAAC;YAChC,IAAI,KAAK,CAAC,IAAI,GAAG,YAAY,EAAE,CAAC;gBAC9B,MAAM,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;gBACjC,IAAI,CAAC;oBAAC,IAAA,oBAAU,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAG;YACZ,MAAM,EAAE,IAAI,CAAC,QAAQ;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;YACvC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,SAAS;YAC9B,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,SAAS;SAC7C,CAAC;QAEF,IAAA,wBAAc,EAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACvE,IAAA,kCAAkB,EAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;IAC9C,CAAC;IAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,IAAA,oCAAoB,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,gDAAgD;QAClD,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAgB,SAAS;IACvB,OAAO,OAAO,CAAC;AACjB,CAAC;AAaD,SAAgB,WAAW,CAAC,QAAgB;IAC1C,MAAM,OAAO,GAAG,IAAA,gBAAI,EAAC,OAAO,EAAE,GAAG,QAAQ,QAAQ,CAAC,CAAC;IACnD,IAAI,CAAC,IAAA,oBAAU,EAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,IAAI,CAAC;QACH,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,OAAO;aACX,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aACrC,GAAG,CAAC,CAAC,IAAY,EAAE,EAAE;YACpB,IAAI,CAAC;gBAAC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,IAAI,CAAC;YAAC,CAAC;QACzD,CAAC,CAAC;aACD,MAAM,CAAC,OAAO,CAAkB,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"run-logger.js","sourceRoot":"","sources":["../../src/utils/run-logger.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rotifer/playground",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "Rotifer Protocol Playground — local development environment for gene development, Arena competition, and protocol simulation",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Rotifer Protocol Contributors",
@@ -87,10 +87,10 @@
87
87
  },
88
88
  "optionalDependencies": {
89
89
  "@rolldown/binding-linux-x64-gnu": "1.1.1",
90
- "@rotifer/playground-darwin-arm64": "0.22.0",
91
- "@rotifer/playground-darwin-x64": "0.22.0",
92
- "@rotifer/playground-linux-x64-gnu": "0.22.0",
93
- "@rotifer/playground-win32-x64-msvc": "0.22.0"
90
+ "@rotifer/playground-darwin-arm64": "0.23.0",
91
+ "@rotifer/playground-darwin-x64": "0.23.0",
92
+ "@rotifer/playground-linux-x64-gnu": "0.23.0",
93
+ "@rotifer/playground-win32-x64-msvc": "0.23.0"
94
94
  },
95
95
  "engines": {
96
96
  "node": ">=22.18.0"