@openagentsy/ledger 0.0.0-stage → 0.2.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.
Files changed (86) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +20 -2
  3. package/data/pricing/litellm.json +8882 -0
  4. package/data/pricing/models.dev.json +12151 -0
  5. package/data/pricing/openrouter.json +1017 -0
  6. package/dist/db.d.ts +44 -0
  7. package/dist/db.d.ts.map +1 -0
  8. package/dist/db.js +97 -0
  9. package/dist/db.js.map +1 -0
  10. package/dist/export.d.ts +71 -0
  11. package/dist/export.d.ts.map +1 -0
  12. package/dist/export.js +78 -0
  13. package/dist/export.js.map +1 -0
  14. package/dist/footprint.d.ts +24 -0
  15. package/dist/footprint.d.ts.map +1 -0
  16. package/dist/footprint.js +33 -0
  17. package/dist/footprint.js.map +1 -0
  18. package/dist/git.d.ts +44 -0
  19. package/dist/git.d.ts.map +1 -0
  20. package/dist/git.js +126 -0
  21. package/dist/git.js.map +1 -0
  22. package/dist/git.test.d.ts +2 -0
  23. package/dist/git.test.d.ts.map +1 -0
  24. package/dist/git.test.js +101 -0
  25. package/dist/git.test.js.map +1 -0
  26. package/dist/index.d.ts +19 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +19 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/ingest.d.ts +133 -0
  31. package/dist/ingest.d.ts.map +1 -0
  32. package/dist/ingest.js +324 -0
  33. package/dist/ingest.js.map +1 -0
  34. package/dist/ingest.test.d.ts +2 -0
  35. package/dist/ingest.test.d.ts.map +1 -0
  36. package/dist/ingest.test.js +245 -0
  37. package/dist/ingest.test.js.map +1 -0
  38. package/dist/outcomes.d.ts +81 -0
  39. package/dist/outcomes.d.ts.map +1 -0
  40. package/dist/outcomes.js +85 -0
  41. package/dist/outcomes.js.map +1 -0
  42. package/dist/outcomes.test.d.ts +2 -0
  43. package/dist/outcomes.test.d.ts.map +1 -0
  44. package/dist/outcomes.test.js +160 -0
  45. package/dist/outcomes.test.js.map +1 -0
  46. package/dist/policy.d.ts +48 -0
  47. package/dist/policy.d.ts.map +1 -0
  48. package/dist/policy.js +99 -0
  49. package/dist/policy.js.map +1 -0
  50. package/dist/policy.test.d.ts +2 -0
  51. package/dist/policy.test.d.ts.map +1 -0
  52. package/dist/policy.test.js +126 -0
  53. package/dist/policy.test.js.map +1 -0
  54. package/dist/pricing.d.ts +92 -0
  55. package/dist/pricing.d.ts.map +1 -0
  56. package/dist/pricing.js +341 -0
  57. package/dist/pricing.js.map +1 -0
  58. package/dist/pricing.test.d.ts +2 -0
  59. package/dist/pricing.test.d.ts.map +1 -0
  60. package/dist/pricing.test.js +167 -0
  61. package/dist/pricing.test.js.map +1 -0
  62. package/dist/query.d.ts +134 -0
  63. package/dist/query.d.ts.map +1 -0
  64. package/dist/query.js +247 -0
  65. package/dist/query.js.map +1 -0
  66. package/dist/query.test.d.ts +2 -0
  67. package/dist/query.test.d.ts.map +1 -0
  68. package/dist/query.test.js +242 -0
  69. package/dist/query.test.js.map +1 -0
  70. package/dist/schema.d.ts +33 -0
  71. package/dist/schema.d.ts.map +1 -0
  72. package/dist/schema.js +139 -0
  73. package/dist/schema.js.map +1 -0
  74. package/dist/schema.test.d.ts +2 -0
  75. package/dist/schema.test.d.ts.map +1 -0
  76. package/dist/schema.test.js +129 -0
  77. package/dist/schema.test.js.map +1 -0
  78. package/dist/waste.d.ts +116 -0
  79. package/dist/waste.d.ts.map +1 -0
  80. package/dist/waste.js +553 -0
  81. package/dist/waste.js.map +1 -0
  82. package/dist/waste.test.d.ts +2 -0
  83. package/dist/waste.test.d.ts.map +1 -0
  84. package/dist/waste.test.js +278 -0
  85. package/dist/waste.test.js.map +1 -0
  86. package/package.json +52 -4
package/dist/db.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { Database } from 'bun:sqlite';
2
+ /**
3
+ * The ledger's database wiring.
4
+ *
5
+ * bun:sqlite is the driver because the OpenCode plugin runtime is Bun: the
6
+ * adapter and the CLI read the same file the board writes, and a driver one
7
+ * runtime lacks breaks the other.
8
+ */
9
+ /** The state directory the ledger lives in (§6.1). */
10
+ export declare const STATE_DIR = ".openagentsy";
11
+ /** The database file, inside the state directory. */
12
+ export declare const LEDGER_FILE = "ledger.db";
13
+ /** How long SQLite waits for a lock before it reports the database busy. */
14
+ export declare const BUSY_TIMEOUT_MS = 250;
15
+ /** How many times a busy write is retried (REV3 §6.1). */
16
+ export declare const BUSY_RETRIES = 5;
17
+ /** The first backoff, doubled per attempt, capped at the last one. */
18
+ export declare const BUSY_BACKOFF_MS = 1;
19
+ export declare const BUSY_BACKOFF_MAX_MS = 64;
20
+ /** The path of the ledger at a root. */
21
+ export declare function ledgerPath(root: string): string;
22
+ /**
23
+ * Open the ledger at a root.
24
+ *
25
+ * The root is injected: the state root of §3.9 is resolved by the caller,
26
+ * so a worktree and its main repository share one ledger, and a test can
27
+ * point at a temporary directory.
28
+ */
29
+ export declare function openLedger(root: string): Database;
30
+ /** Close the ledger. */
31
+ export declare function closeLedger(db: Database): void;
32
+ /** Whether an error is the busy one. */
33
+ export declare function isBusyError(error: unknown): boolean;
34
+ /**
35
+ * Run a write, and try again while the database is busy.
36
+ *
37
+ * SQLite reports a locked database as SQLITE_BUSY; the worktree case is the
38
+ * common one, where a builder in a worktree and the Lead in the main
39
+ * repository write the same file. The retry is bounded: five attempts, with
40
+ * the wait doubling from a millisecond to a cap of sixty-four, so a write
41
+ * never hangs and a locked database is reported rather than waited out.
42
+ */
43
+ export declare function withBusyRetry<T>(operation: () => T, retries?: number): T;
44
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKtC;;;;;;GAMG;AAEH,sDAAsD;AACtD,eAAO,MAAM,SAAS,iBAAiB,CAAC;AACxC,qDAAqD;AACrD,eAAO,MAAM,WAAW,cAAc,CAAC;AACvC,4EAA4E;AAC5E,eAAO,MAAM,eAAe,MAAM,CAAC;AACnC,0DAA0D;AAC1D,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,sEAAsE;AACtE,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,wCAAwC;AACxC,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAYjD;AAED,wBAAwB;AACxB,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAE9C;AAeD,wCAAwC;AACxC,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOnD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,OAAO,SAAe,GAAG,CAAC,CAa9E"}
package/dist/db.js ADDED
@@ -0,0 +1,97 @@
1
+ import { Database } from 'bun:sqlite';
2
+ import { mkdirSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { applySchema } from './schema.js';
5
+ /**
6
+ * The ledger's database wiring.
7
+ *
8
+ * bun:sqlite is the driver because the OpenCode plugin runtime is Bun: the
9
+ * adapter and the CLI read the same file the board writes, and a driver one
10
+ * runtime lacks breaks the other.
11
+ */
12
+ /** The state directory the ledger lives in (§6.1). */
13
+ export const STATE_DIR = '.openagentsy';
14
+ /** The database file, inside the state directory. */
15
+ export const LEDGER_FILE = 'ledger.db';
16
+ /** How long SQLite waits for a lock before it reports the database busy. */
17
+ export const BUSY_TIMEOUT_MS = 250;
18
+ /** How many times a busy write is retried (REV3 §6.1). */
19
+ export const BUSY_RETRIES = 5;
20
+ /** The first backoff, doubled per attempt, capped at the last one. */
21
+ export const BUSY_BACKOFF_MS = 1;
22
+ export const BUSY_BACKOFF_MAX_MS = 64;
23
+ /** The path of the ledger at a root. */
24
+ export function ledgerPath(root) {
25
+ return join(root, STATE_DIR, LEDGER_FILE);
26
+ }
27
+ /**
28
+ * Open the ledger at a root.
29
+ *
30
+ * The root is injected: the state root of §3.9 is resolved by the caller,
31
+ * so a worktree and its main repository share one ledger, and a test can
32
+ * point at a temporary directory.
33
+ */
34
+ export function openLedger(root) {
35
+ const path = ledgerPath(root);
36
+ mkdirSync(dirname(path), { recursive: true });
37
+ const db = new Database(path, { create: true });
38
+ // WAL so a reader never blocks the writer, a short busy timeout so a
39
+ // blocked write fails fast, and a retry on top of that (REV3 §6.1).
40
+ db.exec('PRAGMA journal_mode = WAL');
41
+ db.exec('PRAGMA foreign_keys = ON');
42
+ db.exec('PRAGMA synchronous = NORMAL');
43
+ db.exec(`PRAGMA busy_timeout = ${BUSY_TIMEOUT_MS}`);
44
+ applySchema(db);
45
+ return db;
46
+ }
47
+ /** Close the ledger. */
48
+ export function closeLedger(db) {
49
+ db.close();
50
+ }
51
+ /** The flag the retry loop waits on. A shared buffer, so the wait is a wait. */
52
+ const WAKE = new Int32Array(new SharedArrayBuffer(4));
53
+ /**
54
+ * Sleep without spinning the CPU.
55
+ *
56
+ * `Atomics.wait` parks the thread until the timeout, which is what a backoff
57
+ * wants: the alternative is a loop that burns a core to wait for a lock.
58
+ */
59
+ function sleepSync(ms) {
60
+ Atomics.wait(WAKE, 0, 0, ms);
61
+ }
62
+ /** Whether an error is the busy one. */
63
+ export function isBusyError(error) {
64
+ if (typeof error !== 'object' || error === null)
65
+ return false;
66
+ const code = error.code;
67
+ if (typeof code === 'string' && code.startsWith('SQLITE_BUSY'))
68
+ return true;
69
+ const message = error instanceof Error ? error.message : String(error.message ?? '');
70
+ return message.includes('SQLITE_BUSY') || message.includes('database is locked');
71
+ }
72
+ /**
73
+ * Run a write, and try again while the database is busy.
74
+ *
75
+ * SQLite reports a locked database as SQLITE_BUSY; the worktree case is the
76
+ * common one, where a builder in a worktree and the Lead in the main
77
+ * repository write the same file. The retry is bounded: five attempts, with
78
+ * the wait doubling from a millisecond to a cap of sixty-four, so a write
79
+ * never hangs and a locked database is reported rather than waited out.
80
+ */
81
+ export function withBusyRetry(operation, retries = BUSY_RETRIES) {
82
+ let attempt = 0;
83
+ let delay = BUSY_BACKOFF_MS;
84
+ for (;;) {
85
+ try {
86
+ return operation();
87
+ }
88
+ catch (error) {
89
+ if (!isBusyError(error) || attempt >= retries)
90
+ throw error;
91
+ attempt += 1;
92
+ sleepSync(delay);
93
+ delay = Math.min(delay * 2, BUSY_BACKOFF_MAX_MS);
94
+ }
95
+ }
96
+ }
97
+ //# sourceMappingURL=db.js.map
package/dist/db.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { Database } from 'bun:sqlite';
2
+ /**
3
+ * The export (§6.6).
4
+ *
5
+ * Counters only. No prompt, no completion, no code, no message id and no
6
+ * session id: the export is a set of numbers with the names of a role and a
7
+ * task, so a person can read what the work cost without reading the work.
8
+ * Nothing is uploaded, and there is no leaderboard.
9
+ */
10
+ /** The version of the export shape. */
11
+ export declare const EXPORT_SCHEMA = "openagentsy.ledger/v1";
12
+ export type LedgerExport = {
13
+ schema: string;
14
+ generatedAt: string;
15
+ totals: {
16
+ messages: number;
17
+ tokens: number;
18
+ input: number;
19
+ output: number;
20
+ reasoning: number;
21
+ cacheRead: number;
22
+ cacheWrite: number;
23
+ usd: number | null;
24
+ unpricedMessages: number;
25
+ };
26
+ byRole: {
27
+ role: string;
28
+ messages: number;
29
+ tokens: number;
30
+ usd: number | null;
31
+ unpriced: number;
32
+ }[];
33
+ byTask: {
34
+ taskId: string;
35
+ messages: number;
36
+ tokens: number;
37
+ usd: number | null;
38
+ }[];
39
+ waste: {
40
+ tokens: number;
41
+ percentage: number;
42
+ };
43
+ outcomes: {
44
+ tasksCompleted: number;
45
+ tasksScrapped: number;
46
+ commits: number;
47
+ prsMerged: number;
48
+ };
49
+ /** The mean tokens of a completed task, when there is one. */
50
+ tokensPerCompletedTask: number | null;
51
+ offload: {
52
+ messages: number;
53
+ tokens: number;
54
+ usd: number | null;
55
+ };
56
+ };
57
+ export type ExportOptions = {
58
+ /** The clock, so a test can pin the stamp. */
59
+ generatedAt?: string;
60
+ };
61
+ /** The counters of the ledger, ready to be written as JSON. */
62
+ export declare function ledgerExport(db: Database, options?: ExportOptions): LedgerExport;
63
+ /**
64
+ * The export of a ledger with nothing in it.
65
+ *
66
+ * A project that has no ledger yet has nothing to show, and reading it
67
+ * should not create one, so the zeros come from a database that lives only
68
+ * for the length of the call.
69
+ */
70
+ export declare function emptyLedgerExport(generatedAt?: string): LedgerExport;
71
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAYtC;;;;;;;GAOG;AAEH,uCAAuC;AACvC,eAAO,MAAM,aAAa,0BAA0B,CAAC;AAErD,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;IACJ,MAAM,EAAE;QACN,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;KACpB,EAAE,CAAC;IACJ,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,QAAQ,EAAE;QACR,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,8DAA8D;IAC9D,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAE,aAAkB,GAAG,YAAY,CA+CpF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,YAAY,CAQpE"}
package/dist/export.js ADDED
@@ -0,0 +1,78 @@
1
+ import { Database } from 'bun:sqlite';
2
+ import { ledgerTotals, offloadRows, outcomeTotals, perRoleTotals, perTaskTotals, tokensPerCompletedTask, wasteTotals, } from './query.js';
3
+ import { applySchema } from './schema.js';
4
+ /**
5
+ * The export (§6.6).
6
+ *
7
+ * Counters only. No prompt, no completion, no code, no message id and no
8
+ * session id: the export is a set of numbers with the names of a role and a
9
+ * task, so a person can read what the work cost without reading the work.
10
+ * Nothing is uploaded, and there is no leaderboard.
11
+ */
12
+ /** The version of the export shape. */
13
+ export const EXPORT_SCHEMA = 'openagentsy.ledger/v1';
14
+ /** The counters of the ledger, ready to be written as JSON. */
15
+ export function ledgerExport(db, options = {}) {
16
+ const totals = ledgerTotals(db);
17
+ const roles = perRoleTotals(db);
18
+ const tasks = perTaskTotals(db);
19
+ const waste = wasteTotals(db);
20
+ const outcomes = outcomeTotals(db);
21
+ const offload = offloadRows(db);
22
+ const completed = tokensPerCompletedTask(db);
23
+ const offloadTokens = offload.reduce((sum, row) => sum + row.tokens, 0);
24
+ const offloadUsd = offload.some((row) => row.usd !== null)
25
+ ? offload.reduce((sum, row) => sum + (row.usd ?? 0), 0)
26
+ : null;
27
+ const completedTokens = completed.reduce((sum, row) => sum + row.tokens, 0);
28
+ return {
29
+ schema: EXPORT_SCHEMA,
30
+ generatedAt: options.generatedAt ?? new Date().toISOString(),
31
+ totals: {
32
+ messages: totals.messages,
33
+ tokens: totals.tokens,
34
+ input: totals.input,
35
+ output: totals.output,
36
+ reasoning: totals.reasoning,
37
+ cacheRead: totals.cacheRead,
38
+ cacheWrite: totals.cacheWrite,
39
+ usd: totals.usd,
40
+ unpricedMessages: totals.unpricedMessages,
41
+ },
42
+ byRole: roles.map((row) => ({
43
+ role: row.role,
44
+ messages: row.messages,
45
+ tokens: row.tokens,
46
+ usd: row.usd,
47
+ unpriced: row.unpriced,
48
+ })),
49
+ byTask: tasks.map((row) => ({
50
+ taskId: row.taskId,
51
+ messages: row.messages,
52
+ tokens: row.tokens,
53
+ usd: row.usd,
54
+ })),
55
+ waste: { tokens: waste.tokens, percentage: waste.percentage },
56
+ outcomes,
57
+ tokensPerCompletedTask: completed.length > 0 ? completedTokens / completed.length : null,
58
+ offload: { messages: offload.length, tokens: offloadTokens, usd: offloadUsd },
59
+ };
60
+ }
61
+ /**
62
+ * The export of a ledger with nothing in it.
63
+ *
64
+ * A project that has no ledger yet has nothing to show, and reading it
65
+ * should not create one, so the zeros come from a database that lives only
66
+ * for the length of the call.
67
+ */
68
+ export function emptyLedgerExport(generatedAt) {
69
+ const db = new Database(':memory:');
70
+ try {
71
+ applySchema(db);
72
+ return ledgerExport(db, generatedAt === undefined ? {} : { generatedAt });
73
+ }
74
+ finally {
75
+ db.close();
76
+ }
77
+ }
78
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { Database } from 'bun:sqlite';
2
+ import { type Impact } from '@openagentsy/footprint';
3
+ /**
4
+ * The footprint rows.
5
+ *
6
+ * The ledger does not compute an impact: it stores the one it is given, with
7
+ * the bounds the estimator produced, and the version of the methodology that
8
+ * produced them, so a number is never read without the method behind it.
9
+ */
10
+ /**
11
+ * The methodology the numbers came from.
12
+ *
13
+ * The estimator pins EcoLogits 0.11.3 (see `packages/footprint/data/SOURCES.md`);
14
+ * the string lives here so the row says which method it was written under.
15
+ */
16
+ export declare const FOOTPRINT_METHOD_VERSION = "ecologits-0.11.3";
17
+ /**
18
+ * Record the footprint of one message.
19
+ *
20
+ * The row is written once per message and the bounds are ordered, because a
21
+ * range that reads backwards is a range nobody can use.
22
+ */
23
+ export declare function recordFootprint(db: Database, messageId: string, impact: Impact): void;
24
+ //# sourceMappingURL=footprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footprint.d.ts","sourceRoot":"","sources":["../src/footprint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,KAAK,MAAM,EAAK,MAAM,wBAAwB,CAAC;AAGxD;;;;;;GAMG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,qBAAqB,CAAC;AAE3D;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAqBrF"}
@@ -0,0 +1,33 @@
1
+ import { r } from '@openagentsy/footprint';
2
+ import { withBusyRetry } from './db.js';
3
+ /**
4
+ * The footprint rows.
5
+ *
6
+ * The ledger does not compute an impact: it stores the one it is given, with
7
+ * the bounds the estimator produced, and the version of the methodology that
8
+ * produced them, so a number is never read without the method behind it.
9
+ */
10
+ /**
11
+ * The methodology the numbers came from.
12
+ *
13
+ * The estimator pins EcoLogits 0.11.3 (see `packages/footprint/data/SOURCES.md`);
14
+ * the string lives here so the row says which method it was written under.
15
+ */
16
+ export const FOOTPRINT_METHOD_VERSION = 'ecologits-0.11.3';
17
+ /**
18
+ * Record the footprint of one message.
19
+ *
20
+ * The row is written once per message and the bounds are ordered, because a
21
+ * range that reads backwards is a range nobody can use.
22
+ */
23
+ export function recordFootprint(db, messageId, impact) {
24
+ const energy = r(impact.energyWh[0], impact.energyWh[1]);
25
+ const water = r(impact.waterL[0], impact.waterL[1]);
26
+ const co2 = r(impact.co2Kg[0], impact.co2Kg[1]);
27
+ withBusyRetry(() => {
28
+ db.query(`INSERT OR REPLACE INTO footprint
29
+ (message_id, energy_lo, energy_hi, water_lo, water_hi, co2_lo, co2_hi, method_version)
30
+ VALUES (?,?,?,?,?,?,?,?)`).run(messageId, energy[0], energy[1], water[0], water[1], co2[0], co2[1], FOOTPRINT_METHOD_VERSION);
31
+ });
32
+ }
33
+ //# sourceMappingURL=footprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footprint.js","sourceRoot":"","sources":["../src/footprint.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC;;;;;;GAMG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,kBAAkB,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,EAAY,EAAE,SAAiB,EAAE,MAAc;IAC7E,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhD,aAAa,CAAC,GAAG,EAAE;QACjB,EAAE,CAAC,KAAK,CACN;;mCAE6B,CAC9B,CAAC,GAAG,CACH,SAAS,EACT,MAAM,CAAC,CAAC,CAAC,EACT,MAAM,CAAC,CAAC,CAAC,EACT,KAAK,CAAC,CAAC,CAAC,EACR,KAAK,CAAC,CAAC,CAAC,EACR,GAAG,CAAC,CAAC,CAAC,EACN,GAAG,CAAC,CAAC,CAAC,EACN,wBAAwB,CACzB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ /** The result of one git command. */
2
+ export type GitResult = {
3
+ ok: boolean;
4
+ stdout: string;
5
+ stderr: string;
6
+ };
7
+ /**
8
+ * Run a git command and read what it says.
9
+ *
10
+ * The command never throws: a directory that is not a repository, or a git
11
+ * that is not installed, comes back as `ok: false` with the reason, and the
12
+ * scanner treats it as "nothing found" rather than as a crash. A scanner that
13
+ * cannot read a repository must not take the command down with it.
14
+ */
15
+ export declare function runGit(cwd: string, args: string[]): GitResult;
16
+ /** The output of a git command, or null when the command failed. */
17
+ export declare function gitText(cwd: string, args: string[]): string | null;
18
+ /** A commit, as the scanners read it. */
19
+ export type GitCommit = {
20
+ /** The full sha. */
21
+ sha: string;
22
+ /** Seconds since the epoch, the way git reports a commit time. */
23
+ at: number;
24
+ /** The whole message, without the format placeholders. */
25
+ message: string;
26
+ };
27
+ /**
28
+ * The commits of a repository, newest first.
29
+ *
30
+ * `git log` is asked for the sha, the timestamp and the body of the message
31
+ * in one pass. The three are separated by characters that cannot occur in
32
+ * them, so a message with a blank line in it survives the round trip.
33
+ */
34
+ export declare function gitCommits(cwd: string, since: string): GitCommit[];
35
+ /**
36
+ * The task ids of the `Refs:` trailers of a message.
37
+ *
38
+ * The trailer is the link between a commit and the work it did (§6.5): the
39
+ * pre-commit hook asks for it on an agent commit, and the outcome scanners
40
+ * read it back. A message with no trailer names no task, and a trailer that
41
+ * names nothing is not a trailer.
42
+ */
43
+ export declare function refsTrailers(message: string): string[];
44
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAiDA,qCAAqC;AACrC,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,CAe7D;AAED,oEAAoE;AACpE,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAGlE;AAED,yCAAyC;AACzC,MAAM,MAAM,SAAS,GAAG;IACtB,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,CAqBlE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAQtD"}
package/dist/git.js ADDED
@@ -0,0 +1,126 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ /**
3
+ * The git commands the scanners run.
4
+ *
5
+ * The scanners are commands and not daemons (§6.4): they read a repository
6
+ * on demand and write what they find into the ledger. Every call here is a
7
+ * read — `git log`, `git show` — and none of them writes to the repository.
8
+ */
9
+ /** The separator between the fields of one commit. */
10
+ const UNIT = '\u001f';
11
+ /** The separator between two commits. */
12
+ const RECORD = '\u001e';
13
+ /**
14
+ * The git variables that point a command at a repository.
15
+ *
16
+ * A git that runs a hook sets these in the environment of the hook, and a
17
+ * command spawned inside that hook inherits them. The child then addresses
18
+ * the repository of the hook instead of the one it was asked about: it
19
+ * writes to the outer index and fights the process that holds the lock —
20
+ * "fatal: Unable to create .../index.lock: File exists" is what that looks
21
+ * like. The child gets these removed, so the repository is the one the
22
+ * caller named.
23
+ */
24
+ const GIT_REPOSITORY_VARS = [
25
+ 'GIT_DIR',
26
+ 'GIT_WORK_TREE',
27
+ 'GIT_INDEX_FILE',
28
+ 'GIT_COMMON_DIR',
29
+ 'GIT_OBJECT_DIRECTORY',
30
+ 'GIT_ALTERNATE_OBJECT_DIRECTORIES',
31
+ 'GIT_CEILING_DIRECTORIES',
32
+ 'GIT_PREFIX',
33
+ 'GIT_NAMESPACE',
34
+ ];
35
+ /** The environment a git child gets: the caller's, without the git variables. */
36
+ function cleanEnv() {
37
+ const env = {};
38
+ for (const [key, value] of Object.entries(process.env)) {
39
+ if (value === undefined)
40
+ continue;
41
+ if (GIT_REPOSITORY_VARS.includes(key))
42
+ continue;
43
+ env[key] = value;
44
+ }
45
+ return env;
46
+ }
47
+ /**
48
+ * Run a git command and read what it says.
49
+ *
50
+ * The command never throws: a directory that is not a repository, or a git
51
+ * that is not installed, comes back as `ok: false` with the reason, and the
52
+ * scanner treats it as "nothing found" rather than as a crash. A scanner that
53
+ * cannot read a repository must not take the command down with it.
54
+ */
55
+ export function runGit(cwd, args) {
56
+ const result = spawnSync('git', args, {
57
+ cwd,
58
+ encoding: 'utf8',
59
+ maxBuffer: 64 * 1024 * 1024,
60
+ env: cleanEnv(),
61
+ });
62
+ if (result.error !== undefined) {
63
+ return { ok: false, stdout: '', stderr: result.error.message };
64
+ }
65
+ return {
66
+ ok: result.status === 0,
67
+ stdout: result.stdout ?? '',
68
+ stderr: result.stderr ?? '',
69
+ };
70
+ }
71
+ /** The output of a git command, or null when the command failed. */
72
+ export function gitText(cwd, args) {
73
+ const result = runGit(cwd, args);
74
+ return result.ok ? result.stdout : null;
75
+ }
76
+ /**
77
+ * The commits of a repository, newest first.
78
+ *
79
+ * `git log` is asked for the sha, the timestamp and the body of the message
80
+ * in one pass. The three are separated by characters that cannot occur in
81
+ * them, so a message with a blank line in it survives the round trip.
82
+ */
83
+ export function gitCommits(cwd, since) {
84
+ const output = gitText(cwd, [
85
+ 'log',
86
+ `--since=${since}`,
87
+ `--format=%H${UNIT}%at${UNIT}%B${RECORD}`,
88
+ ]);
89
+ if (output === null)
90
+ return [];
91
+ const commits = [];
92
+ for (const block of output.split(RECORD)) {
93
+ const trimmed = block.trim();
94
+ if (trimmed.length === 0)
95
+ continue;
96
+ const parts = trimmed.split(UNIT);
97
+ const sha = parts[0];
98
+ const at = parts[1];
99
+ if (sha === undefined || at === undefined)
100
+ continue;
101
+ const timestamp = Number(at);
102
+ if (!Number.isFinite(timestamp))
103
+ continue;
104
+ commits.push({ sha, at: timestamp, message: parts.slice(2).join(UNIT) });
105
+ }
106
+ return commits;
107
+ }
108
+ /**
109
+ * The task ids of the `Refs:` trailers of a message.
110
+ *
111
+ * The trailer is the link between a commit and the work it did (§6.5): the
112
+ * pre-commit hook asks for it on an agent commit, and the outcome scanners
113
+ * read it back. A message with no trailer names no task, and a trailer that
114
+ * names nothing is not a trailer.
115
+ */
116
+ export function refsTrailers(message) {
117
+ const refs = [];
118
+ for (const line of message.split('\n')) {
119
+ const match = /^\s*Refs:\s*(\S+)\s*$/.exec(line);
120
+ const taskId = match?.[1];
121
+ if (taskId !== undefined)
122
+ refs.push(taskId);
123
+ }
124
+ return refs;
125
+ }
126
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=git.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.test.d.ts","sourceRoot":"","sources":["../src/git.test.ts"],"names":[],"mappings":""}