estela 0.1.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 (186) hide show
  1. package/README.md +138 -0
  2. package/dist/billing/amortize.d.ts +44 -0
  3. package/dist/billing/amortize.d.ts.map +1 -0
  4. package/dist/billing/amortize.js +83 -0
  5. package/dist/billing/amortize.js.map +1 -0
  6. package/dist/billing/amortize.test.d.ts +2 -0
  7. package/dist/billing/amortize.test.d.ts.map +1 -0
  8. package/dist/billing/amortize.test.js +121 -0
  9. package/dist/billing/amortize.test.js.map +1 -0
  10. package/dist/billing/format.test.d.ts +2 -0
  11. package/dist/billing/format.test.d.ts.map +1 -0
  12. package/dist/billing/format.test.js +110 -0
  13. package/dist/billing/format.test.js.map +1 -0
  14. package/dist/billing/invoice.d.ts +52 -0
  15. package/dist/billing/invoice.d.ts.map +1 -0
  16. package/dist/billing/invoice.js +148 -0
  17. package/dist/billing/invoice.js.map +1 -0
  18. package/dist/billing/invoice.test.d.ts +2 -0
  19. package/dist/billing/invoice.test.d.ts.map +1 -0
  20. package/dist/billing/invoice.test.js +200 -0
  21. package/dist/billing/invoice.test.js.map +1 -0
  22. package/dist/billing/sessionize.d.ts +104 -0
  23. package/dist/billing/sessionize.d.ts.map +1 -0
  24. package/dist/billing/sessionize.js +0 -0
  25. package/dist/billing/sessionize.js.map +1 -0
  26. package/dist/billing/sessionize.test.d.ts +2 -0
  27. package/dist/billing/sessionize.test.d.ts.map +1 -0
  28. package/dist/billing/sessionize.test.js +67 -0
  29. package/dist/billing/sessionize.test.js.map +1 -0
  30. package/dist/cli.d.ts +4 -0
  31. package/dist/cli.d.ts.map +1 -0
  32. package/dist/cli.js +1091 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/cloud/auth.d.ts +4 -0
  35. package/dist/cloud/auth.d.ts.map +1 -0
  36. package/dist/cloud/auth.js +98 -0
  37. package/dist/cloud/auth.js.map +1 -0
  38. package/dist/cloud/client.d.ts +12 -0
  39. package/dist/cloud/client.d.ts.map +1 -0
  40. package/dist/cloud/client.js +34 -0
  41. package/dist/cloud/client.js.map +1 -0
  42. package/dist/db/schema.d.ts +11 -0
  43. package/dist/db/schema.d.ts.map +1 -0
  44. package/dist/db/schema.js +424 -0
  45. package/dist/db/schema.js.map +1 -0
  46. package/dist/db/schema.test.d.ts +2 -0
  47. package/dist/db/schema.test.d.ts.map +1 -0
  48. package/dist/db/schema.test.js +335 -0
  49. package/dist/db/schema.test.js.map +1 -0
  50. package/dist/db/store.d.ts +113 -0
  51. package/dist/db/store.d.ts.map +1 -0
  52. package/dist/db/store.js +550 -0
  53. package/dist/db/store.js.map +1 -0
  54. package/dist/doctor.d.ts +24 -0
  55. package/dist/doctor.d.ts.map +1 -0
  56. package/dist/doctor.js +229 -0
  57. package/dist/doctor.js.map +1 -0
  58. package/dist/export/csv.d.ts +9 -0
  59. package/dist/export/csv.d.ts.map +1 -0
  60. package/dist/export/csv.js +81 -0
  61. package/dist/export/csv.js.map +1 -0
  62. package/dist/export/invoice-pdf.d.ts +21 -0
  63. package/dist/export/invoice-pdf.d.ts.map +1 -0
  64. package/dist/export/invoice-pdf.js +135 -0
  65. package/dist/export/invoice-pdf.js.map +1 -0
  66. package/dist/export/panel.d.ts +78 -0
  67. package/dist/export/panel.d.ts.map +1 -0
  68. package/dist/export/panel.js +693 -0
  69. package/dist/export/panel.js.map +1 -0
  70. package/dist/export/panel.test.d.ts +2 -0
  71. package/dist/export/panel.test.d.ts.map +1 -0
  72. package/dist/export/panel.test.js +273 -0
  73. package/dist/export/panel.test.js.map +1 -0
  74. package/dist/export/pdf.d.ts +32 -0
  75. package/dist/export/pdf.d.ts.map +1 -0
  76. package/dist/export/pdf.js +229 -0
  77. package/dist/export/pdf.js.map +1 -0
  78. package/dist/export/pdf.test.d.ts +2 -0
  79. package/dist/export/pdf.test.d.ts.map +1 -0
  80. package/dist/export/pdf.test.js +151 -0
  81. package/dist/export/pdf.test.js.map +1 -0
  82. package/dist/export/share.d.ts +42 -0
  83. package/dist/export/share.d.ts.map +1 -0
  84. package/dist/export/share.js +181 -0
  85. package/dist/export/share.js.map +1 -0
  86. package/dist/export/share.test.d.ts +2 -0
  87. package/dist/export/share.test.d.ts.map +1 -0
  88. package/dist/export/share.test.js +116 -0
  89. package/dist/export/share.test.js.map +1 -0
  90. package/dist/metrics/index.d.ts +101 -0
  91. package/dist/metrics/index.d.ts.map +1 -0
  92. package/dist/metrics/index.js +221 -0
  93. package/dist/metrics/index.js.map +1 -0
  94. package/dist/metrics/metrics.test.d.ts +2 -0
  95. package/dist/metrics/metrics.test.d.ts.map +1 -0
  96. package/dist/metrics/metrics.test.js +162 -0
  97. package/dist/metrics/metrics.test.js.map +1 -0
  98. package/dist/metrics/people.d.ts +46 -0
  99. package/dist/metrics/people.d.ts.map +1 -0
  100. package/dist/metrics/people.js +126 -0
  101. package/dist/metrics/people.js.map +1 -0
  102. package/dist/metrics/people.test.d.ts +2 -0
  103. package/dist/metrics/people.test.d.ts.map +1 -0
  104. package/dist/metrics/people.test.js +84 -0
  105. package/dist/metrics/people.test.js.map +1 -0
  106. package/dist/metrics/team.d.ts +41 -0
  107. package/dist/metrics/team.d.ts.map +1 -0
  108. package/dist/metrics/team.js +0 -0
  109. package/dist/metrics/team.js.map +1 -0
  110. package/dist/metrics/team.test.d.ts +2 -0
  111. package/dist/metrics/team.test.d.ts.map +1 -0
  112. package/dist/metrics/team.test.js +90 -0
  113. package/dist/metrics/team.test.js.map +1 -0
  114. package/dist/pricing/catalog.d.ts +39 -0
  115. package/dist/pricing/catalog.d.ts.map +1 -0
  116. package/dist/pricing/catalog.js +59 -0
  117. package/dist/pricing/catalog.js.map +1 -0
  118. package/dist/pricing/cost.d.ts +25 -0
  119. package/dist/pricing/cost.d.ts.map +1 -0
  120. package/dist/pricing/cost.js +50 -0
  121. package/dist/pricing/cost.js.map +1 -0
  122. package/dist/pricing/cost.test.d.ts +2 -0
  123. package/dist/pricing/cost.test.d.ts.map +1 -0
  124. package/dist/pricing/cost.test.js +74 -0
  125. package/dist/pricing/cost.test.js.map +1 -0
  126. package/dist/server.d.ts +15 -0
  127. package/dist/server.d.ts.map +1 -0
  128. package/dist/server.js +1141 -0
  129. package/dist/server.js.map +1 -0
  130. package/dist/setup.d.ts +70 -0
  131. package/dist/setup.d.ts.map +1 -0
  132. package/dist/setup.js +223 -0
  133. package/dist/setup.js.map +1 -0
  134. package/dist/setup.test.d.ts +2 -0
  135. package/dist/setup.test.d.ts.map +1 -0
  136. package/dist/setup.test.js +131 -0
  137. package/dist/setup.test.js.map +1 -0
  138. package/dist/watchers/claude.d.ts +34 -0
  139. package/dist/watchers/claude.d.ts.map +1 -0
  140. package/dist/watchers/claude.js +235 -0
  141. package/dist/watchers/claude.js.map +1 -0
  142. package/dist/watchers/claude.test.d.ts +2 -0
  143. package/dist/watchers/claude.test.d.ts.map +1 -0
  144. package/dist/watchers/claude.test.js +180 -0
  145. package/dist/watchers/claude.test.js.map +1 -0
  146. package/dist/watchers/git.d.ts +42 -0
  147. package/dist/watchers/git.d.ts.map +1 -0
  148. package/dist/watchers/git.js +218 -0
  149. package/dist/watchers/git.js.map +1 -0
  150. package/dist/watchers/git.test.d.ts +2 -0
  151. package/dist/watchers/git.test.d.ts.map +1 -0
  152. package/dist/watchers/git.test.js +73 -0
  153. package/dist/watchers/git.test.js.map +1 -0
  154. package/dist/watchers/identity.d.ts +34 -0
  155. package/dist/watchers/identity.d.ts.map +1 -0
  156. package/dist/watchers/identity.js +85 -0
  157. package/dist/watchers/identity.js.map +1 -0
  158. package/dist/watchers/identity.test.d.ts +2 -0
  159. package/dist/watchers/identity.test.d.ts.map +1 -0
  160. package/dist/watchers/identity.test.js +48 -0
  161. package/dist/watchers/identity.test.js.map +1 -0
  162. package/dist/web-ui.test.d.ts +2 -0
  163. package/dist/web-ui.test.d.ts.map +1 -0
  164. package/dist/web-ui.test.js +312 -0
  165. package/dist/web-ui.test.js.map +1 -0
  166. package/node_modules/@estela/shared/dist/index.d.ts +3 -0
  167. package/node_modules/@estela/shared/dist/index.d.ts.map +1 -0
  168. package/node_modules/@estela/shared/dist/index.js +19 -0
  169. package/node_modules/@estela/shared/dist/index.js.map +1 -0
  170. package/node_modules/@estela/shared/dist/money.d.ts +71 -0
  171. package/node_modules/@estela/shared/dist/money.d.ts.map +1 -0
  172. package/node_modules/@estela/shared/dist/money.js +171 -0
  173. package/node_modules/@estela/shared/dist/money.js.map +1 -0
  174. package/node_modules/@estela/shared/dist/types.d.ts +365 -0
  175. package/node_modules/@estela/shared/dist/types.d.ts.map +1 -0
  176. package/node_modules/@estela/shared/dist/types.js +24 -0
  177. package/node_modules/@estela/shared/dist/types.js.map +1 -0
  178. package/node_modules/@estela/shared/package.json +5 -0
  179. package/package.json +41 -0
  180. package/web/app.css +749 -0
  181. package/web/app.js +1257 -0
  182. package/web/apple-touch-icon.png +0 -0
  183. package/web/favicon.png +0 -0
  184. package/web/index.html +132 -0
  185. package/web/lib.js +94 -0
  186. package/web/logo-mark.png +0 -0
@@ -0,0 +1,550 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.upsertClient = upsertClient;
4
+ exports.upsertProject = upsertProject;
5
+ exports.addRatePeriod = addRatePeriod;
6
+ exports.getClient = getClient;
7
+ exports.getProject = getProject;
8
+ exports.listProjects = listProjects;
9
+ exports.listClients = listClients;
10
+ exports.getRates = getRates;
11
+ exports.getProjectAuthors = getProjectAuthors;
12
+ exports.setProjectAuthors = setProjectAuthors;
13
+ exports.recordPublication = recordPublication;
14
+ exports.listPublications = listPublications;
15
+ exports.authorsByRepo = authorsByRepo;
16
+ exports.projectForRepo = projectForRepo;
17
+ exports.saveTurns = saveTurns;
18
+ exports.saveCommits = saveCommits;
19
+ exports.logScan = logScan;
20
+ exports.saveTimeEntry = saveTimeEntry;
21
+ exports.getTimeEntries = getTimeEntries;
22
+ exports.listEntriesBetween = listEntriesBetween;
23
+ exports.saveInvoice = saveInvoice;
24
+ exports.nextInvoiceNumber = nextInvoiceNumber;
25
+ exports.readInvoiceLines = readInvoiceLines;
26
+ exports.upsertSubscription = upsertSubscription;
27
+ exports.listSubscriptions = listSubscriptions;
28
+ exports.totalConsumptionByMonth = totalConsumptionByMonth;
29
+ exports.consumptionByProjectMonth = consumptionByProjectMonth;
30
+ exports.getCloudAccount = getCloudAccount;
31
+ exports.setCloudAccount = setCloudAccount;
32
+ exports.clearCloudAccount = clearCloudAccount;
33
+ exports.getProjectSync = getProjectSync;
34
+ exports.setProjectSync = setProjectSync;
35
+ exports.listTeamSyncedProjects = listTeamSyncedProjects;
36
+ exports.listPersonalSyncCandidates = listPersonalSyncCandidates;
37
+ exports.getAiConsent = getAiConsent;
38
+ exports.setAiConsent = setAiConsent;
39
+ const node_crypto_1 = require("node:crypto");
40
+ const shared_1 = require("@estela/shared");
41
+ const cost_js_1 = require("../pricing/cost.js");
42
+ const iso = (d) => d.toISOString();
43
+ // ---------------------------------------------------------------------------
44
+ // Clientes y proyectos
45
+ // ---------------------------------------------------------------------------
46
+ function upsertClient(db, client) {
47
+ db.prepare(`
48
+ INSERT INTO clients (id, name, currency, tax_id, email, address)
49
+ VALUES (?, ?, ?, ?, ?, ?)
50
+ ON CONFLICT(id) DO UPDATE SET
51
+ name = excluded.name, currency = excluded.currency,
52
+ tax_id = excluded.tax_id, email = excluded.email, address = excluded.address
53
+ `).run(client.id, client.name, client.currency, client.taxId ?? null, client.email ?? null, client.address ?? null);
54
+ }
55
+ function upsertProject(db, project) {
56
+ db.prepare(`
57
+ INSERT INTO projects (id, client_id, name, billable, rounding_minutes, ai_cost_policy, kind)
58
+ VALUES (?, ?, ?, ?, ?, ?, ?)
59
+ ON CONFLICT(id) DO UPDATE SET
60
+ client_id = excluded.client_id, name = excluded.name,
61
+ billable = excluded.billable, rounding_minutes = excluded.rounding_minutes,
62
+ ai_cost_policy = excluded.ai_cost_policy, kind = excluded.kind
63
+ `).run(project.id, project.clientId, project.name, project.billable ? 1 : 0, project.roundingMinutes, project.aiCostPolicy, project.kind);
64
+ const link = db.prepare("INSERT OR IGNORE INTO project_repos (project_id, repo_path) VALUES (?, ?)");
65
+ for (const repo of project.repoPaths)
66
+ link.run(project.id, repo);
67
+ }
68
+ function addRatePeriod(db, rate) {
69
+ // Cerrar la tarifa abierta anterior en la fecha en que empieza la nueva.
70
+ db.prepare(`
71
+ UPDATE rate_periods SET effective_to = ?
72
+ WHERE project_id = ? AND effective_to IS NULL AND effective_from < ?
73
+ `).run(iso(rate.effectiveFrom), rate.projectId, iso(rate.effectiveFrom));
74
+ db.prepare(`
75
+ INSERT INTO rate_periods (project_id, hourly_minor, currency, effective_from, effective_to)
76
+ VALUES (?, ?, ?, ?, ?)
77
+ `).run(rate.projectId, rate.hourlyRate.amount, rate.hourlyRate.currency, iso(rate.effectiveFrom), rate.effectiveTo ? iso(rate.effectiveTo) : null);
78
+ }
79
+ function getClient(db, id) {
80
+ const row = db.prepare("SELECT * FROM clients WHERE id = ?").get(id);
81
+ if (!row)
82
+ return null;
83
+ return {
84
+ id: row["id"],
85
+ name: row["name"],
86
+ currency: row["currency"],
87
+ ...(row["tax_id"] ? { taxId: row["tax_id"] } : {}),
88
+ ...(row["email"] ? { email: row["email"] } : {}),
89
+ ...(row["address"] ? { address: row["address"] } : {}),
90
+ };
91
+ }
92
+ function getProject(db, id) {
93
+ const row = db.prepare("SELECT * FROM projects WHERE id = ?").get(id);
94
+ if (!row)
95
+ return null;
96
+ const repos = db.prepare("SELECT repo_path FROM project_repos WHERE project_id = ?")
97
+ .all(id);
98
+ return {
99
+ id: row["id"],
100
+ clientId: row["client_id"],
101
+ name: row["name"],
102
+ repoPaths: repos.map((r) => r.repo_path),
103
+ billable: Boolean(row["billable"]),
104
+ roundingMinutes: row["rounding_minutes"],
105
+ aiCostPolicy: row["ai_cost_policy"],
106
+ kind: row["kind"] ?? "client",
107
+ };
108
+ }
109
+ function listProjects(db) {
110
+ const rows = db.prepare("SELECT id FROM projects ORDER BY name").all();
111
+ return rows.map((r) => getProject(db, r.id)).filter(Boolean);
112
+ }
113
+ function listClients(db) {
114
+ const rows = db.prepare("SELECT id FROM clients ORDER BY name").all();
115
+ return rows.map((r) => getClient(db, r.id)).filter(Boolean);
116
+ }
117
+ function getRates(db, projectId) {
118
+ const rows = db.prepare("SELECT * FROM rate_periods WHERE project_id = ? ORDER BY effective_from").all(projectId);
119
+ return rows.map((r) => ({
120
+ projectId: r["project_id"],
121
+ hourlyRate: { amount: r["hourly_minor"], currency: r["currency"] },
122
+ effectiveFrom: new Date(r["effective_from"]),
123
+ effectiveTo: r["effective_to"] ? new Date(r["effective_to"]) : null,
124
+ }));
125
+ }
126
+ /**
127
+ * Correos con los que commiteas en un proyecto.
128
+ *
129
+ * Vacío significa "sin configurar", y entonces se cae a la configuración de
130
+ * git. Es un mal apaño pero mejor que capturar los commits de todo el equipo:
131
+ * imputarte el trabajo de un compañero es peor que no imputar nada.
132
+ */
133
+ function getProjectAuthors(db, projectId) {
134
+ return db.prepare("SELECT author_email FROM project_authors WHERE project_id = ?")
135
+ .all(projectId).map((r) => r.author_email);
136
+ }
137
+ function setProjectAuthors(db, projectId, emails) {
138
+ db.exec("BEGIN");
139
+ try {
140
+ db.prepare("DELETE FROM project_authors WHERE project_id = ?").run(projectId);
141
+ const add = db.prepare("INSERT OR IGNORE INTO project_authors (project_id, author_email) VALUES (?, ?)");
142
+ for (const email of emails) {
143
+ // Sin normalizar a minúsculas: aquí puede haber un nombre de autor, no
144
+ // solo un correo, y git lo compara tal cual.
145
+ const clean = email.trim();
146
+ if (clean)
147
+ add.run(projectId, clean);
148
+ }
149
+ db.exec("COMMIT");
150
+ }
151
+ catch (error) {
152
+ db.exec("ROLLBACK");
153
+ throw error;
154
+ }
155
+ }
156
+ function recordPublication(db, projectId, token, baseUrl, at = new Date()) {
157
+ db.prepare(`
158
+ INSERT INTO publications (project_id, token, published_at, base_url)
159
+ VALUES (?, ?, ?, ?)
160
+ ON CONFLICT(project_id) DO UPDATE SET
161
+ token = excluded.token, published_at = excluded.published_at,
162
+ base_url = COALESCE(excluded.base_url, publications.base_url)
163
+ `).run(projectId, token, iso(at), baseUrl);
164
+ }
165
+ /**
166
+ * Estado de las publicaciones.
167
+ *
168
+ * `staleBlocks` cuenta el trabajo posterior a la última publicación. Es lo que
169
+ * de verdad envejece un panel: los días transcurridos no importan si en ese
170
+ * tiempo no tocaste el proyecto.
171
+ */
172
+ function listPublications(db) {
173
+ const rows = db.prepare("SELECT * FROM publications").all();
174
+ return rows.map((r) => {
175
+ const projectId = r["project_id"];
176
+ const publishedAt = r["published_at"];
177
+ const stale = db.prepare(`
178
+ SELECT COUNT(*) AS n, MAX(updated_at) AS last
179
+ FROM time_entries WHERE project_id = ? AND updated_at > ?
180
+ `).get(projectId, publishedAt);
181
+ return {
182
+ projectId,
183
+ token: r["token"],
184
+ publishedAt: new Date(publishedAt),
185
+ baseUrl: r["base_url"] ?? null,
186
+ staleBlocks: stale.n,
187
+ lastWorkAt: stale.last ? new Date(stale.last) : null,
188
+ };
189
+ });
190
+ }
191
+ /** Todos los correos configurados, por repositorio, para filtrar al importar. */
192
+ function authorsByRepo(db) {
193
+ const rows = db.prepare(`
194
+ SELECT r.repo_path, a.author_email
195
+ FROM project_repos r JOIN project_authors a ON a.project_id = r.project_id
196
+ `).all();
197
+ const map = new Map();
198
+ for (const row of rows) {
199
+ const list = map.get(row.repo_path);
200
+ if (list)
201
+ list.push(row.author_email);
202
+ else
203
+ map.set(row.repo_path, [row.author_email]);
204
+ }
205
+ return map;
206
+ }
207
+ /** Encuentra el proyecto al que pertenece una ruta de repositorio. */
208
+ function projectForRepo(db, repoPath) {
209
+ const rows = db.prepare("SELECT project_id, repo_path FROM project_repos")
210
+ .all();
211
+ // El prefijo más largo gana: permite anidar un subproyecto dentro de un monorepo.
212
+ const match = rows
213
+ .filter((r) => repoPath === r.repo_path || repoPath.startsWith(r.repo_path + "/"))
214
+ .sort((a, b) => b.repo_path.length - a.repo_path.length)[0];
215
+ return match?.project_id ?? null;
216
+ }
217
+ // ---------------------------------------------------------------------------
218
+ // Captura
219
+ // ---------------------------------------------------------------------------
220
+ /** Persiste turnos. `INSERT OR IGNORE` sobre la PK hace la dedup permanente. */
221
+ function saveTurns(db, turns) {
222
+ const stmt = db.prepare(`
223
+ INSERT OR IGNORE INTO agent_turns (
224
+ turn_id, agent, session_id, at, model, repo_path, branch,
225
+ tok_input, tok_output, tok_cache_read, tok_cache_w5m, tok_cache_w1h,
226
+ cost_micro_usd, producer_version
227
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
228
+ `);
229
+ let inserted = 0;
230
+ db.exec("BEGIN");
231
+ try {
232
+ for (const t of turns) {
233
+ const cost = (0, cost_js_1.costOfTurn)(t.tokens, t.model, t.at);
234
+ const result = stmt.run(t.turnId, t.agent, t.sessionId, iso(t.at), t.model, t.repoPath, t.branch, t.tokens.input, t.tokens.output, t.tokens.cacheRead, t.tokens.cacheWrite5m, t.tokens.cacheWrite1h, cost ? cost.microUsd : null, t.producerVersion);
235
+ inserted += Number(result.changes);
236
+ }
237
+ db.exec("COMMIT");
238
+ }
239
+ catch (error) {
240
+ db.exec("ROLLBACK");
241
+ throw error;
242
+ }
243
+ return inserted;
244
+ }
245
+ /**
246
+ * Guarda commits.
247
+ *
248
+ * El commit es inmutable, pero **nuestra lectura de él no lo es**: si un día se
249
+ * corrige el parser, reimportar tiene que poder rehacer los campos derivados.
250
+ * Con `INSERT OR IGNORE` los datos mal parseados se quedarían para siempre, sin
251
+ * forma de arreglarlos salvo borrando la base entera.
252
+ *
253
+ * Por eso hash y fecha se conservan (son la identidad) y las estadísticas se
254
+ * sobrescriben.
255
+ */
256
+ function saveCommits(db, commits) {
257
+ const stmt = db.prepare(`
258
+ INSERT INTO commits
259
+ (repo_path, hash, at, author_email, author_name, branch, subject,
260
+ lines_added, lines_deleted, files)
261
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
262
+ ON CONFLICT(repo_path, hash) DO UPDATE SET
263
+ subject = excluded.subject,
264
+ branch = excluded.branch,
265
+ author_name = excluded.author_name,
266
+ lines_added = excluded.lines_added,
267
+ lines_deleted = excluded.lines_deleted,
268
+ files = excluded.files
269
+ `);
270
+ let inserted = 0;
271
+ db.exec("BEGIN");
272
+ try {
273
+ for (const c of commits) {
274
+ const result = stmt.run(c.repoPath, c.hash, iso(c.at), c.authorEmail, c.authorName, c.branch, c.subject, c.linesAdded, c.linesDeleted, c.files.join("\n"));
275
+ inserted += Number(result.changes);
276
+ }
277
+ db.exec("COMMIT");
278
+ }
279
+ catch (error) {
280
+ db.exec("ROLLBACK");
281
+ throw error;
282
+ }
283
+ return inserted;
284
+ }
285
+ function logScan(db, source, report) {
286
+ db.prepare(`
287
+ INSERT INTO scan_log (
288
+ ran_at, source, files_read, records_seen, turns_accepted,
289
+ duplicates_dropped, unknown_records, malformed_records,
290
+ producer_versions, warnings
291
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
292
+ `).run(iso(new Date()), source, report.filesRead, report.recordsSeen, report.turnsAccepted, report.duplicatesDropped, report.unknownRecords, report.malformedRecords, report.producerVersions.join(","), report.warnings.join(" | "));
293
+ }
294
+ // ---------------------------------------------------------------------------
295
+ // Imputaciones y facturas
296
+ // ---------------------------------------------------------------------------
297
+ /**
298
+ * Guarda una imputación.
299
+ *
300
+ * `at` es la hora de escritura, no la del trabajo. Se puede pasar para que los
301
+ * tests no dependan del reloj: publicar y escribir en el mismo milisegundo hace
302
+ * que la comparación de desfase falle por empate.
303
+ */
304
+ function saveTimeEntry(db, entry, at = new Date()) {
305
+ const id = entry.id ?? `te_${(0, node_crypto_1.randomUUID)()}`;
306
+ db.prepare(`
307
+ INSERT INTO time_entries (
308
+ id, project_id, started_at, local_date, ended_at, seconds, description,
309
+ billable, approved, invoice_id, ai_micro_usd, agent_seconds,
310
+ commit_hashes, agents, source, kind, branch, updated_at
311
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?)
312
+ ON CONFLICT(id) DO UPDATE SET
313
+ started_at = excluded.started_at, local_date = excluded.local_date,
314
+ ended_at = excluded.ended_at,
315
+ seconds = excluded.seconds, description = excluded.description,
316
+ billable = excluded.billable, ai_micro_usd = excluded.ai_micro_usd,
317
+ -- Los commits también se rehacen. Sin esto, un bloque creado cuando
318
+ -- todavía no se capturaban los commits del proyecto se quedaba sin
319
+ -- ellos para siempre: la descripción se corregía al reimportar, pero
320
+ -- el respaldo que la justifica no aparecía nunca.
321
+ commit_hashes = excluded.commit_hashes,
322
+ agents = excluded.agents,
323
+ agent_seconds = excluded.agent_seconds,
324
+ -- La procedencia también se rehace: un bloque deducido de commits pasa a
325
+ -- 'agent' en cuanto aparece el transcript que lo cubre, y al revés. Sin
326
+ -- esto, una fila mal etiquetada lo seguiría estando para siempre.
327
+ source = excluded.source,
328
+ branch = excluded.branch,
329
+ -- Solo se marca como tocada si algo cambió de verdad: un reimport que
330
+ -- reescribe los mismos valores no debería envejecer un panel publicado.
331
+ updated_at = CASE
332
+ WHEN time_entries.seconds <> excluded.seconds
333
+ OR time_entries.description <> excluded.description
334
+ OR time_entries.commit_hashes <> excluded.commit_hashes
335
+ THEN excluded.updated_at ELSE time_entries.updated_at END
336
+ -- Reimportar rehace lo deducido de los agentes. Lo escrito a mano es tuyo:
337
+ -- un import no puede borrarte una reunión de dos horas que apuntaste ayer.
338
+ WHERE time_entries.source IN ('agent', 'commit')
339
+ `).run(id, entry.projectId, iso(entry.startedAt), (0, shared_1.localDate)(entry.startedAt), iso(entry.endedAt), entry.seconds, entry.description, entry.billable ? 1 : 0, entry.invoiceId, entry.aiCost.microUsd, entry.agentSeconds, entry.commitHashes.join(","), entry.agents.join(","), entry.source, entry.kind, entry.branch, iso(at));
340
+ return id;
341
+ }
342
+ function getTimeEntries(db, projectId) {
343
+ const rows = db.prepare("SELECT * FROM time_entries WHERE project_id = ? ORDER BY started_at").all(projectId);
344
+ return rows.map(rowToEntry);
345
+ }
346
+ /**
347
+ * Imputaciones de un rango de fechas.
348
+ *
349
+ * Filtra por `local_date` y no por `started_at`: la fecha en que trabajaste es
350
+ * la de tu reloj, no la de Greenwich. Un bloque de las 23:20 pertenece a hoy
351
+ * aunque en UTC ya sea mañana.
352
+ */
353
+ function listEntriesBetween(db, from, to) {
354
+ const rows = db.prepare("SELECT * FROM time_entries WHERE local_date >= ? AND local_date <= ? ORDER BY started_at").all(from, to);
355
+ return rows.map(rowToEntry);
356
+ }
357
+ function rowToEntry(r) {
358
+ return ({
359
+ id: r["id"],
360
+ projectId: r["project_id"],
361
+ startedAt: new Date(r["started_at"]),
362
+ endedAt: new Date(r["ended_at"]),
363
+ seconds: r["seconds"],
364
+ description: r["description"],
365
+ billable: Boolean(r["billable"]),
366
+ invoiceId: r["invoice_id"] ?? null,
367
+ aiCost: { microUsd: r["ai_micro_usd"] },
368
+ agentSeconds: r["agent_seconds"],
369
+ commitHashes: String(r["commit_hashes"] || "").split(",").filter(Boolean),
370
+ agents: String(r["agents"] || "").split(",").filter(Boolean),
371
+ source: r["source"] ?? "agent",
372
+ kind: r["kind"] ?? "development",
373
+ branch: r["branch"] ?? null,
374
+ });
375
+ }
376
+ /** Guarda la factura y marca sus imputaciones. Todo o nada. */
377
+ function saveInvoice(db, invoice, entryIds) {
378
+ db.exec("BEGIN");
379
+ try {
380
+ db.prepare(`
381
+ INSERT INTO invoices (
382
+ id, number, client_id, project_id, issued_at, cutoff_at, period_start,
383
+ currency, subtotal_minor, total_minor, total_seconds, ai_micro_usd,
384
+ usd_fx_rate, ai_billed_minor, ai_amort_minor, ai_amort_cur, notes, lines_json
385
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
386
+ `).run(invoice.id, invoice.number, invoice.clientId, invoice.projectId, iso(invoice.issuedAt), iso(invoice.cutoffAt), iso(invoice.periodStart), invoice.currency, invoice.subtotal.amount, invoice.total.amount, invoice.totalSeconds, invoice.aiCost.microUsd, invoice.usdFxRate, invoice.aiCostBilled?.amount ?? null, invoice.aiAmortized?.amount ?? null, invoice.aiAmortized?.currency ?? null, invoice.notes ?? null, JSON.stringify(invoice.lines));
387
+ const mark = db.prepare("UPDATE time_entries SET invoice_id = ? WHERE id = ?");
388
+ for (const id of entryIds)
389
+ mark.run(invoice.id, id);
390
+ db.exec("COMMIT");
391
+ }
392
+ catch (error) {
393
+ db.exec("ROLLBACK");
394
+ throw error;
395
+ }
396
+ }
397
+ function nextInvoiceNumber(db, prefix) {
398
+ const year = new Date().getFullYear();
399
+ const row = db.prepare("SELECT COUNT(*) AS n FROM invoices WHERE number LIKE ?").get(`${prefix}-${year}-%`);
400
+ return `${prefix}-${year}-${String(row.n + 1).padStart(3, "0")}`;
401
+ }
402
+ function readInvoiceLines(json) {
403
+ return JSON.parse(json);
404
+ }
405
+ // ---------------------------------------------------------------------------
406
+ // Suscripciones
407
+ // ---------------------------------------------------------------------------
408
+ function upsertSubscription(db, sub) {
409
+ db.prepare(`
410
+ INSERT INTO subscriptions (id, name, fee_minor, currency, effective_from, effective_to)
411
+ VALUES (?, ?, ?, ?, ?, ?)
412
+ ON CONFLICT(id) DO UPDATE SET
413
+ name = excluded.name, fee_minor = excluded.fee_minor,
414
+ currency = excluded.currency, effective_from = excluded.effective_from,
415
+ effective_to = excluded.effective_to
416
+ `).run(sub.id, sub.name, sub.monthlyFee.amount, sub.monthlyFee.currency, iso(sub.effectiveFrom), sub.effectiveTo ? iso(sub.effectiveTo) : null);
417
+ }
418
+ function listSubscriptions(db) {
419
+ const rows = db.prepare("SELECT * FROM subscriptions ORDER BY effective_from")
420
+ .all();
421
+ return rows.map((r) => ({
422
+ id: r["id"],
423
+ name: r["name"],
424
+ monthlyFee: { amount: r["fee_minor"], currency: r["currency"] },
425
+ effectiveFrom: new Date(r["effective_from"]),
426
+ effectiveTo: r["effective_to"] ? new Date(r["effective_to"]) : null,
427
+ }));
428
+ }
429
+ /**
430
+ * Consumo total del mes en toda la máquina, esté asignado a un proyecto o no.
431
+ *
432
+ * Es el denominador correcto para repartir una cuota fija: la pagaste entera,
433
+ * la usaras donde la usaras. Se lee de `agent_turns` y no de `time_entries`
434
+ * porque ahí está *todo* tu consumo, incluidos los repos que aún no configuraste.
435
+ */
436
+ function totalConsumptionByMonth(db) {
437
+ const rows = db.prepare(`
438
+ SELECT substr(at, 1, 7) AS month, SUM(COALESCE(cost_micro_usd, 0)) AS micro
439
+ FROM agent_turns
440
+ GROUP BY month
441
+ `).all();
442
+ return new Map(rows.map((r) => [r.month, { microUsd: r.micro ?? 0 }]));
443
+ }
444
+ /** Consumo por proyecto y mes, sobre las imputaciones ya asignadas. */
445
+ function consumptionByProjectMonth(db) {
446
+ const rows = db.prepare(`
447
+ SELECT project_id, substr(started_at, 1, 7) AS month, SUM(ai_micro_usd) AS micro
448
+ FROM time_entries
449
+ GROUP BY project_id, month
450
+ `).all();
451
+ return rows.map((r) => ({
452
+ projectId: r.project_id,
453
+ month: r.month,
454
+ consumption: { microUsd: r.micro ?? 0 },
455
+ }));
456
+ }
457
+ // ---------------------------------------------------------------------------
458
+ // Cuenta cloud, alcance de sincronización y consentimiento de IA
459
+ // ---------------------------------------------------------------------------
460
+ /** La cuenta cloud vinculada a esta máquina, o null si todo sigue local. */
461
+ function getCloudAccount(db) {
462
+ const row = db.prepare("SELECT * FROM cloud_account WHERE id = 'local'")
463
+ .get();
464
+ if (!row)
465
+ return null;
466
+ return {
467
+ accountId: row["account_id"],
468
+ email: row["email"],
469
+ plan: row["plan"],
470
+ deviceToken: row["device_token"],
471
+ apiBaseUrl: row["api_base_url"],
472
+ linkedAt: new Date(row["linked_at"]),
473
+ };
474
+ }
475
+ function setCloudAccount(db, account) {
476
+ db.prepare(`
477
+ INSERT INTO cloud_account (id, account_id, email, plan, device_token, api_base_url, linked_at)
478
+ VALUES ('local', ?, ?, ?, ?, ?, ?)
479
+ ON CONFLICT(id) DO UPDATE SET
480
+ account_id = excluded.account_id, email = excluded.email, plan = excluded.plan,
481
+ device_token = excluded.device_token, api_base_url = excluded.api_base_url,
482
+ linked_at = excluded.linked_at
483
+ `).run(account.accountId, account.email, account.plan, account.deviceToken, account.apiBaseUrl, iso(account.linkedAt));
484
+ }
485
+ /** `estela logout`. Borra el vínculo cloud; los datos locales no se tocan. */
486
+ function clearCloudAccount(db) {
487
+ db.prepare("DELETE FROM cloud_account WHERE id = 'local'").run();
488
+ }
489
+ function getProjectSync(db, projectId) {
490
+ const row = db.prepare("SELECT * FROM project_sync WHERE project_id = ?")
491
+ .get(projectId);
492
+ if (!row)
493
+ return null;
494
+ return {
495
+ projectId: row["project_id"],
496
+ scope: row["scope"],
497
+ remoteProjectId: row["remote_project_id"],
498
+ remoteOrgId: row["remote_org_id"] ?? null,
499
+ inviteToken: row["invite_token"] ?? null,
500
+ };
501
+ }
502
+ function setProjectSync(db, sync) {
503
+ db.prepare(`
504
+ INSERT INTO project_sync (project_id, scope, remote_project_id, remote_org_id, invite_token)
505
+ VALUES (?, ?, ?, ?, ?)
506
+ ON CONFLICT(project_id) DO UPDATE SET
507
+ scope = excluded.scope, remote_project_id = excluded.remote_project_id,
508
+ remote_org_id = excluded.remote_org_id, invite_token = excluded.invite_token
509
+ `).run(sync.projectId, sync.scope, sync.remoteProjectId, sync.remoteOrgId, sync.inviteToken);
510
+ }
511
+ /** Proyectos de equipo enlazados en esta máquina — lo único que sube `sync/team.ts`. */
512
+ function listTeamSyncedProjects(db) {
513
+ const rows = db.prepare("SELECT project_id FROM project_sync WHERE scope = 'team'")
514
+ .all();
515
+ return rows.map((r) => getProjectSync(db, r.project_id)).filter(Boolean);
516
+ }
517
+ /**
518
+ * Proyectos candidatos al sync personal (Pro): todos menos los que ya están
519
+ * enlazados a un equipo. Es la guardia anti-fuga: un proyecto de equipo nunca
520
+ * puede colarse también como sync personal, porque `project_sync.project_id`
521
+ * es su clave primaria — un proyecto tiene un único alcance.
522
+ */
523
+ function listPersonalSyncCandidates(db) {
524
+ const rows = db.prepare(`
525
+ SELECT id FROM projects
526
+ WHERE id NOT IN (SELECT project_id FROM project_sync WHERE scope = 'team')
527
+ `).all();
528
+ return rows.map((r) => r.id);
529
+ }
530
+ function getAiConsent(db, projectId) {
531
+ const row = db.prepare("SELECT * FROM ai_consent WHERE project_id = ?")
532
+ .get(projectId);
533
+ if (!row)
534
+ return null;
535
+ return {
536
+ projectId: row["project_id"],
537
+ requested: Boolean(row["requested"]),
538
+ decision: row["decision"],
539
+ decidedAt: row["decided_at"] ? new Date(row["decided_at"]) : null,
540
+ };
541
+ }
542
+ function setAiConsent(db, projectId, requested, decision) {
543
+ db.prepare(`
544
+ INSERT INTO ai_consent (project_id, requested, decision, decided_at)
545
+ VALUES (?, ?, ?, ?)
546
+ ON CONFLICT(project_id) DO UPDATE SET
547
+ requested = excluded.requested, decision = excluded.decision, decided_at = excluded.decided_at
548
+ `).run(projectId, requested ? 1 : 0, decision, decision === "pending" ? null : iso(new Date()));
549
+ }
550
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/db/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ /**
3
+ * Revisión de los datos antes de publicar.
4
+ *
5
+ * Existe porque el fallo que arruina una demo no es una gráfica fea: es una
6
+ * cifra que no cuadra delante del cliente. Cada comprobación de aquí
7
+ * corresponde a un fallo que ya ocurrió de verdad — un proyecto sin autor
8
+ * configurado capturando 3 commits de 1697, filas duplicadas por mezclar UTC
9
+ * con hora local, modelos sin precio sumando cero en silencio.
10
+ *
11
+ * Todo lo que avisa tiene arreglo y dice cuál. Un diagnóstico sin remedio solo
12
+ * genera ansiedad.
13
+ */
14
+ export type Severity = "error" | "warning" | "info";
15
+ export interface Finding {
16
+ readonly severity: Severity;
17
+ readonly title: string;
18
+ readonly detail: string;
19
+ /** Qué hacer. Sin esto, avisar solo preocupa. */
20
+ readonly fix: string;
21
+ }
22
+ export declare function diagnose(db: DatabaseSync): Finding[];
23
+ export declare function renderFindings(findings: readonly Finding[]): string;
24
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,YAAY,GAAG,OAAO,EAAE,CA6LpD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAyBnE"}