@voxslopuli/openagentsy 0.0.0-stage → 0.2.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 (168) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +21 -2
  3. package/dist/adapter-dependency.test.d.ts +2 -0
  4. package/dist/adapter-dependency.test.d.ts.map +1 -0
  5. package/dist/adapter-dependency.test.js +51 -0
  6. package/dist/adapter-dependency.test.js.map +1 -0
  7. package/dist/commands/approve.d.ts +63 -0
  8. package/dist/commands/approve.d.ts.map +1 -0
  9. package/dist/commands/approve.js +218 -0
  10. package/dist/commands/approve.js.map +1 -0
  11. package/dist/commands/approve.test.d.ts +2 -0
  12. package/dist/commands/approve.test.d.ts.map +1 -0
  13. package/dist/commands/approve.test.js +219 -0
  14. package/dist/commands/approve.test.js.map +1 -0
  15. package/dist/commands/audit.d.ts +74 -0
  16. package/dist/commands/audit.d.ts.map +1 -0
  17. package/dist/commands/audit.js +230 -0
  18. package/dist/commands/audit.js.map +1 -0
  19. package/dist/commands/audit.test.d.ts +2 -0
  20. package/dist/commands/audit.test.d.ts.map +1 -0
  21. package/dist/commands/audit.test.js +194 -0
  22. package/dist/commands/audit.test.js.map +1 -0
  23. package/dist/commands/board.d.ts +33 -0
  24. package/dist/commands/board.d.ts.map +1 -0
  25. package/dist/commands/board.js +65 -0
  26. package/dist/commands/board.js.map +1 -0
  27. package/dist/commands/build.d.ts +17 -0
  28. package/dist/commands/build.d.ts.map +1 -0
  29. package/dist/commands/build.js +145 -0
  30. package/dist/commands/build.js.map +1 -0
  31. package/dist/commands/conformance.d.ts +31 -0
  32. package/dist/commands/conformance.d.ts.map +1 -0
  33. package/dist/commands/conformance.js +57 -0
  34. package/dist/commands/conformance.js.map +1 -0
  35. package/dist/commands/conformance.test.d.ts +2 -0
  36. package/dist/commands/conformance.test.d.ts.map +1 -0
  37. package/dist/commands/conformance.test.js +74 -0
  38. package/dist/commands/conformance.test.js.map +1 -0
  39. package/dist/commands/doctor.d.ts +132 -0
  40. package/dist/commands/doctor.d.ts.map +1 -0
  41. package/dist/commands/doctor.js +768 -0
  42. package/dist/commands/doctor.js.map +1 -0
  43. package/dist/commands/doctor.test.d.ts +2 -0
  44. package/dist/commands/doctor.test.d.ts.map +1 -0
  45. package/dist/commands/doctor.test.js +329 -0
  46. package/dist/commands/doctor.test.js.map +1 -0
  47. package/dist/commands/ledger.d.ts +109 -0
  48. package/dist/commands/ledger.d.ts.map +1 -0
  49. package/dist/commands/ledger.js +286 -0
  50. package/dist/commands/ledger.js.map +1 -0
  51. package/dist/commands/ledger.test.d.ts +2 -0
  52. package/dist/commands/ledger.test.d.ts.map +1 -0
  53. package/dist/commands/ledger.test.js +238 -0
  54. package/dist/commands/ledger.test.js.map +1 -0
  55. package/dist/commands/lessons.d.ts +73 -0
  56. package/dist/commands/lessons.d.ts.map +1 -0
  57. package/dist/commands/lessons.js +97 -0
  58. package/dist/commands/lessons.js.map +1 -0
  59. package/dist/commands/lessons.test.d.ts +2 -0
  60. package/dist/commands/lessons.test.d.ts.map +1 -0
  61. package/dist/commands/lessons.test.js +146 -0
  62. package/dist/commands/lessons.test.js.map +1 -0
  63. package/dist/commands/models.d.ts +49 -0
  64. package/dist/commands/models.d.ts.map +1 -0
  65. package/dist/commands/models.js +125 -0
  66. package/dist/commands/models.js.map +1 -0
  67. package/dist/commands/report.d.ts +57 -0
  68. package/dist/commands/report.d.ts.map +1 -0
  69. package/dist/commands/report.js +164 -0
  70. package/dist/commands/report.js.map +1 -0
  71. package/dist/commands/report.test.d.ts +2 -0
  72. package/dist/commands/report.test.d.ts.map +1 -0
  73. package/dist/commands/report.test.js +294 -0
  74. package/dist/commands/report.test.js.map +1 -0
  75. package/dist/commands/scope.d.ts +34 -0
  76. package/dist/commands/scope.d.ts.map +1 -0
  77. package/dist/commands/scope.js +78 -0
  78. package/dist/commands/scope.js.map +1 -0
  79. package/dist/commands/scope.test.d.ts +2 -0
  80. package/dist/commands/scope.test.d.ts.map +1 -0
  81. package/dist/commands/scope.test.js +98 -0
  82. package/dist/commands/scope.test.js.map +1 -0
  83. package/dist/commands/setup.d.ts +31 -0
  84. package/dist/commands/setup.d.ts.map +1 -0
  85. package/dist/commands/setup.js +93 -0
  86. package/dist/commands/setup.js.map +1 -0
  87. package/dist/commands/waivers.d.ts +47 -0
  88. package/dist/commands/waivers.d.ts.map +1 -0
  89. package/dist/commands/waivers.js +68 -0
  90. package/dist/commands/waivers.js.map +1 -0
  91. package/dist/commands/waivers.test.d.ts +2 -0
  92. package/dist/commands/waivers.test.d.ts.map +1 -0
  93. package/dist/commands/waivers.test.js +64 -0
  94. package/dist/commands/waivers.test.js.map +1 -0
  95. package/dist/generate/agent.d.ts +19 -0
  96. package/dist/generate/agent.d.ts.map +1 -0
  97. package/dist/generate/agent.js +35 -0
  98. package/dist/generate/agent.js.map +1 -0
  99. package/dist/generate/agent.test.d.ts +2 -0
  100. package/dist/generate/agent.test.d.ts.map +1 -0
  101. package/dist/generate/agent.test.js +245 -0
  102. package/dist/generate/agent.test.js.map +1 -0
  103. package/dist/generate/commands.d.ts +15 -0
  104. package/dist/generate/commands.d.ts.map +1 -0
  105. package/dist/generate/commands.js +59 -0
  106. package/dist/generate/commands.js.map +1 -0
  107. package/dist/generate/lock.d.ts +18 -0
  108. package/dist/generate/lock.d.ts.map +1 -0
  109. package/dist/generate/lock.js +26 -0
  110. package/dist/generate/lock.js.map +1 -0
  111. package/dist/generate/prompt.d.ts +11 -0
  112. package/dist/generate/prompt.d.ts.map +1 -0
  113. package/dist/generate/prompt.js +114 -0
  114. package/dist/generate/prompt.js.map +1 -0
  115. package/dist/generate/prompt.test.d.ts +2 -0
  116. package/dist/generate/prompt.test.d.ts.map +1 -0
  117. package/dist/generate/prompt.test.js +59 -0
  118. package/dist/generate/prompt.test.js.map +1 -0
  119. package/dist/index.d.ts +40 -0
  120. package/dist/index.d.ts.map +1 -0
  121. package/dist/index.js +448 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/index.test.d.ts +2 -0
  124. package/dist/index.test.d.ts.map +1 -0
  125. package/dist/index.test.js +237 -0
  126. package/dist/index.test.js.map +1 -0
  127. package/dist/opencode.d.ts +29 -0
  128. package/dist/opencode.d.ts.map +1 -0
  129. package/dist/opencode.js +125 -0
  130. package/dist/opencode.js.map +1 -0
  131. package/dist/plugin-bundle.test.d.ts +2 -0
  132. package/dist/plugin-bundle.test.d.ts.map +1 -0
  133. package/dist/plugin-bundle.test.js +43 -0
  134. package/dist/plugin-bundle.test.js.map +1 -0
  135. package/dist/plugin.d.ts +11 -0
  136. package/dist/plugin.d.ts.map +1 -0
  137. package/dist/plugin.js +46 -0
  138. package/dist/plugin.js.map +1 -0
  139. package/dist/quality-skills.test.d.ts +2 -0
  140. package/dist/quality-skills.test.d.ts.map +1 -0
  141. package/dist/quality-skills.test.js +141 -0
  142. package/dist/quality-skills.test.js.map +1 -0
  143. package/dist/report/footprint.d.ts +12 -0
  144. package/dist/report/footprint.d.ts.map +1 -0
  145. package/dist/report/footprint.js +121 -0
  146. package/dist/report/footprint.js.map +1 -0
  147. package/dist/report/ledger.d.ts +27 -0
  148. package/dist/report/ledger.d.ts.map +1 -0
  149. package/dist/report/ledger.js +197 -0
  150. package/dist/report/ledger.js.map +1 -0
  151. package/dist/report/oversight.d.ts +21 -0
  152. package/dist/report/oversight.d.ts.map +1 -0
  153. package/dist/report/oversight.js +146 -0
  154. package/dist/report/oversight.js.map +1 -0
  155. package/dist/report/policy-firing.test.d.ts +2 -0
  156. package/dist/report/policy-firing.test.d.ts.map +1 -0
  157. package/dist/report/policy-firing.test.js +68 -0
  158. package/dist/report/policy-firing.test.js.map +1 -0
  159. package/dist/report/scope.d.ts +64 -0
  160. package/dist/report/scope.d.ts.map +1 -0
  161. package/dist/report/scope.js +146 -0
  162. package/dist/report/scope.js.map +1 -0
  163. package/dist/who.d.ts +9 -0
  164. package/dist/who.d.ts.map +1 -0
  165. package/dist/who.js +11 -0
  166. package/dist/who.js.map +1 -0
  167. package/package.json +54 -4
  168. package/plugin/openagentsy.js +39478 -0
@@ -0,0 +1,146 @@
1
+ import { access, readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { closeDatabase, listRecords, openDatabase, } from '@openagentsy/core';
4
+ import { createWaiverStore, listLessons, pendingLessons } from '@openagentsy/hooks';
5
+ /**
6
+ * The oversight of the scope.
7
+ *
8
+ * The counts are the board's records, the lessons that wait for a person,
9
+ * the waivers a person recorded, the audit log and the findings store. The
10
+ * two the plan names and no package keeps are carried as measurements that
11
+ * are not known, with the reason: a zero there would look like a
12
+ * measurement, and it is not one.
13
+ */
14
+ /** How many records one page of the board holds. */
15
+ const PAGE_SIZE = 100;
16
+ /** The bean the archivist posts a candidate memory under. */
17
+ const MEMORY_BEAN = 'memory';
18
+ /** The states a decided candidate carries. */
19
+ const DECIDED_STATES = ['promoted', 'rejected'];
20
+ /**
21
+ * Every record on the board.
22
+ *
23
+ * The board holds more than one page of records, and a report that read
24
+ * only the first page would undercount a project with a long history. The
25
+ * pages are walked until one comes back short.
26
+ */
27
+ async function boardRecords(stateRoot) {
28
+ const path = join(stateRoot, '.openagentsy', 'board.sqlite');
29
+ const exists = await access(path).then(() => true, () => false);
30
+ if (!exists)
31
+ return [];
32
+ const db = openDatabase(path);
33
+ try {
34
+ const found = [];
35
+ let cursor = 0;
36
+ for (;;) {
37
+ const page = listRecords(db, { cursor, limit: PAGE_SIZE });
38
+ found.push(...page.records);
39
+ if (page.records.length < PAGE_SIZE)
40
+ return found;
41
+ cursor = page.nextCursor;
42
+ }
43
+ }
44
+ finally {
45
+ closeDatabase(db);
46
+ }
47
+ }
48
+ /**
49
+ * The memory candidates waiting for a person.
50
+ *
51
+ * A candidate is a board record under the memory bean that no person has
52
+ * decided on, and the decided states are the ones the memory package
53
+ * writes: promoted and rejected. The rule is the memory package's, and the
54
+ * report counts the records itself because the package sits above the
55
+ * adapter and the report needs nothing else of it.
56
+ */
57
+ function memoryCandidates(records) {
58
+ return records.filter((record) => record.bean === MEMORY_BEAN && !DECIDED_STATES.includes(record.state)).length;
59
+ }
60
+ /** The lines of the audit log. */
61
+ async function auditEntries(stateRoot) {
62
+ const path = join(stateRoot, '.openagentsy', 'audit.jsonl');
63
+ let text;
64
+ try {
65
+ text = await readFile(path, 'utf8');
66
+ }
67
+ catch {
68
+ return 0;
69
+ }
70
+ return text.split('\n').filter((line) => line.trim() !== '').length;
71
+ }
72
+ /**
73
+ * The findings of the scope.
74
+ *
75
+ * The findings are the store's, read through the quality package's read
76
+ * path. A bean scope reads the findings of that task, because the ledger
77
+ * reads the task of a bean the same way. Every other scope reads them all:
78
+ * the findings store has no session and no window, and a report that
79
+ * narrowed it by guesswork would be narrowing it wrongly.
80
+ */
81
+ export function scopedFindings(findings, scope) {
82
+ const scoped = [];
83
+ for (const [taskId, entries] of Object.entries(findings)) {
84
+ if (scope.kind === 'bean' && taskId !== scope.id)
85
+ continue;
86
+ scoped.push(...entries);
87
+ }
88
+ return scoped;
89
+ }
90
+ /**
91
+ * The open floor findings of the scope.
92
+ *
93
+ * The floor tier is the one the gate refuses a ship over, so a report that
94
+ * counts the open floor findings is counting the things that would stop the
95
+ * work from shipping.
96
+ */
97
+ function openFloor(findings, scope) {
98
+ const found = [];
99
+ for (const [taskId, entries] of Object.entries(findings)) {
100
+ if (scope.kind === 'bean' && taskId !== scope.id)
101
+ continue;
102
+ for (const finding of entries) {
103
+ if (finding.tier !== 'floor')
104
+ continue;
105
+ found.push({
106
+ taskId,
107
+ ruleId: finding.ruleId,
108
+ file: finding.file,
109
+ message: finding.message,
110
+ });
111
+ }
112
+ }
113
+ return found;
114
+ }
115
+ /**
116
+ * The oversight of the scope.
117
+ *
118
+ * The board records of a bean scope are the records of that bean, and every
119
+ * other scope sees the whole board: the board has no session column and no
120
+ * window, so a report that narrowed it would be narrowing it by guesswork.
121
+ */
122
+ export async function oversightFacts(stateRoot, scope, findings) {
123
+ const records = await boardRecords(stateRoot);
124
+ const scoped = scope.kind === 'bean' ? records.filter((r) => r.bean === scope.id) : records;
125
+ const lessons = await listLessons(stateRoot);
126
+ const waivers = await createWaiverStore(stateRoot).count();
127
+ const floor = openFloor(findings, scope);
128
+ return {
129
+ records: scoped.length,
130
+ lessons: pendingLessons(lessons).length,
131
+ memory: memoryCandidates(records),
132
+ waivers,
133
+ auditEntries: await auditEntries(stateRoot),
134
+ openFloor: floor.length,
135
+ openFloorFindings: floor,
136
+ mismatches: {
137
+ known: false,
138
+ reason: 'no package compares the board with a report',
139
+ },
140
+ redactions: {
141
+ known: false,
142
+ reason: 'no package keeps a counter',
143
+ },
144
+ };
145
+ }
146
+ //# sourceMappingURL=oversight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oversight.js","sourceRoot":"","sources":["../../src/report/oversight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=policy-firing.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-firing.test.d.ts","sourceRoot":"","sources":["../../src/report/policy-firing.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ import { mkdtempSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { firstPartyPolicyModules, PolicyEngine, PolicyRegistry } from '@openagentsy/hooks';
5
+ import { closeLedger, createPolicyFiringSink, openLedger, topPoliciesByFireCount, } from '@openagentsy/ledger';
6
+ import { describe, expect, it } from 'vitest';
7
+ /**
8
+ * The firing log, from the engine to the ledger and back (§21.3).
9
+ *
10
+ * The engine writes through a sink and the ledger stores the rows, so the
11
+ * log is a store: it is read back after the ledger was closed and opened
12
+ * again.
13
+ */
14
+ describe('the policy firing log', () => {
15
+ it('holds the firings of a session after the ledger was reopened', () => {
16
+ const root = mkdtempSync(join(tmpdir(), 'openagentsy-policy-engine-'));
17
+ const db = openLedger(root);
18
+ const registry = new PolicyRegistry(firstPartyPolicyModules({ workspace: root }));
19
+ const engine = new PolicyEngine(registry, { sink: createPolicyFiringSink(db) });
20
+ engine.evaluate({
21
+ session: { id: 'ses_1', roleId: 'builder' },
22
+ response: { text: 'You are absolutely right, this is a great point.' },
23
+ });
24
+ closeLedger(db);
25
+ const again = openLedger(root);
26
+ try {
27
+ const counts = topPoliciesByFireCount(again, 10);
28
+ const flagged = counts.find((entry) => entry.policyId === 'oa.anti-sycophancy');
29
+ expect(flagged?.count).toBe(1);
30
+ expect(flagged?.flags).toBe(1);
31
+ expect(flagged?.versions).toEqual(['1.0.0']);
32
+ const stack = again
33
+ .query('SELECT reason, detail FROM policy_firing WHERE policy_id = ?')
34
+ .get('oa.policy.stack');
35
+ expect(stack?.reason).toBe('stack-assembled');
36
+ expect(stack?.detail).toContain('oa.anti-sycophancy');
37
+ }
38
+ finally {
39
+ closeLedger(again);
40
+ }
41
+ });
42
+ it('records the stack of a session once, and the decisions of it', () => {
43
+ const root = mkdtempSync(join(tmpdir(), 'openagentsy-policy-engine-'));
44
+ const db = openLedger(root);
45
+ const registry = new PolicyRegistry(firstPartyPolicyModules({ workspace: root }));
46
+ const engine = new PolicyEngine(registry, { sink: createPolicyFiringSink(db) });
47
+ const context = {
48
+ session: { id: 'ses_1', roleId: 'builder' },
49
+ response: { text: 'The parser reads the file.' },
50
+ };
51
+ engine.evaluate(context);
52
+ engine.evaluate(context);
53
+ closeLedger(db);
54
+ const again = openLedger(root);
55
+ try {
56
+ const stack = again
57
+ .query('SELECT COUNT(*) AS total FROM policy_firing WHERE policy_id = ?')
58
+ .get('oa.policy.stack');
59
+ expect(stack.total).toBe(1);
60
+ const total = again.query('SELECT COUNT(*) AS total FROM policy_firing').get();
61
+ expect(total.total).toBeGreaterThan(1);
62
+ }
63
+ finally {
64
+ closeLedger(again);
65
+ }
66
+ });
67
+ });
68
+ //# sourceMappingURL=policy-firing.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-firing.test.js","sourceRoot":"","sources":["../../src/report/policy-firing.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import type { ReportScope } from '@openagentsy/core';
2
+ import type { openLedger } from '@openagentsy/ledger';
3
+ /**
4
+ * The scope of the report, and the rows it selects.
5
+ *
6
+ * A scope is one of three things: a session, a bean or a window. The report
7
+ * says which one it is, and an empty scope is a fact the report prints
8
+ * rather than a gap it fills with zeroes.
9
+ */
10
+ /**
11
+ * The ledger's database, as the ledger names it.
12
+ *
13
+ * The type comes from the ledger rather than from `bun:sqlite`, so the CLI
14
+ * does not need the Bun type definitions to talk about the ledger it
15
+ * already opens.
16
+ */
17
+ export type LedgerDb = ReturnType<typeof openLedger>;
18
+ /** The flags a scope is built from. */
19
+ export type ScopeFlags = {
20
+ /** The session, and the subagents that rolled up into it. */
21
+ session?: string | undefined;
22
+ /** The bean: the rows whose task is that bean. */
23
+ bean?: string | undefined;
24
+ /** The window, as a phrase: 30d, 30 days ago, 2 weeks ago. */
25
+ since?: string | undefined;
26
+ };
27
+ /** The scope the flags name, or the problem with them. */
28
+ export type ScopeResult = {
29
+ ok: true;
30
+ scope: ReportScope;
31
+ } | {
32
+ ok: false;
33
+ error: string;
34
+ };
35
+ /**
36
+ * The scope the flags name.
37
+ *
38
+ * The flags name one thing. Two of them name two things, and a report of
39
+ * two scopes at once is a report of none of them, so the command says the
40
+ * scope is ambiguous and stops.
41
+ */
42
+ export declare function parseScope(flags: ScopeFlags): ScopeResult;
43
+ /**
44
+ * Shadow the ledger's tables with the rows the scope selects.
45
+ *
46
+ * The ledger's own queries read the tables by name, and they take no scope:
47
+ * the ledger holds every row it was given. So the scope is applied here,
48
+ * once, by putting the scoped rows into temp tables of the same names. The
49
+ * ledger's queries then read the scope, and the report cannot drift from
50
+ * the ledger, because the report never totals anything itself.
51
+ *
52
+ * The temp tables live in the connection and go with it: nothing is written
53
+ * to the ledger, and a report never changes what it reports on.
54
+ */
55
+ export declare function shadowScope(db: LedgerDb, scope: ReportScope): void;
56
+ /**
57
+ * The days the ledger's own window covers.
58
+ *
59
+ * The ledger's outcome queries look at the last thirty days. A scope that
60
+ * names a window uses that window, and a scope that names a thing opens the
61
+ * ledger's window wide, so the scope alone decides what is in the report.
62
+ */
63
+ export declare function windowDays(scope: ReportScope): number;
64
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/report/scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;;;;;GAMG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAErD,uCAAuC;AACvC,MAAM,MAAM,UAAU,GAAG;IACvB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B,CAAC;AAEF,0DAA0D;AAC1D,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA2C1F;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAuBzD;AA+CD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAYlE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAErD"}
@@ -0,0 +1,146 @@
1
+ /** How long a unit of a window is, in milliseconds. */
2
+ const UNITS = {
3
+ h: 3_600_000,
4
+ hour: 3_600_000,
5
+ hours: 3_600_000,
6
+ d: 86_400_000,
7
+ day: 86_400_000,
8
+ days: 86_400_000,
9
+ w: 604_800_000,
10
+ week: 604_800_000,
11
+ weeks: 604_800_000,
12
+ m: 2_592_000_000,
13
+ month: 2_592_000_000,
14
+ months: 2_592_000_000,
15
+ };
16
+ /**
17
+ * The window a phrase names.
18
+ *
19
+ * The phrase is a number and a unit, with an optional "ago": 30d, 30 days,
20
+ * 30 days ago. A phrase that names no window is no window, and the caller
21
+ * says so rather than guessing a default.
22
+ */
23
+ function parseWindow(phrase) {
24
+ const trimmed = phrase
25
+ .trim()
26
+ .toLowerCase()
27
+ .replace(/\s+ago$/, '')
28
+ .trim();
29
+ const found = /^(\d+)\s*([a-z]+)$/.exec(trimmed);
30
+ if (found === null)
31
+ return undefined;
32
+ const amount = Number(found[1]);
33
+ const unit = found[2];
34
+ if (unit === undefined)
35
+ return undefined;
36
+ const millis = UNITS[unit];
37
+ if (millis === undefined || !Number.isFinite(amount) || amount <= 0)
38
+ return undefined;
39
+ const days = Math.round((amount * millis) / 86_400_000);
40
+ if (days <= 0)
41
+ return undefined;
42
+ return { days, label: `${amount} ${unit}` };
43
+ }
44
+ /**
45
+ * The scope the flags name.
46
+ *
47
+ * The flags name one thing. Two of them name two things, and a report of
48
+ * two scopes at once is a report of none of them, so the command says the
49
+ * scope is ambiguous and stops.
50
+ */
51
+ export function parseScope(flags) {
52
+ const named = [
53
+ ...(flags.session === undefined ? [] : [`session ${flags.session}`]),
54
+ ...(flags.bean === undefined ? [] : [`bean ${flags.bean}`]),
55
+ ...(flags.since === undefined ? [] : [`since ${flags.since}`]),
56
+ ];
57
+ if (named.length > 1) {
58
+ return { ok: false, error: `the scope names more than one thing: ${named.join(' and ')}` };
59
+ }
60
+ if (flags.session !== undefined) {
61
+ return { ok: true, scope: { kind: 'session', id: flags.session } };
62
+ }
63
+ if (flags.bean !== undefined) {
64
+ return { ok: true, scope: { kind: 'bean', id: flags.bean } };
65
+ }
66
+ if (flags.since !== undefined) {
67
+ const window = parseWindow(flags.since);
68
+ if (window === undefined) {
69
+ return { ok: false, error: `the window ${flags.since} names no time` };
70
+ }
71
+ return { ok: true, scope: { kind: 'since', days: window.days, label: window.label } };
72
+ }
73
+ return { ok: true, scope: { kind: 'project' } };
74
+ }
75
+ /** The tables the scope is applied to. */
76
+ const TABLES = ['usage', 'waste', 'outcome', 'policy_firing'];
77
+ /**
78
+ * The rows a table holds for the scope.
79
+ *
80
+ * The predicate is the scope, and the parameters are what it names. A
81
+ * project scope selects every row, so the predicate is a tautology and the
82
+ * table is read whole.
83
+ */
84
+ function predicate(table, scope, instant) {
85
+ switch (scope.kind) {
86
+ case 'project':
87
+ return { sql: '1 = 1', params: [] };
88
+ case 'since':
89
+ return { sql: 'ts >= ?', params: [instant] };
90
+ case 'session':
91
+ if (table === 'usage') {
92
+ return { sql: '(root_session_id = ? OR session_id = ?)', params: [scope.id, scope.id] };
93
+ }
94
+ if (table === 'policy_firing') {
95
+ return { sql: 'session_id = ?', params: [scope.id] };
96
+ }
97
+ return { sql: 'root_session_id = ?', params: [scope.id] };
98
+ case 'bean':
99
+ if (table === 'waste') {
100
+ return {
101
+ sql: 'message_id IN (SELECT message_id FROM main.usage WHERE task_id = ?)',
102
+ params: [scope.id],
103
+ };
104
+ }
105
+ if (table === 'policy_firing') {
106
+ return {
107
+ sql: 'session_id IN (SELECT session_id FROM main.usage WHERE task_id = ?)',
108
+ params: [scope.id],
109
+ };
110
+ }
111
+ return { sql: 'task_id = ?', params: [scope.id] };
112
+ }
113
+ }
114
+ /**
115
+ * Shadow the ledger's tables with the rows the scope selects.
116
+ *
117
+ * The ledger's own queries read the tables by name, and they take no scope:
118
+ * the ledger holds every row it was given. So the scope is applied here,
119
+ * once, by putting the scoped rows into temp tables of the same names. The
120
+ * ledger's queries then read the scope, and the report cannot drift from
121
+ * the ledger, because the report never totals anything itself.
122
+ *
123
+ * The temp tables live in the connection and go with it: nothing is written
124
+ * to the ledger, and a report never changes what it reports on.
125
+ */
126
+ export function shadowScope(db, scope) {
127
+ const instant = scope.kind === 'since'
128
+ ? new Date(Date.now() - scope.days * 86_400_000).toISOString()
129
+ : new Date(0).toISOString();
130
+ for (const table of TABLES) {
131
+ const { sql, params } = predicate(table, scope, instant);
132
+ db.exec(`DROP TABLE IF EXISTS temp.${table}`);
133
+ db.query(`CREATE TEMP TABLE ${table} AS SELECT * FROM main.${table} WHERE ${sql}`).run(...params);
134
+ }
135
+ }
136
+ /**
137
+ * The days the ledger's own window covers.
138
+ *
139
+ * The ledger's outcome queries look at the last thirty days. A scope that
140
+ * names a window uses that window, and a scope that names a thing opens the
141
+ * ledger's window wide, so the scope alone decides what is in the report.
142
+ */
143
+ export function windowDays(scope) {
144
+ return scope.kind === 'since' ? scope.days : 36_500;
145
+ }
146
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/report/scope.ts"],"names":[],"mappings":"AAiCA,uDAAuD;AACvD,MAAM,KAAK,GAA2B;IACpC,CAAC,EAAE,SAAS;IACZ,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,CAAC,EAAE,UAAU;IACb,GAAG,EAAE,UAAU;IACf,IAAI,EAAE,UAAU;IAChB,CAAC,EAAE,WAAW;IACd,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,WAAW;IAClB,CAAC,EAAE,aAAa;IAChB,KAAK,EAAE,aAAa;IACpB,MAAM,EAAE,aAAa;CACtB,CAAC;AAEF;;;;;;GAMG;AACH,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,OAAO,GAAG,MAAM;SACnB,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;SACtB,IAAI,EAAE,CAAC;IACV,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACtF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC;IACxD,IAAI,IAAI,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,MAAM,KAAK,GAAG;QACZ,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACpE,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;KAC/D,CAAC;IACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;IAC7F,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;IACrE,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;IAC/D,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,KAAK,CAAC,KAAK,gBAAgB,EAAE,CAAC;QACzE,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;IACxF,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;AAClD,CAAC;AAED,0CAA0C;AAC1C,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,CAAU,CAAC;AAEvE;;;;;;GAMG;AACH,SAAS,SAAS,CAChB,KAA8B,EAC9B,KAAkB,EAClB,OAAe;IAEf,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACtC,KAAK,OAAO;YACV,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/C,KAAK,SAAS;YACZ,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;gBACtB,OAAO,EAAE,GAAG,EAAE,yCAAyC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;YAC1F,CAAC;YACD,IAAI,KAAK,KAAK,eAAe,EAAE,CAAC;gBAC9B,OAAO,EAAE,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;YACvD,CAAC;YACD,OAAO,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5D,KAAK,MAAM;YACT,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;gBACtB,OAAO;oBACL,GAAG,EAAE,qEAAqE;oBAC1E,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;iBACnB,CAAC;YACJ,CAAC;YACD,IAAI,KAAK,KAAK,eAAe,EAAE,CAAC;gBAC9B,OAAO;oBACL,GAAG,EAAE,qEAAqE;oBAC1E,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;iBACnB,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;IACtD,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,EAAY,EAAE,KAAkB;IAC1D,MAAM,OAAO,GACX,KAAK,CAAC,IAAI,KAAK,OAAO;QACpB,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,IAAI,GAAG,UAAU,CAAC,CAAC,WAAW,EAAE;QAC9D,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACzD,EAAE,CAAC,IAAI,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAC;QAC9C,EAAE,CAAC,KAAK,CAAC,qBAAqB,KAAK,0BAA0B,KAAK,UAAU,GAAG,EAAE,CAAC,CAAC,GAAG,CACpF,GAAG,MAAM,CACV,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,KAAkB;IAC3C,OAAO,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AACtD,CAAC"}
package/dist/who.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Who the person running a command is.
3
+ *
4
+ * A decision a person makes carries the name of the person who made it. The
5
+ * name comes from the environment when it is set, because a person may want
6
+ * the record to say who they are, and the default is "a person".
7
+ */
8
+ export declare function deciderBy(override?: string): string;
9
+ //# sourceMappingURL=who.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"who.d.ts","sourceRoot":"","sources":["../src/who.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD"}
package/dist/who.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Who the person running a command is.
3
+ *
4
+ * A decision a person makes carries the name of the person who made it. The
5
+ * name comes from the environment when it is set, because a person may want
6
+ * the record to say who they are, and the default is "a person".
7
+ */
8
+ export function deciderBy(override) {
9
+ return override ?? process.env.OPENAGENTSY_USER ?? 'human';
10
+ }
11
+ //# sourceMappingURL=who.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"who.js","sourceRoot":"","sources":["../src/who.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,QAAiB;IACzC,OAAO,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,OAAO,CAAC;AAC7D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,56 @@
1
1
  {
2
2
  "name": "@voxslopuli/openagentsy",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "openagentsy": "./dist/index.js",
7
+ "oa": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc -b tsconfig.json && chmod +x dist/index.js && node scripts/copy-plugin.mjs",
11
+ "typecheck": "tsc -b tsconfig.json"
12
+ },
13
+ "dependencies": {
14
+ "@openagentsy/core": "^0.2.0",
15
+ "@openagentsy/footprint": "^0.2.0",
16
+ "@openagentsy/hooks": "^0.2.0",
17
+ "@openagentsy/ledger": "^0.2.0",
18
+ "@openagentsy/models": "^0.2.0",
19
+ "@openagentsy/quality": "^0.2.0",
20
+ "jsonc-parser": "^3.3.1",
21
+ "yaml": "^2.8.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^24.3.0",
25
+ "typescript": "^5.9.2",
26
+ "@openagentsy/adapter-opencode": "0.2.0"
27
+ },
28
+ "description": "The hub and spoke agent system for OpenCode: one Lead, many specialists, one writer per file.",
29
+ "license": "GPL-3.0-or-later",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/voxslopuli/openagentsy.git"
33
+ },
34
+ "homepage": "https://github.com/voxslopuli/openagentsy#readme",
35
+ "bugs": {
36
+ "url": "https://github.com/voxslopuli/openagentsy/issues"
37
+ },
38
+ "keywords": [
39
+ "agents",
40
+ "opencode",
41
+ "coordination",
42
+ "leases",
43
+ "mcp",
44
+ "bun"
45
+ ],
46
+ "engines": {
47
+ "node": ">=22.5.0"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "files": [
53
+ "dist",
54
+ "plugin"
55
+ ]
56
+ }