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.
- package/README.md +138 -0
- package/dist/billing/amortize.d.ts +44 -0
- package/dist/billing/amortize.d.ts.map +1 -0
- package/dist/billing/amortize.js +83 -0
- package/dist/billing/amortize.js.map +1 -0
- package/dist/billing/amortize.test.d.ts +2 -0
- package/dist/billing/amortize.test.d.ts.map +1 -0
- package/dist/billing/amortize.test.js +121 -0
- package/dist/billing/amortize.test.js.map +1 -0
- package/dist/billing/format.test.d.ts +2 -0
- package/dist/billing/format.test.d.ts.map +1 -0
- package/dist/billing/format.test.js +110 -0
- package/dist/billing/format.test.js.map +1 -0
- package/dist/billing/invoice.d.ts +52 -0
- package/dist/billing/invoice.d.ts.map +1 -0
- package/dist/billing/invoice.js +148 -0
- package/dist/billing/invoice.js.map +1 -0
- package/dist/billing/invoice.test.d.ts +2 -0
- package/dist/billing/invoice.test.d.ts.map +1 -0
- package/dist/billing/invoice.test.js +200 -0
- package/dist/billing/invoice.test.js.map +1 -0
- package/dist/billing/sessionize.d.ts +104 -0
- package/dist/billing/sessionize.d.ts.map +1 -0
- package/dist/billing/sessionize.js +0 -0
- package/dist/billing/sessionize.js.map +1 -0
- package/dist/billing/sessionize.test.d.ts +2 -0
- package/dist/billing/sessionize.test.d.ts.map +1 -0
- package/dist/billing/sessionize.test.js +67 -0
- package/dist/billing/sessionize.test.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1091 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloud/auth.d.ts +4 -0
- package/dist/cloud/auth.d.ts.map +1 -0
- package/dist/cloud/auth.js +98 -0
- package/dist/cloud/auth.js.map +1 -0
- package/dist/cloud/client.d.ts +12 -0
- package/dist/cloud/client.d.ts.map +1 -0
- package/dist/cloud/client.js +34 -0
- package/dist/cloud/client.js.map +1 -0
- package/dist/db/schema.d.ts +11 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +424 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/schema.test.d.ts +2 -0
- package/dist/db/schema.test.d.ts.map +1 -0
- package/dist/db/schema.test.js +335 -0
- package/dist/db/schema.test.js.map +1 -0
- package/dist/db/store.d.ts +113 -0
- package/dist/db/store.d.ts.map +1 -0
- package/dist/db/store.js +550 -0
- package/dist/db/store.js.map +1 -0
- package/dist/doctor.d.ts +24 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +229 -0
- package/dist/doctor.js.map +1 -0
- package/dist/export/csv.d.ts +9 -0
- package/dist/export/csv.d.ts.map +1 -0
- package/dist/export/csv.js +81 -0
- package/dist/export/csv.js.map +1 -0
- package/dist/export/invoice-pdf.d.ts +21 -0
- package/dist/export/invoice-pdf.d.ts.map +1 -0
- package/dist/export/invoice-pdf.js +135 -0
- package/dist/export/invoice-pdf.js.map +1 -0
- package/dist/export/panel.d.ts +78 -0
- package/dist/export/panel.d.ts.map +1 -0
- package/dist/export/panel.js +693 -0
- package/dist/export/panel.js.map +1 -0
- package/dist/export/panel.test.d.ts +2 -0
- package/dist/export/panel.test.d.ts.map +1 -0
- package/dist/export/panel.test.js +273 -0
- package/dist/export/panel.test.js.map +1 -0
- package/dist/export/pdf.d.ts +32 -0
- package/dist/export/pdf.d.ts.map +1 -0
- package/dist/export/pdf.js +229 -0
- package/dist/export/pdf.js.map +1 -0
- package/dist/export/pdf.test.d.ts +2 -0
- package/dist/export/pdf.test.d.ts.map +1 -0
- package/dist/export/pdf.test.js +151 -0
- package/dist/export/pdf.test.js.map +1 -0
- package/dist/export/share.d.ts +42 -0
- package/dist/export/share.d.ts.map +1 -0
- package/dist/export/share.js +181 -0
- package/dist/export/share.js.map +1 -0
- package/dist/export/share.test.d.ts +2 -0
- package/dist/export/share.test.d.ts.map +1 -0
- package/dist/export/share.test.js +116 -0
- package/dist/export/share.test.js.map +1 -0
- package/dist/metrics/index.d.ts +101 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +221 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/metrics.test.d.ts +2 -0
- package/dist/metrics/metrics.test.d.ts.map +1 -0
- package/dist/metrics/metrics.test.js +162 -0
- package/dist/metrics/metrics.test.js.map +1 -0
- package/dist/metrics/people.d.ts +46 -0
- package/dist/metrics/people.d.ts.map +1 -0
- package/dist/metrics/people.js +126 -0
- package/dist/metrics/people.js.map +1 -0
- package/dist/metrics/people.test.d.ts +2 -0
- package/dist/metrics/people.test.d.ts.map +1 -0
- package/dist/metrics/people.test.js +84 -0
- package/dist/metrics/people.test.js.map +1 -0
- package/dist/metrics/team.d.ts +41 -0
- package/dist/metrics/team.d.ts.map +1 -0
- package/dist/metrics/team.js +0 -0
- package/dist/metrics/team.js.map +1 -0
- package/dist/metrics/team.test.d.ts +2 -0
- package/dist/metrics/team.test.d.ts.map +1 -0
- package/dist/metrics/team.test.js +90 -0
- package/dist/metrics/team.test.js.map +1 -0
- package/dist/pricing/catalog.d.ts +39 -0
- package/dist/pricing/catalog.d.ts.map +1 -0
- package/dist/pricing/catalog.js +59 -0
- package/dist/pricing/catalog.js.map +1 -0
- package/dist/pricing/cost.d.ts +25 -0
- package/dist/pricing/cost.d.ts.map +1 -0
- package/dist/pricing/cost.js +50 -0
- package/dist/pricing/cost.js.map +1 -0
- package/dist/pricing/cost.test.d.ts +2 -0
- package/dist/pricing/cost.test.d.ts.map +1 -0
- package/dist/pricing/cost.test.js +74 -0
- package/dist/pricing/cost.test.js.map +1 -0
- package/dist/server.d.ts +15 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1141 -0
- package/dist/server.js.map +1 -0
- package/dist/setup.d.ts +70 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +223 -0
- package/dist/setup.js.map +1 -0
- package/dist/setup.test.d.ts +2 -0
- package/dist/setup.test.d.ts.map +1 -0
- package/dist/setup.test.js +131 -0
- package/dist/setup.test.js.map +1 -0
- package/dist/watchers/claude.d.ts +34 -0
- package/dist/watchers/claude.d.ts.map +1 -0
- package/dist/watchers/claude.js +235 -0
- package/dist/watchers/claude.js.map +1 -0
- package/dist/watchers/claude.test.d.ts +2 -0
- package/dist/watchers/claude.test.d.ts.map +1 -0
- package/dist/watchers/claude.test.js +180 -0
- package/dist/watchers/claude.test.js.map +1 -0
- package/dist/watchers/git.d.ts +42 -0
- package/dist/watchers/git.d.ts.map +1 -0
- package/dist/watchers/git.js +218 -0
- package/dist/watchers/git.js.map +1 -0
- package/dist/watchers/git.test.d.ts +2 -0
- package/dist/watchers/git.test.d.ts.map +1 -0
- package/dist/watchers/git.test.js +73 -0
- package/dist/watchers/git.test.js.map +1 -0
- package/dist/watchers/identity.d.ts +34 -0
- package/dist/watchers/identity.d.ts.map +1 -0
- package/dist/watchers/identity.js +85 -0
- package/dist/watchers/identity.js.map +1 -0
- package/dist/watchers/identity.test.d.ts +2 -0
- package/dist/watchers/identity.test.d.ts.map +1 -0
- package/dist/watchers/identity.test.js +48 -0
- package/dist/watchers/identity.test.js.map +1 -0
- package/dist/web-ui.test.d.ts +2 -0
- package/dist/web-ui.test.d.ts.map +1 -0
- package/dist/web-ui.test.js +312 -0
- package/dist/web-ui.test.js.map +1 -0
- package/node_modules/@estela/shared/dist/index.d.ts +3 -0
- package/node_modules/@estela/shared/dist/index.d.ts.map +1 -0
- package/node_modules/@estela/shared/dist/index.js +19 -0
- package/node_modules/@estela/shared/dist/index.js.map +1 -0
- package/node_modules/@estela/shared/dist/money.d.ts +71 -0
- package/node_modules/@estela/shared/dist/money.d.ts.map +1 -0
- package/node_modules/@estela/shared/dist/money.js +171 -0
- package/node_modules/@estela/shared/dist/money.js.map +1 -0
- package/node_modules/@estela/shared/dist/types.d.ts +365 -0
- package/node_modules/@estela/shared/dist/types.d.ts.map +1 -0
- package/node_modules/@estela/shared/dist/types.js +24 -0
- package/node_modules/@estela/shared/dist/types.js.map +1 -0
- package/node_modules/@estela/shared/package.json +5 -0
- package/package.json +41 -0
- package/web/app.css +749 -0
- package/web/app.js +1257 -0
- package/web/apple-touch-icon.png +0 -0
- package/web/favicon.png +0 -0
- package/web/index.html +132 -0
- package/web/lib.js +94 -0
- package/web/logo-mark.png +0 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
40
|
+
const node_sqlite_1 = require("node:sqlite");
|
|
41
|
+
const node_fs_1 = require("node:fs");
|
|
42
|
+
const node_os_1 = require("node:os");
|
|
43
|
+
const node_path_1 = require("node:path");
|
|
44
|
+
const node_test_1 = require("node:test");
|
|
45
|
+
const schema_js_1 = require("./schema.js");
|
|
46
|
+
const store = __importStar(require("./store.js"));
|
|
47
|
+
function tempDb() {
|
|
48
|
+
return (0, node_path_1.join)((0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "estela-db-")), "estela.db");
|
|
49
|
+
}
|
|
50
|
+
function seedProject(db) {
|
|
51
|
+
store.upsertClient(db, { id: "c", name: "Cliente", currency: "EUR" });
|
|
52
|
+
store.upsertProject(db, {
|
|
53
|
+
id: "p", clientId: "c", name: "Proyecto", repoPaths: ["/repo"],
|
|
54
|
+
billable: true, roundingMinutes: 0, aiCostPolicy: "absorbed", kind: "client",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function entry(over = {}) {
|
|
58
|
+
const startedAt = new Date("2026-08-25T10:00:00Z");
|
|
59
|
+
return {
|
|
60
|
+
projectId: "p", startedAt,
|
|
61
|
+
endedAt: new Date(startedAt.getTime() + 3600_000),
|
|
62
|
+
seconds: 3600, description: "Bloque", billable: true, invoiceId: null,
|
|
63
|
+
aiCost: { microUsd: 0 }, agentSeconds: 0, commitHashes: [], agents: [],
|
|
64
|
+
source: "agent", kind: "development", branch: "main",
|
|
65
|
+
...over,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// ── Migraciones ────────────────────────────────────────────────────────
|
|
69
|
+
(0, node_test_1.test)("una base antigua se migra en vez de reventar", () => {
|
|
70
|
+
// El fallo que esto previene: CREATE TABLE IF NOT EXISTS no añade columnas a
|
|
71
|
+
// una tabla que ya existe. La sentencia no hace nada y la app peta al primer
|
|
72
|
+
// INSERT con "table has no column named source".
|
|
73
|
+
const path = tempDb();
|
|
74
|
+
// Simula una base v1: sin las columnas source ni kind.
|
|
75
|
+
const old = new node_sqlite_1.DatabaseSync(path);
|
|
76
|
+
old.exec(`
|
|
77
|
+
CREATE TABLE schema_version (version INTEGER NOT NULL);
|
|
78
|
+
INSERT INTO schema_version VALUES (1);
|
|
79
|
+
CREATE TABLE clients (id TEXT PRIMARY KEY, name TEXT NOT NULL, currency TEXT NOT NULL,
|
|
80
|
+
tax_id TEXT, email TEXT, address TEXT);
|
|
81
|
+
CREATE TABLE projects (id TEXT PRIMARY KEY, client_id TEXT NOT NULL, name TEXT NOT NULL,
|
|
82
|
+
billable INTEGER NOT NULL DEFAULT 1,
|
|
83
|
+
rounding_minutes INTEGER NOT NULL DEFAULT 0,
|
|
84
|
+
ai_cost_policy TEXT NOT NULL DEFAULT 'absorbed');
|
|
85
|
+
CREATE TABLE time_entries (
|
|
86
|
+
id TEXT PRIMARY KEY, project_id TEXT NOT NULL, started_at TEXT NOT NULL,
|
|
87
|
+
local_date TEXT NOT NULL DEFAULT '', ended_at TEXT NOT NULL, seconds INTEGER NOT NULL,
|
|
88
|
+
description TEXT NOT NULL, billable INTEGER NOT NULL DEFAULT 1,
|
|
89
|
+
approved INTEGER NOT NULL DEFAULT 0, invoice_id TEXT,
|
|
90
|
+
ai_micro_usd INTEGER NOT NULL DEFAULT 0, agent_seconds INTEGER NOT NULL DEFAULT 0,
|
|
91
|
+
commit_hashes TEXT NOT NULL DEFAULT '', agents TEXT NOT NULL DEFAULT '');
|
|
92
|
+
INSERT INTO clients VALUES ('c','Cliente','EUR',NULL,NULL,NULL);
|
|
93
|
+
INSERT INTO projects VALUES ('p','c','Proyecto',1,0,'absorbed');
|
|
94
|
+
INSERT INTO time_entries VALUES
|
|
95
|
+
('viejo','p','2026-07-01T10:00:00Z','2026-07-01','2026-07-01T11:00:00Z',
|
|
96
|
+
3600,'Trabajo anterior',1,0,NULL,0,0,'','');
|
|
97
|
+
`);
|
|
98
|
+
old.close();
|
|
99
|
+
const db = (0, schema_js_1.openDatabase)(path);
|
|
100
|
+
try {
|
|
101
|
+
const columns = db.prepare("PRAGMA table_info(time_entries)").all()
|
|
102
|
+
.map((c) => c.name);
|
|
103
|
+
strict_1.default.ok(columns.includes("source"), "la migración añadió source");
|
|
104
|
+
strict_1.default.ok(columns.includes("kind"), "la migración añadió kind");
|
|
105
|
+
const version = db.prepare("SELECT version FROM schema_version").get();
|
|
106
|
+
strict_1.default.equal(version.version, 2);
|
|
107
|
+
// Lo que ya había sigue ahí. Migrar no puede perder el trabajo de meses.
|
|
108
|
+
const previo = db.prepare("SELECT * FROM time_entries WHERE id='viejo'")
|
|
109
|
+
.get();
|
|
110
|
+
strict_1.default.ok(previo, "la fila anterior sobrevive");
|
|
111
|
+
strict_1.default.equal(previo["description"], "Trabajo anterior");
|
|
112
|
+
strict_1.default.equal(previo["source"], "agent", "las filas viejas quedan como 'agent'");
|
|
113
|
+
// Y ahora sí se puede escribir con los campos nuevos.
|
|
114
|
+
seedProject(db);
|
|
115
|
+
strict_1.default.doesNotThrow(() => store.saveTimeEntry(db, entry({ source: "manual" })));
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
db.close();
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
(0, node_test_1.test)("abrir dos veces la misma base no vuelve a migrar ni falla", () => {
|
|
122
|
+
const path = tempDb();
|
|
123
|
+
(0, schema_js_1.openDatabase)(path).close();
|
|
124
|
+
strict_1.default.doesNotThrow(() => (0, schema_js_1.openDatabase)(path).close());
|
|
125
|
+
});
|
|
126
|
+
(0, node_test_1.test)("una base de una versión futura se rechaza en vez de corromperse", () => {
|
|
127
|
+
const path = tempDb();
|
|
128
|
+
const db = (0, schema_js_1.openDatabase)(path);
|
|
129
|
+
db.prepare("UPDATE schema_version SET version = ?").run(999);
|
|
130
|
+
db.close();
|
|
131
|
+
strict_1.default.throws(() => (0, schema_js_1.openDatabase)(path), /v999|Actualiza Estela/);
|
|
132
|
+
});
|
|
133
|
+
// ── Lo escrito a mano es intocable ─────────────────────────────────────
|
|
134
|
+
(0, node_test_1.test)("reimportar NO pisa una imputación manual", () => {
|
|
135
|
+
// Reunión de dos horas apuntada a mano el lunes. El martes se reimporta y
|
|
136
|
+
// el bloque deducido de los agentes cae con el mismo id determinista.
|
|
137
|
+
const db = (0, schema_js_1.openDatabase)(":memory:");
|
|
138
|
+
try {
|
|
139
|
+
seedProject(db);
|
|
140
|
+
const id = "te_p_2026-08-25_main";
|
|
141
|
+
store.saveTimeEntry(db, {
|
|
142
|
+
...entry({ source: "manual", kind: "meeting", seconds: 7200,
|
|
143
|
+
description: "Reunión con el cliente" }),
|
|
144
|
+
id,
|
|
145
|
+
});
|
|
146
|
+
// El import intenta sobrescribir esa misma fila.
|
|
147
|
+
store.saveTimeEntry(db, {
|
|
148
|
+
...entry({ source: "agent", seconds: 600, description: "Desarrollo en main" }),
|
|
149
|
+
id,
|
|
150
|
+
});
|
|
151
|
+
const row = db.prepare("SELECT * FROM time_entries WHERE id = ?")
|
|
152
|
+
.get(id);
|
|
153
|
+
strict_1.default.equal(row["description"], "Reunión con el cliente", "el texto manual se conserva");
|
|
154
|
+
strict_1.default.equal(row["seconds"], 7200, "las 2 horas apuntadas se conservan");
|
|
155
|
+
strict_1.default.equal(row["kind"], "meeting");
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
db.close();
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
(0, node_test_1.test)("reimportar sí actualiza lo deducido de los agentes", () => {
|
|
162
|
+
const db = (0, schema_js_1.openDatabase)(":memory:");
|
|
163
|
+
try {
|
|
164
|
+
seedProject(db);
|
|
165
|
+
const id = "te_p_2026-08-25_main";
|
|
166
|
+
store.saveTimeEntry(db, { ...entry({ seconds: 600, description: "Primera lectura" }), id });
|
|
167
|
+
store.saveTimeEntry(db, { ...entry({ seconds: 3600, description: "Lectura corregida" }), id });
|
|
168
|
+
const row = db.prepare("SELECT * FROM time_entries WHERE id = ?")
|
|
169
|
+
.get(id);
|
|
170
|
+
strict_1.default.equal(row["seconds"], 3600, "lo deducido sí se rehace");
|
|
171
|
+
strict_1.default.equal(row["description"], "Lectura corregida");
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
db.close();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
(0, node_test_1.test)("las horas manuales no traen coste de IA ni commits", () => {
|
|
178
|
+
const db = (0, schema_js_1.openDatabase)(":memory:");
|
|
179
|
+
try {
|
|
180
|
+
seedProject(db);
|
|
181
|
+
const id = store.saveTimeEntry(db, entry({ source: "manual", kind: "travel" }));
|
|
182
|
+
const saved = store.getTimeEntries(db, "p").find((e) => e.id === id);
|
|
183
|
+
strict_1.default.equal(saved.aiCost.microUsd, 0);
|
|
184
|
+
strict_1.default.deepEqual(saved.commitHashes, []);
|
|
185
|
+
strict_1.default.equal(saved.kind, "travel");
|
|
186
|
+
strict_1.default.equal(saved.source, "manual");
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
db.close();
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
(0, node_test_1.test)("reimportar rehace los commits de un bloque, no solo su texto", () => {
|
|
193
|
+
// El fallo que esto previene: un bloque creado cuando aún no se capturaban
|
|
194
|
+
// los commits del proyecto se quedaba sin ellos para siempre. El ON CONFLICT
|
|
195
|
+
// actualizaba la descripción pero no commit_hashes, así que el respaldo que
|
|
196
|
+
// justifica esa línea de la factura no aparecía nunca.
|
|
197
|
+
const db = (0, schema_js_1.openDatabase)(":memory:");
|
|
198
|
+
try {
|
|
199
|
+
seedProject(db);
|
|
200
|
+
const id = "te_p_2026-08-26_main";
|
|
201
|
+
// Primer import: el autor no estaba configurado, no hay commits.
|
|
202
|
+
store.saveTimeEntry(db, {
|
|
203
|
+
...entry({ description: "Desarrollo en main", commitHashes: [] }), id,
|
|
204
|
+
});
|
|
205
|
+
// Segundo import, ya con el autor correcto.
|
|
206
|
+
store.saveTimeEntry(db, {
|
|
207
|
+
...entry({ description: "feat: filtro de Canarias", commitHashes: ["b942998abe"] }), id,
|
|
208
|
+
});
|
|
209
|
+
const saved = store.getTimeEntries(db, "p").find((e) => e.id === id);
|
|
210
|
+
strict_1.default.equal(saved.description, "feat: filtro de Canarias");
|
|
211
|
+
strict_1.default.deepEqual(saved.commitHashes, ["b942998abe"], "los commits también se rehacen");
|
|
212
|
+
}
|
|
213
|
+
finally {
|
|
214
|
+
db.close();
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
(0, node_test_1.test)("una imputación manual no recibe commits al reimportar", () => {
|
|
218
|
+
const db = (0, schema_js_1.openDatabase)(":memory:");
|
|
219
|
+
try {
|
|
220
|
+
seedProject(db);
|
|
221
|
+
const id = "te_p_2026-08-26_main";
|
|
222
|
+
store.saveTimeEntry(db, {
|
|
223
|
+
...entry({ source: "manual", kind: "meeting", description: "Reunión", commitHashes: [] }), id,
|
|
224
|
+
});
|
|
225
|
+
store.saveTimeEntry(db, {
|
|
226
|
+
...entry({ description: "Desarrollo", commitHashes: ["abc123"] }), id,
|
|
227
|
+
});
|
|
228
|
+
const saved = store.getTimeEntries(db, "p").find((e) => e.id === id);
|
|
229
|
+
strict_1.default.equal(saved.description, "Reunión");
|
|
230
|
+
strict_1.default.deepEqual(saved.commitHashes, []);
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
db.close();
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
// ── Cuándo un panel publicado se queda atrás ───────────────────────────
|
|
237
|
+
(0, node_test_1.test)("un panel se queda atrás solo si los datos cambian de verdad", () => {
|
|
238
|
+
// El fallo que esto previene: comparar contra la hora del trabajo en vez de
|
|
239
|
+
// la de escritura. Una reunión anotada esta tarde lleva fecha de las 10:00,
|
|
240
|
+
// así que parecía anterior a la publicación y el aviso no saltaba nunca.
|
|
241
|
+
const db = (0, schema_js_1.openDatabase)(":memory:");
|
|
242
|
+
try {
|
|
243
|
+
seedProject(db);
|
|
244
|
+
const id = "te_p_2026-08-26_main";
|
|
245
|
+
const T = (min) => new Date(`2026-08-27T10:${String(min).padStart(2, "0")}:00Z`);
|
|
246
|
+
store.saveTimeEntry(db, { ...entry({ seconds: 3600 }), id }, T(0));
|
|
247
|
+
store.recordPublication(db, "p", "tok", "https://x.dev", T(1));
|
|
248
|
+
strict_1.default.equal(store.listPublications(db)[0].staleBlocks, 0, "recién publicado");
|
|
249
|
+
// Reimportar los mismos valores no cambia nada que el cliente vea.
|
|
250
|
+
store.saveTimeEntry(db, { ...entry({ seconds: 3600 }), id }, T(2));
|
|
251
|
+
strict_1.default.equal(store.listPublications(db)[0].staleBlocks, 0, "un reimport idéntico no envejece el panel");
|
|
252
|
+
// Cambiar la duración sí.
|
|
253
|
+
store.saveTimeEntry(db, { ...entry({ seconds: 7200 }), id }, T(3));
|
|
254
|
+
strict_1.default.equal(store.listPublications(db)[0].staleBlocks, 1, "cambiar las horas sí lo envejece");
|
|
255
|
+
}
|
|
256
|
+
finally {
|
|
257
|
+
db.close();
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
(0, node_test_1.test)("trabajo nuevo posterior a la publicación cuenta como desfase", () => {
|
|
261
|
+
const db = (0, schema_js_1.openDatabase)(":memory:");
|
|
262
|
+
try {
|
|
263
|
+
seedProject(db);
|
|
264
|
+
store.recordPublication(db, "p", "tok", null, new Date("2026-08-27T10:00:00Z"));
|
|
265
|
+
// Fecha de trabajo anterior a la publicación, pero anotado después: es lo
|
|
266
|
+
// que pasa al apuntar a mano una reunión de esta mañana.
|
|
267
|
+
store.saveTimeEntry(db, {
|
|
268
|
+
...entry({ source: "manual", kind: "meeting" }),
|
|
269
|
+
id: "te_manual",
|
|
270
|
+
}, new Date("2026-08-27T18:00:00Z"));
|
|
271
|
+
strict_1.default.equal(store.listPublications(db)[0].staleBlocks, 1);
|
|
272
|
+
}
|
|
273
|
+
finally {
|
|
274
|
+
db.close();
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
(0, node_test_1.test)("republicar pone el contador a cero y conserva el enlace", () => {
|
|
278
|
+
const db = (0, schema_js_1.openDatabase)(":memory:");
|
|
279
|
+
try {
|
|
280
|
+
seedProject(db);
|
|
281
|
+
store.recordPublication(db, "p", "tok-1", "https://x.dev", new Date("2026-08-27T10:00:00Z"));
|
|
282
|
+
store.saveTimeEntry(db, { ...entry(), id: "te_a" }, new Date("2026-08-27T11:00:00Z"));
|
|
283
|
+
strict_1.default.equal(store.listPublications(db)[0].staleBlocks, 1);
|
|
284
|
+
// Republicar sin repetir la URL: no debe perderse.
|
|
285
|
+
store.recordPublication(db, "p", "tok-1", null, new Date("2026-08-27T12:00:00Z"));
|
|
286
|
+
const pub = store.listPublications(db)[0];
|
|
287
|
+
strict_1.default.equal(pub.staleBlocks, 0);
|
|
288
|
+
strict_1.default.equal(pub.baseUrl, "https://x.dev", "el dominio se conserva");
|
|
289
|
+
strict_1.default.equal(pub.token, "tok-1", "y el token también, o el cliente pierde su enlace");
|
|
290
|
+
}
|
|
291
|
+
finally {
|
|
292
|
+
db.close();
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
(0, node_test_1.test)("una base nueva tiene exactamente las columnas de una migrada", () => {
|
|
296
|
+
// El fallo real: `ai_budget_micro_usd` se añadió en la migración v10 y se
|
|
297
|
+
// olvidó en el esquema base. Una base nueva no ejecuta migraciones —el código
|
|
298
|
+
// asume que el esquema ya está al día— así que a cada instalación nueva le
|
|
299
|
+
// faltaba esa columna y la vista de equipo respondía 500.
|
|
300
|
+
//
|
|
301
|
+
// Nadie lo habría visto desarrollando: las bases existentes sí se migran. Lo
|
|
302
|
+
// descubre quien instala por primera vez, que es justo a quien no puedes
|
|
303
|
+
// permitirte fallarle.
|
|
304
|
+
const nueva = (0, schema_js_1.openDatabase)(":memory:");
|
|
305
|
+
// Una base "vieja": se le quitan las columnas que añadieron las migraciones
|
|
306
|
+
// y se la marca en la versión anterior, para que migre de verdad.
|
|
307
|
+
const migrada = (0, schema_js_1.openDatabase)(":memory:");
|
|
308
|
+
try {
|
|
309
|
+
for (const tabla of ["projects", "commits", "time_entries", "agent_turns"]) {
|
|
310
|
+
const cols = (db) => db.prepare(`PRAGMA table_info(${tabla})`).all()
|
|
311
|
+
.map((c) => c.name).sort((a, b) => a.localeCompare(b));
|
|
312
|
+
strict_1.default.deepEqual(cols(nueva), cols(migrada), `difieren en ${tabla}`);
|
|
313
|
+
}
|
|
314
|
+
// Y las columnas que añaden las migraciones tienen que estar de verdad.
|
|
315
|
+
const projectCols = nueva.prepare("PRAGMA table_info(projects)").all().map((c) => c.name);
|
|
316
|
+
strict_1.default.ok(projectCols.includes("ai_budget_micro_usd"));
|
|
317
|
+
const commitCols = nueva.prepare("PRAGMA table_info(commits)").all().map((c) => c.name);
|
|
318
|
+
strict_1.default.ok(commitCols.includes("author_name"));
|
|
319
|
+
}
|
|
320
|
+
finally {
|
|
321
|
+
nueva.close();
|
|
322
|
+
migrada.close();
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
(0, node_test_1.test)("una base nueva sirve la vista de equipo sin migrar nada", () => {
|
|
326
|
+
// La consulta concreta que reventaba en cada instalación nueva.
|
|
327
|
+
const db = (0, schema_js_1.openDatabase)(":memory:");
|
|
328
|
+
try {
|
|
329
|
+
strict_1.default.doesNotThrow(() => db.prepare("SELECT id, ai_budget_micro_usd FROM projects WHERE ai_budget_micro_usd IS NOT NULL").all());
|
|
330
|
+
}
|
|
331
|
+
finally {
|
|
332
|
+
db.close();
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
//# sourceMappingURL=schema.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.test.js","sourceRoot":"","sources":["../../src/db/schema.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gEAAwC;AACxC,6CAA2C;AAC3C,qCAAsC;AACtC,qCAAiC;AACjC,yCAAiC;AACjC,yCAAiC;AAIjC,2CAA2C;AAC3C,kDAAoC;AAEpC,SAAS,MAAM;IACb,OAAO,IAAA,gBAAI,EAAC,IAAA,qBAAW,EAAC,IAAA,gBAAI,EAAC,IAAA,gBAAM,GAAE,EAAE,YAAY,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;AACtE,CAAC;AAED,SAAS,WAAW,CAAC,EAAmC;IACtD,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE;QACtB,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,OAAO,CAAC;QAC9D,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ;KAC7E,CAAC,CAAC;AACL,CAAC;AAED,SAAS,KAAK,CAAC,OAA2B,EAAE;IAC1C,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnD,OAAO;QACL,SAAS,EAAE,GAAG,EAAE,SAAS;QACzB,OAAO,EAAE,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC;QACjD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI;QACrE,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE;QACtE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM;QACpD,GAAG,IAAI;KACR,CAAC;AACJ,CAAC;AAED,0EAA0E;AAE1E,IAAA,gBAAI,EAAC,8CAA8C,EAAE,GAAG,EAAE;IACxD,6EAA6E;IAC7E,6EAA6E;IAC7E,iDAAiD;IACjD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC;IAEtB,uDAAuD;IACvD,MAAM,GAAG,GAAG,IAAI,0BAAY,CAAC,IAAI,CAAC,CAAC;IACnC,GAAG,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;GAqBR,CAAC,CAAC;IACH,GAAG,CAAC,KAAK,EAAE,CAAC;IAEZ,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAI,EAAE,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC,GAAG,EAAyB;aACxF,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,gBAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,4BAA4B,CAAC,CAAC;QACpE,gBAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,0BAA0B,CAAC,CAAC;QAEhE,MAAM,OAAO,GAAI,EAAE,CAAC,OAAO,CAAC,oCAAoC,CAAC,CAAC,GAAG,EAA0B,CAAC;QAChG,gBAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAEjC,yEAAyE;QACzE,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,6CAA6C,CAAC;aACrE,GAAG,EAA6B,CAAC;QACpC,gBAAM,CAAC,EAAE,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAAC;QAChD,gBAAM,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,kBAAkB,CAAC,CAAC;QACxD,gBAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,sCAAsC,CAAC,CAAC;QAEhF,sDAAsD;QACtD,WAAW,CAAC,EAAE,CAAC,CAAC;QAChB,gBAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,2DAA2D,EAAE,GAAG,EAAE;IACrE,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC;IACtB,IAAA,wBAAY,EAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;IAC3B,gBAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,IAAA,wBAAY,EAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,iEAAiE,EAAE,GAAG,EAAE;IAC3E,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,IAAI,CAAC,CAAC;IAC9B,EAAE,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7D,EAAE,CAAC,KAAK,EAAE,CAAC;IAEX,gBAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,IAAA,wBAAY,EAAC,IAAI,CAAC,EAAE,uBAAuB,CAAC,CAAC;AACnE,CAAC,CAAC,CAAC;AAEH,0EAA0E;AAE1E,IAAA,gBAAI,EAAC,0CAA0C,EAAE,GAAG,EAAE;IACpD,0EAA0E;IAC1E,sEAAsE;IACtE,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,WAAW,CAAC,EAAE,CAAC,CAAC;QAEhB,MAAM,EAAE,GAAG,sBAAsB,CAAC;QAClC,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE;YACtB,GAAG,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI;gBAChD,WAAW,EAAE,wBAAwB,EAAE,CAAC;YACnD,EAAE;SACH,CAAC,CAAC;QAEH,iDAAiD;QACjD,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE;YACtB,GAAG,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC;YAC9E,EAAE;SACH,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,yCAAyC,CAAC;aAC9D,GAAG,CAAC,EAAE,CAA4B,CAAC;QACtC,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,wBAAwB,EAAE,6BAA6B,CAAC,CAAC;QAC1F,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,oCAAoC,CAAC,CAAC;QACzE,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,oDAAoD,EAAE,GAAG,EAAE;IAC9D,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,WAAW,CAAC,EAAE,CAAC,CAAC;QAChB,MAAM,EAAE,GAAG,sBAAsB,CAAC;QAElC,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5F,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAE/F,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,yCAAyC,CAAC;aAC9D,GAAG,CAAC,EAAE,CAA4B,CAAC;QACtC,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,0BAA0B,CAAC,CAAC;QAC/D,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,mBAAmB,CAAC,CAAC;IACxD,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,oDAAoD,EAAE,GAAG,EAAE;IAC9D,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,WAAW,CAAC,EAAE,CAAC,CAAC;QAChB,MAAM,EAAE,GAAG,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAChF,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAE,CAAC;QAEtE,gBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACvC,gBAAM,CAAC,SAAS,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QACzC,gBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACnC,gBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,8DAA8D,EAAE,GAAG,EAAE;IACxE,2EAA2E;IAC3E,6EAA6E;IAC7E,4EAA4E;IAC5E,uDAAuD;IACvD,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,WAAW,CAAC,EAAE,CAAC,CAAC;QAChB,MAAM,EAAE,GAAG,sBAAsB,CAAC;QAElC,iEAAiE;QACjE,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE;YACtB,GAAG,KAAK,CAAC,EAAE,WAAW,EAAE,oBAAoB,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE;SACtE,CAAC,CAAC;QAEH,4CAA4C;QAC5C,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE;YACtB,GAAG,KAAK,CAAC,EAAE,WAAW,EAAE,0BAA0B,EAAE,YAAY,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE;SACxF,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAE,CAAC;QACtE,gBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC;QAC5D,gBAAM,CAAC,SAAS,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,YAAY,CAAC,EAAE,gCAAgC,CAAC,CAAC;IACzF,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,uDAAuD,EAAE,GAAG,EAAE;IACjE,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,WAAW,CAAC,EAAE,CAAC,CAAC;QAChB,MAAM,EAAE,GAAG,sBAAsB,CAAC;QAClC,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE;YACtB,GAAG,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE;SAC9F,CAAC,CAAC;QACH,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE;YACtB,GAAG,KAAK,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE;SACtE,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAE,CAAC;QACtE,gBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAC3C,gBAAM,CAAC,SAAS,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAC3C,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,0EAA0E;AAE1E,IAAA,gBAAI,EAAC,6DAA6D,EAAE,GAAG,EAAE;IACvE,4EAA4E;IAC5E,4EAA4E;IAC5E,yEAAyE;IACzE,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,WAAW,CAAC,EAAE,CAAC,CAAC;QAChB,MAAM,EAAE,GAAG,sBAAsB,CAAC;QAClC,MAAM,CAAC,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,iBAAiB,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QACzF,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,KAAK,CAAC,iBAAiB,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE/D,gBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,EAAE,kBAAkB,CAAC,CAAC;QAEhF,mEAAmE;QACnE,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,gBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,EACxD,2CAA2C,CAAC,CAAC;QAE/C,0BAA0B;QAC1B,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,gBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,EACxD,kCAAkC,CAAC,CAAC;IACxC,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,8DAA8D,EAAE,GAAG,EAAE;IACxE,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,WAAW,CAAC,EAAE,CAAC,CAAC;QAChB,KAAK,CAAC,iBAAiB,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;QAChF,0EAA0E;QAC1E,yDAAyD;QACzD,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE;YACtB,GAAG,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YAC/C,EAAE,EAAE,WAAW;SAChB,EAAE,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;QACrC,gBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC9D,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,yDAAyD,EAAE,GAAG,EAAE;IACnE,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,WAAW,CAAC,EAAE,CAAC,CAAC;QAChB,KAAK,CAAC,iBAAiB,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,eAAe,EACvD,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;QACpC,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;QACtF,gBAAM,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAE5D,mDAAmD;QACnD,KAAK,CAAC,iBAAiB,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;QAClF,MAAM,GAAG,GAAG,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC;QAC3C,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QACjC,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,eAAe,EAAE,wBAAwB,CAAC,CAAC;QACrE,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,mDAAmD,CAAC,CAAC;IACxF,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,8DAA8D,EAAE,GAAG,EAAE;IACxE,0EAA0E;IAC1E,8EAA8E;IAC9E,2EAA2E;IAC3E,0DAA0D;IAC1D,EAAE;IACF,6EAA6E;IAC7E,yEAAyE;IACzE,uBAAuB;IACvB,MAAM,KAAK,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IAEvC,4EAA4E;IAC5E,kEAAkE;IAClE,MAAM,OAAO,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IAEzC,IAAI,CAAC;QACH,KAAK,MAAM,KAAK,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,CAAC,EAAE,CAAC;YAC3E,MAAM,IAAI,GAAG,CAAC,EAAgB,EAAE,EAAE,CAC/B,EAAE,CAAC,OAAO,CAAC,qBAAqB,KAAK,GAAG,CAAC,CAAC,GAAG,EAAyB;iBACpE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;YAE3D,gBAAM,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,eAAe,KAAK,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,wEAAwE;QACxE,MAAM,WAAW,GAAI,KAAK,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC,GAAG,EAChD,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzC,gBAAM,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAEvD,MAAM,UAAU,GAAI,KAAK,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC,GAAG,EAC9C,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzC,gBAAM,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;IAChD,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,yDAAyD,EAAE,GAAG,EAAE;IACnE,gEAAgE;IAChE,MAAM,EAAE,GAAG,IAAA,wBAAY,EAAC,UAAU,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,gBAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,OAAO,CAClC,oFAAoF,CACrF,CAAC,GAAG,EAAE,CAAC,CAAC;IACX,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3B,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import type { AgentTurn, AiConsentDecision, AiConsentRecord, Client, CloudAccount, CommitRecord, Invoice, InvoiceLine, ParseReport, Project, ProjectSync, RatePeriod, Subscription, TimeEntry } from "@estela/shared";
|
|
3
|
+
import type { ConsumptionRow } from "../billing/amortize.js";
|
|
4
|
+
export declare function upsertClient(db: DatabaseSync, client: Client): void;
|
|
5
|
+
export declare function upsertProject(db: DatabaseSync, project: Project): void;
|
|
6
|
+
export declare function addRatePeriod(db: DatabaseSync, rate: RatePeriod): void;
|
|
7
|
+
export declare function getClient(db: DatabaseSync, id: string): Client | null;
|
|
8
|
+
export declare function getProject(db: DatabaseSync, id: string): Project | null;
|
|
9
|
+
export declare function listProjects(db: DatabaseSync): Project[];
|
|
10
|
+
export declare function listClients(db: DatabaseSync): Client[];
|
|
11
|
+
export declare function getRates(db: DatabaseSync, projectId: string): RatePeriod[];
|
|
12
|
+
/**
|
|
13
|
+
* Correos con los que commiteas en un proyecto.
|
|
14
|
+
*
|
|
15
|
+
* Vacío significa "sin configurar", y entonces se cae a la configuración de
|
|
16
|
+
* git. Es un mal apaño pero mejor que capturar los commits de todo el equipo:
|
|
17
|
+
* imputarte el trabajo de un compañero es peor que no imputar nada.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getProjectAuthors(db: DatabaseSync, projectId: string): string[];
|
|
20
|
+
export declare function setProjectAuthors(db: DatabaseSync, projectId: string, emails: readonly string[]): void;
|
|
21
|
+
export interface Publication {
|
|
22
|
+
readonly projectId: string;
|
|
23
|
+
readonly token: string;
|
|
24
|
+
readonly publishedAt: Date;
|
|
25
|
+
readonly baseUrl: string | null;
|
|
26
|
+
/** Bloques con trabajo posterior a la publicación. */
|
|
27
|
+
readonly staleBlocks: number;
|
|
28
|
+
readonly lastWorkAt: Date | null;
|
|
29
|
+
}
|
|
30
|
+
export declare function recordPublication(db: DatabaseSync, projectId: string, token: string, baseUrl: string | null, at?: Date): void;
|
|
31
|
+
/**
|
|
32
|
+
* Estado de las publicaciones.
|
|
33
|
+
*
|
|
34
|
+
* `staleBlocks` cuenta el trabajo posterior a la última publicación. Es lo que
|
|
35
|
+
* de verdad envejece un panel: los días transcurridos no importan si en ese
|
|
36
|
+
* tiempo no tocaste el proyecto.
|
|
37
|
+
*/
|
|
38
|
+
export declare function listPublications(db: DatabaseSync): Publication[];
|
|
39
|
+
/** Todos los correos configurados, por repositorio, para filtrar al importar. */
|
|
40
|
+
export declare function authorsByRepo(db: DatabaseSync): Map<string, string[]>;
|
|
41
|
+
/** Encuentra el proyecto al que pertenece una ruta de repositorio. */
|
|
42
|
+
export declare function projectForRepo(db: DatabaseSync, repoPath: string): string | null;
|
|
43
|
+
/** Persiste turnos. `INSERT OR IGNORE` sobre la PK hace la dedup permanente. */
|
|
44
|
+
export declare function saveTurns(db: DatabaseSync, turns: readonly AgentTurn[]): number;
|
|
45
|
+
/**
|
|
46
|
+
* Guarda commits.
|
|
47
|
+
*
|
|
48
|
+
* El commit es inmutable, pero **nuestra lectura de él no lo es**: si un día se
|
|
49
|
+
* corrige el parser, reimportar tiene que poder rehacer los campos derivados.
|
|
50
|
+
* Con `INSERT OR IGNORE` los datos mal parseados se quedarían para siempre, sin
|
|
51
|
+
* forma de arreglarlos salvo borrando la base entera.
|
|
52
|
+
*
|
|
53
|
+
* Por eso hash y fecha se conservan (son la identidad) y las estadísticas se
|
|
54
|
+
* sobrescriben.
|
|
55
|
+
*/
|
|
56
|
+
export declare function saveCommits(db: DatabaseSync, commits: readonly CommitRecord[]): number;
|
|
57
|
+
export declare function logScan(db: DatabaseSync, source: string, report: ParseReport): void;
|
|
58
|
+
/**
|
|
59
|
+
* Guarda una imputación.
|
|
60
|
+
*
|
|
61
|
+
* `at` es la hora de escritura, no la del trabajo. Se puede pasar para que los
|
|
62
|
+
* tests no dependan del reloj: publicar y escribir en el mismo milisegundo hace
|
|
63
|
+
* que la comparación de desfase falle por empate.
|
|
64
|
+
*/
|
|
65
|
+
export declare function saveTimeEntry(db: DatabaseSync, entry: Omit<TimeEntry, "id"> & {
|
|
66
|
+
id?: string;
|
|
67
|
+
}, at?: Date): string;
|
|
68
|
+
export declare function getTimeEntries(db: DatabaseSync, projectId: string): TimeEntry[];
|
|
69
|
+
/**
|
|
70
|
+
* Imputaciones de un rango de fechas.
|
|
71
|
+
*
|
|
72
|
+
* Filtra por `local_date` y no por `started_at`: la fecha en que trabajaste es
|
|
73
|
+
* la de tu reloj, no la de Greenwich. Un bloque de las 23:20 pertenece a hoy
|
|
74
|
+
* aunque en UTC ya sea mañana.
|
|
75
|
+
*/
|
|
76
|
+
export declare function listEntriesBetween(db: DatabaseSync, from: string, to: string): TimeEntry[];
|
|
77
|
+
/** Guarda la factura y marca sus imputaciones. Todo o nada. */
|
|
78
|
+
export declare function saveInvoice(db: DatabaseSync, invoice: Invoice, entryIds: readonly string[]): void;
|
|
79
|
+
export declare function nextInvoiceNumber(db: DatabaseSync, prefix: string): string;
|
|
80
|
+
export declare function readInvoiceLines(json: string): InvoiceLine[];
|
|
81
|
+
export declare function upsertSubscription(db: DatabaseSync, sub: Subscription): void;
|
|
82
|
+
export declare function listSubscriptions(db: DatabaseSync): Subscription[];
|
|
83
|
+
/**
|
|
84
|
+
* Consumo total del mes en toda la máquina, esté asignado a un proyecto o no.
|
|
85
|
+
*
|
|
86
|
+
* Es el denominador correcto para repartir una cuota fija: la pagaste entera,
|
|
87
|
+
* la usaras donde la usaras. Se lee de `agent_turns` y no de `time_entries`
|
|
88
|
+
* porque ahí está *todo* tu consumo, incluidos los repos que aún no configuraste.
|
|
89
|
+
*/
|
|
90
|
+
export declare function totalConsumptionByMonth(db: DatabaseSync): Map<string, {
|
|
91
|
+
microUsd: number;
|
|
92
|
+
}>;
|
|
93
|
+
/** Consumo por proyecto y mes, sobre las imputaciones ya asignadas. */
|
|
94
|
+
export declare function consumptionByProjectMonth(db: DatabaseSync): ConsumptionRow[];
|
|
95
|
+
/** La cuenta cloud vinculada a esta máquina, o null si todo sigue local. */
|
|
96
|
+
export declare function getCloudAccount(db: DatabaseSync): CloudAccount | null;
|
|
97
|
+
export declare function setCloudAccount(db: DatabaseSync, account: CloudAccount): void;
|
|
98
|
+
/** `estela logout`. Borra el vínculo cloud; los datos locales no se tocan. */
|
|
99
|
+
export declare function clearCloudAccount(db: DatabaseSync): void;
|
|
100
|
+
export declare function getProjectSync(db: DatabaseSync, projectId: string): ProjectSync | null;
|
|
101
|
+
export declare function setProjectSync(db: DatabaseSync, sync: ProjectSync): void;
|
|
102
|
+
/** Proyectos de equipo enlazados en esta máquina — lo único que sube `sync/team.ts`. */
|
|
103
|
+
export declare function listTeamSyncedProjects(db: DatabaseSync): ProjectSync[];
|
|
104
|
+
/**
|
|
105
|
+
* Proyectos candidatos al sync personal (Pro): todos menos los que ya están
|
|
106
|
+
* enlazados a un equipo. Es la guardia anti-fuga: un proyecto de equipo nunca
|
|
107
|
+
* puede colarse también como sync personal, porque `project_sync.project_id`
|
|
108
|
+
* es su clave primaria — un proyecto tiene un único alcance.
|
|
109
|
+
*/
|
|
110
|
+
export declare function listPersonalSyncCandidates(db: DatabaseSync): string[];
|
|
111
|
+
export declare function getAiConsent(db: DatabaseSync, projectId: string): AiConsentRecord | null;
|
|
112
|
+
export declare function setAiConsent(db: DatabaseSync, projectId: string, requested: boolean, decision: AiConsentDecision): void;
|
|
113
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/db/store.ts"],"names":[],"mappings":"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"}
|