estela 0.1.39 → 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 (90) hide show
  1. package/README.md +96 -0
  2. package/dist/billing/assign.d.ts +45 -0
  3. package/dist/billing/assign.d.ts.map +1 -0
  4. package/dist/billing/assign.js +159 -0
  5. package/dist/billing/assign.js.map +1 -0
  6. package/dist/billing/assign.test.d.ts +2 -0
  7. package/dist/billing/assign.test.d.ts.map +1 -0
  8. package/dist/billing/assign.test.js +153 -0
  9. package/dist/billing/assign.test.js.map +1 -0
  10. package/dist/bin.js +23 -1
  11. package/dist/bin.js.map +1 -1
  12. package/dist/cli-import-recover.test.d.ts +2 -0
  13. package/dist/cli-import-recover.test.d.ts.map +1 -0
  14. package/dist/cli-import-recover.test.js +191 -0
  15. package/dist/cli-import-recover.test.js.map +1 -0
  16. package/dist/cli-quota.test.d.ts +2 -0
  17. package/dist/cli-quota.test.d.ts.map +1 -0
  18. package/dist/cli-quota.test.js +281 -0
  19. package/dist/cli-quota.test.js.map +1 -0
  20. package/dist/cli-statusline.test.d.ts +2 -0
  21. package/dist/cli-statusline.test.d.ts.map +1 -0
  22. package/dist/cli-statusline.test.js +333 -0
  23. package/dist/cli-statusline.test.js.map +1 -0
  24. package/dist/cli.d.ts.map +1 -1
  25. package/dist/cli.js +350 -49
  26. package/dist/cli.js.map +1 -1
  27. package/dist/db/store.d.ts +12 -1
  28. package/dist/db/store.d.ts.map +1 -1
  29. package/dist/db/store.js +52 -0
  30. package/dist/db/store.js.map +1 -1
  31. package/dist/demo.d.ts.map +1 -1
  32. package/dist/demo.js +53 -0
  33. package/dist/demo.js.map +1 -1
  34. package/dist/i18n/en.d.ts.map +1 -1
  35. package/dist/i18n/en.js +68 -0
  36. package/dist/i18n/en.js.map +1 -1
  37. package/dist/metrics/quota.d.ts +226 -0
  38. package/dist/metrics/quota.d.ts.map +1 -0
  39. package/dist/metrics/quota.js +291 -0
  40. package/dist/metrics/quota.js.map +1 -0
  41. package/dist/metrics/quota.test.d.ts +2 -0
  42. package/dist/metrics/quota.test.d.ts.map +1 -0
  43. package/dist/metrics/quota.test.js +325 -0
  44. package/dist/metrics/quota.test.js.map +1 -0
  45. package/dist/project-of.d.ts +52 -0
  46. package/dist/project-of.d.ts.map +1 -0
  47. package/dist/project-of.js +124 -0
  48. package/dist/project-of.js.map +1 -0
  49. package/dist/project-of.test.d.ts +2 -0
  50. package/dist/project-of.test.d.ts.map +1 -0
  51. package/dist/project-of.test.js +203 -0
  52. package/dist/project-of.test.js.map +1 -0
  53. package/dist/quota.d.ts +27 -0
  54. package/dist/quota.d.ts.map +1 -0
  55. package/dist/quota.js +79 -0
  56. package/dist/quota.js.map +1 -0
  57. package/dist/server.d.ts.map +1 -1
  58. package/dist/server.js +17 -26
  59. package/dist/server.js.map +1 -1
  60. package/dist/server.test.js +37 -0
  61. package/dist/server.test.js.map +1 -1
  62. package/dist/statusline-cache.d.ts +35 -0
  63. package/dist/statusline-cache.d.ts.map +1 -0
  64. package/dist/statusline-cache.js +57 -0
  65. package/dist/statusline-cache.js.map +1 -0
  66. package/dist/statusline-install.d.ts +52 -0
  67. package/dist/statusline-install.d.ts.map +1 -0
  68. package/dist/statusline-install.js +115 -0
  69. package/dist/statusline-install.js.map +1 -0
  70. package/dist/statusline-run.d.ts +8 -0
  71. package/dist/statusline-run.d.ts.map +1 -0
  72. package/dist/statusline-run.js +256 -0
  73. package/dist/statusline-run.js.map +1 -0
  74. package/dist/statusline.d.ts +71 -0
  75. package/dist/statusline.d.ts.map +1 -0
  76. package/dist/statusline.js +139 -0
  77. package/dist/statusline.js.map +1 -0
  78. package/dist/statusline.test.d.ts +2 -0
  79. package/dist/statusline.test.d.ts.map +1 -0
  80. package/dist/statusline.test.js +197 -0
  81. package/dist/statusline.test.js.map +1 -0
  82. package/dist/watchers/claude.d.ts +11 -1
  83. package/dist/watchers/claude.d.ts.map +1 -1
  84. package/dist/watchers/claude.js +32 -15
  85. package/dist/watchers/claude.js.map +1 -1
  86. package/package.json +1 -1
  87. package/web/app.css +36 -0
  88. package/web/app.js +61 -1
  89. package/web/i18n.js +28 -0
  90. package/web/index.html +4 -1
@@ -0,0 +1,203 @@
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_child_process_1 = require("node:child_process");
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("./db/schema.js");
46
+ const store = __importStar(require("./db/store.js"));
47
+ const quota_js_1 = require("./metrics/quota.js");
48
+ const quota_js_2 = require("./quota.js");
49
+ const paths_js_1 = require("./paths.js");
50
+ const project_of_js_1 = require("./project-of.js");
51
+ /**
52
+ * A qué proyecto va una sesión según su carpeta. El fallo de antes: una sesión
53
+ * en `repo/src` de un repo sin registrar salía como "src", y una en un
54
+ * worktree (que vive al lado del repo) no contaba para su proyecto.
55
+ */
56
+ /** Un directorio temporal con la ruta real (en macOS /var es un enlace a /private/var). */
57
+ function tmp() {
58
+ return (0, node_fs_1.realpathSync)((0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "estela-root-")));
59
+ }
60
+ /** Un repo de mentira: basta la carpeta .git, no hace falta git. */
61
+ function repo(base, name) {
62
+ const r = (0, node_path_1.join)(base, name);
63
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(r, ".git", "worktrees"), { recursive: true });
64
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(r, "src"), { recursive: true });
65
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(r, "packages", "x", "src"), { recursive: true });
66
+ return r;
67
+ }
68
+ /** Un worktree como lo deja `git worktree add`: un fichero .git que apunta al principal. */
69
+ function worktree(main, at, name, relative = false) {
70
+ const meta = (0, node_path_1.join)(main, ".git", "worktrees", name);
71
+ (0, node_fs_1.mkdirSync)(meta, { recursive: true });
72
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(meta, "commondir"), "../..\n");
73
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(at, "lib"), { recursive: true });
74
+ const gitdir = relative ? (0, node_path_1.join)("..", "web", ".git", "worktrees", name) : meta;
75
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(at, ".git"), `gitdir: ${gitdir}\n`);
76
+ return at;
77
+ }
78
+ const n = (p) => (0, paths_js_1.normalizePath)(p);
79
+ // ── gitRoot ─────────────────────────────────────────────────────────────
80
+ (0, node_test_1.test)("subcarpetas: repo/src y repo/packages/x llevan a la raíz del repo", () => {
81
+ const base = tmp();
82
+ const r = repo(base, "web");
83
+ strict_1.default.equal((0, project_of_js_1.gitRoot)(r), n(r));
84
+ strict_1.default.equal((0, project_of_js_1.gitRoot)((0, node_path_1.join)(r, "src")), n(r));
85
+ strict_1.default.equal((0, project_of_js_1.gitRoot)((0, node_path_1.join)(r, "packages", "x", "src")), n(r));
86
+ });
87
+ (0, node_test_1.test)("worktree: lleva al repositorio principal, con gitdir absoluto o relativo", () => {
88
+ const base = tmp();
89
+ const main = repo(base, "web");
90
+ const wt = worktree(main, (0, node_path_1.join)(base, "web-feature"), "web-feature");
91
+ strict_1.default.equal((0, project_of_js_1.gitRoot)(wt), n(main));
92
+ strict_1.default.equal((0, project_of_js_1.gitRoot)((0, node_path_1.join)(wt, "lib")), n(main));
93
+ const rel = worktree(main, (0, node_path_1.join)(base, "web-fix"), "web-fix", true);
94
+ strict_1.default.equal((0, project_of_js_1.gitRoot)(rel), n(main));
95
+ });
96
+ (0, node_test_1.test)("submódulo: un .git fichero sin commondir es su propio repositorio", () => {
97
+ const base = tmp();
98
+ const main = repo(base, "web");
99
+ const sub = (0, node_path_1.join)(main, "vendor", "lib");
100
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(main, ".git", "modules", "lib"), { recursive: true });
101
+ (0, node_fs_1.mkdirSync)(sub, { recursive: true });
102
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(sub, ".git"), `gitdir: ${(0, node_path_1.join)(main, ".git", "modules", "lib")}\n`);
103
+ strict_1.default.equal((0, project_of_js_1.gitRoot)(sub), n(sub));
104
+ });
105
+ (0, node_test_1.test)("fuera de git: null; y una carpeta que ya no existe no rompe nada", () => {
106
+ const base = tmp();
107
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(base, "suelta"), { recursive: true });
108
+ strict_1.default.equal((0, project_of_js_1.gitRoot)((0, node_path_1.join)(base, "suelta")), null);
109
+ const r = repo(base, "web");
110
+ strict_1.default.equal((0, project_of_js_1.gitRoot)((0, node_path_1.join)(r, "borrada", "hace", "tiempo")), n(r), "sube aunque la carpeta no exista");
111
+ });
112
+ (0, node_test_1.test)("una ruta relativa o con ~ no busca raíz git: no puede caer en el repo de quien ejecuta", () => {
113
+ strict_1.default.equal((0, project_of_js_1.gitRoot)("~/code/web"), null);
114
+ strict_1.default.equal((0, project_of_js_1.gitRoot)("src"), null);
115
+ });
116
+ (0, node_test_1.test)("con git de verdad: un worktree creado con git worktree add", (t) => {
117
+ if ((0, node_child_process_1.spawnSync)("git", ["--version"]).status !== 0) {
118
+ t.skip("sin git");
119
+ return;
120
+ }
121
+ const base = tmp();
122
+ const main = (0, node_path_1.join)(base, "app");
123
+ const git = (...args) => {
124
+ const r = (0, node_child_process_1.spawnSync)("git", args, { cwd: main, encoding: "utf8" });
125
+ strict_1.default.equal(r.status, 0, r.stderr);
126
+ };
127
+ (0, node_fs_1.mkdirSync)(main);
128
+ git("init", "-q");
129
+ git("-c", "user.email=t@t", "-c", "user.name=t", "commit", "-q", "--allow-empty", "-m", "x");
130
+ git("worktree", "add", "-q", (0, node_path_1.join)(base, "app-feature"));
131
+ strict_1.default.equal((0, project_of_js_1.gitRoot)((0, node_path_1.join)(base, "app-feature")), n(main));
132
+ });
133
+ // ── A qué proyecto va ───────────────────────────────────────────────────
134
+ function base() {
135
+ const b = tmp();
136
+ const web = repo(b, "web");
137
+ const db = (0, schema_js_1.openDatabase)(":memory:");
138
+ store.upsertClient(db, { id: "c", name: "C", currency: "EUR" });
139
+ store.upsertProject(db, { id: "web", clientId: "c", name: "Web", repoPaths: [n(web)], billable: true,
140
+ roundingMinutes: 0, aiCostPolicy: "absorbed", kind: "client" });
141
+ return { b, web, db };
142
+ }
143
+ (0, node_test_1.test)("una sesión en una subcarpeta o en un worktree cuenta para el proyecto del repo", () => {
144
+ const { b, web, db } = base();
145
+ try {
146
+ const owner = (0, project_of_js_1.ownerResolver)(db);
147
+ const wt = worktree(web, (0, node_path_1.join)(b, "web-feature"), "web-feature");
148
+ for (const dir of [web, (0, node_path_1.join)(web, "src"), (0, node_path_1.join)(web, "packages", "x"), wt, (0, node_path_1.join)(wt, "lib")]) {
149
+ strict_1.default.deepEqual(owner(n(dir)), { kind: "project", projectId: "web" }, dir);
150
+ }
151
+ }
152
+ finally {
153
+ db.close();
154
+ }
155
+ });
156
+ (0, node_test_1.test)("un subproyecto registrado dentro del monorepo no se pierde al subir a la raíz", () => {
157
+ const { web, db } = base();
158
+ try {
159
+ store.upsertProject(db, { id: "x", clientId: "c", name: "X", repoPaths: [n((0, node_path_1.join)(web, "packages", "x"))],
160
+ billable: true, roundingMinutes: 0, aiCostPolicy: "absorbed", kind: "client" });
161
+ const owner = (0, project_of_js_1.ownerResolver)(db);
162
+ strict_1.default.deepEqual(owner(n((0, node_path_1.join)(web, "packages", "x", "src"))), { kind: "project", projectId: "x" });
163
+ strict_1.default.deepEqual(owner(n((0, node_path_1.join)(web, "src"))), { kind: "project", projectId: "web" });
164
+ }
165
+ finally {
166
+ db.close();
167
+ }
168
+ });
169
+ (0, node_test_1.test)("sin proyecto: el nombre de la raíz git, nunca el de una subcarpeta; fuera de git, la carpeta", () => {
170
+ const { b, db } = base();
171
+ try {
172
+ const otro = repo(b, "otro-repo");
173
+ const owner = (0, project_of_js_1.ownerResolver)(db);
174
+ strict_1.default.deepEqual(owner(n((0, node_path_1.join)(otro, "packages", "x", "src"))), { kind: "folder", path: n(otro), name: "otro-repo", inGit: true });
175
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(b, "notas"));
176
+ strict_1.default.deepEqual(owner(n((0, node_path_1.join)(b, "notas"))), { kind: "folder", path: n((0, node_path_1.join)(b, "notas")), name: "notas", inGit: false });
177
+ }
178
+ finally {
179
+ db.close();
180
+ }
181
+ });
182
+ (0, node_test_1.test)("en quota, las subcarpetas de un repo sin registrar son una sola fila con su nombre", () => {
183
+ const { b, db } = base();
184
+ try {
185
+ const otro = repo(b, "otro-repo");
186
+ // Dentro de esta semana a cualquier hora, también un lunes a las 00:05.
187
+ const at = new Date(Math.max((0, quota_js_1.weekStart)(new Date()).getTime(), Date.now() - 10 * 60_000));
188
+ const turno = (id, cwd) => ({
189
+ agent: "claude-code", turnId: id, sessionId: "s", at, model: "claude-sonnet-4-6",
190
+ repoPath: n(cwd), branch: null, producerVersion: null,
191
+ tokens: { input: 0, output: 0, cacheRead: 100, cacheWrite5m: 0, cacheWrite1h: 0 },
192
+ });
193
+ store.saveTurns(db, [turno("a", (0, node_path_1.join)(otro, "src")), turno("b", (0, node_path_1.join)(otro, "packages", "x")), turno("c", otro)]);
194
+ const filas = (0, quota_js_2.loadQuotaReport)(db).agents[0].week.rows;
195
+ strict_1.default.equal(filas.length, 1);
196
+ strict_1.default.deepEqual(filas[0].bucket, { kind: "folder", folder: "otro-repo", path: n(otro) });
197
+ strict_1.default.equal(filas[0].usage.total, 300);
198
+ }
199
+ finally {
200
+ db.close();
201
+ }
202
+ });
203
+ //# sourceMappingURL=project-of.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-of.test.js","sourceRoot":"","sources":["../src/project-of.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import { type QuotaReport } from "./metrics/quota.js";
3
+ /**
4
+ * La cuota sobre la base: lo que comparten `estela quota` y el panel web.
5
+ * El cálculo vive en `metrics/quota.ts`; aquí solo se leen los datos.
6
+ */
7
+ export interface QuotaLoadOptions {
8
+ /** % por precio de lista en vez de por tokens (`--weighted`). */
9
+ readonly weighted?: boolean;
10
+ /**
11
+ * La base de la que se lee, para encontrar al lado lo que guardó la status
12
+ * line (el `resets_at` de Claude Code). Sin ella, la ventana se estima.
13
+ */
14
+ readonly dbPath?: string;
15
+ }
16
+ export declare function loadQuotaReport(db: DatabaseSync, now?: Date, options?: QuotaLoadOptions): QuotaReport;
17
+ /**
18
+ * Trae los turnos de esta semana antes de calcular.
19
+ *
20
+ * Sin esto, la "ventana actual" sería la de la última vez que alguien ejecutó
21
+ * `estela import`, que puede ser de ayer. Solo se leen los transcripts desde el
22
+ * lunes, y solo se guardan turnos: `INSERT OR IGNORE` sobre el `turn_id` hace
23
+ * que repetirlo no duplique nada, y el siguiente `import` reconstruye las horas
24
+ * con lo que lee él mismo, así que no se le quita trabajo.
25
+ */
26
+ export declare function refreshQuotaTurns(db: DatabaseSync, since: Date): Promise<number>;
27
+ //# sourceMappingURL=quota.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.d.ts","sourceRoot":"","sources":["../src/quota.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAA4D,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKhH;;;GAGG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,GAAE,IAAiB,EAAE,OAAO,GAAE,gBAAqB,GAAG,WAAW,CAsBrH;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAGtF"}
package/dist/quota.js ADDED
@@ -0,0 +1,79 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.loadQuotaReport = loadQuotaReport;
37
+ exports.refreshQuotaTurns = refreshQuotaTurns;
38
+ const store = __importStar(require("./db/store.js"));
39
+ const quota_js_1 = require("./metrics/quota.js");
40
+ const project_of_js_1 = require("./project-of.js");
41
+ const statusline_cache_js_1 = require("./statusline-cache.js");
42
+ const agents_js_1 = require("./watchers/agents.js");
43
+ function loadQuotaReport(db, now = new Date(), options = {}) {
44
+ const range = (0, quota_js_1.quotaRange)(now);
45
+ const names = new Map(store.listProjects(db).map((p) => [p.id, p.name]));
46
+ // La carpeta, y si no, su raíz git: ver project-of.ts. Una carpeta sin
47
+ // proyecto sale con el nombre de su raíz git, no el de una subcarpeta.
48
+ const ownerOf = (0, project_of_js_1.ownerResolver)(db);
49
+ const bucketOf = (repoPath) => {
50
+ const o = ownerOf(repoPath);
51
+ if (o.kind === "project")
52
+ return { kind: "project", projectId: o.projectId, projectName: names.get(o.projectId) ?? o.projectId };
53
+ if (o.kind === "folder")
54
+ return { kind: "folder", folder: o.name, path: o.path };
55
+ return { kind: "none" };
56
+ };
57
+ return (0, quota_js_1.buildQuota)({
58
+ turns: store.quotaTurns(db, range.start, range.end),
59
+ firstTurnAt: store.firstTurnByAgent(db),
60
+ now,
61
+ bucketOf,
62
+ weighted: options.weighted === true,
63
+ claudeWindow: options.dbPath ? (0, quota_js_1.officialWindow)((0, statusline_cache_js_1.readFiveHourReset)(options.dbPath), now) : null,
64
+ });
65
+ }
66
+ /**
67
+ * Trae los turnos de esta semana antes de calcular.
68
+ *
69
+ * Sin esto, la "ventana actual" sería la de la última vez que alguien ejecutó
70
+ * `estela import`, que puede ser de ayer. Solo se leen los transcripts desde el
71
+ * lunes, y solo se guardan turnos: `INSERT OR IGNORE` sobre el `turn_id` hace
72
+ * que repetirlo no duplique nada, y el siguiente `import` reconstruye las horas
73
+ * con lo que lee él mismo, así que no se le quita trabajo.
74
+ */
75
+ async function refreshQuotaTurns(db, since) {
76
+ const scans = await (0, agents_js_1.scanAgents)({ since });
77
+ return store.saveTurns(db, scans.flatMap((s) => [...s.turns]));
78
+ }
79
+ //# sourceMappingURL=quota.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.js","sourceRoot":"","sources":["../src/quota.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,0CAsBC;AAWD,8CAGC;AAzDD,qDAAuC;AACvC,iDAAgH;AAChH,mDAAgD;AAChD,+DAA0D;AAC1D,oDAAkD;AAiBlD,SAAgB,eAAe,CAAC,EAAgB,EAAE,MAAY,IAAI,IAAI,EAAE,EAAE,UAA4B,EAAE;IACtG,MAAM,KAAK,GAAG,IAAA,qBAAU,EAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEzE,uEAAuE;IACvE,uEAAuE;IACvE,MAAM,OAAO,GAAG,IAAA,6BAAa,EAAC,EAAE,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,CAAC,QAAuB,EAAe,EAAE;QACxD,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC5B,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;QACjI,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACjF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC,CAAC;IAEF,OAAO,IAAA,qBAAU,EAAC;QAChB,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC;QACnD,WAAW,EAAE,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACvC,GAAG;QACH,QAAQ;QACR,QAAQ,EAAE,OAAO,CAAC,QAAQ,KAAK,IAAI;QACnC,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAA,yBAAc,EAAC,IAAA,uCAAiB,EAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;KAC7F,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACI,KAAK,UAAU,iBAAiB,CAAC,EAAgB,EAAE,KAAW;IACnE,MAAM,KAAK,GAAG,MAAM,IAAA,sBAAU,EAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1C,OAAO,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAwEjG,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,qEAAqE;IACrE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AA8ED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAcD,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CAErD;AA2CD,wBAAgB,WAAW,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6CxE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AA2EjG,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,qEAAqE;IACrE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AA0DD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAcD,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CAErD;AA2CD,wBAAgB,WAAW,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6CxE"}
package/dist/server.js CHANGED
@@ -60,6 +60,9 @@ const identity_js_1 = require("./watchers/identity.js");
60
60
  const index_js_2 = require("./i18n/index.js");
61
61
  const paths_js_1 = require("./paths.js");
62
62
  const localize_js_1 = require("./billing/localize.js");
63
+ const assign_js_1 = require("./billing/assign.js");
64
+ const quota_js_1 = require("./metrics/quota.js");
65
+ const quota_js_2 = require("./quota.js");
63
66
  const labels_js_1 = require("./i18n/labels.js");
64
67
  /**
65
68
  * Servidor local del dashboard.
@@ -139,32 +142,14 @@ async function importOnce(dbPath) {
139
142
  const commits = (0, identity_js_1.onlyMine)(allRepoCommits, mine);
140
143
  const fromAgents = (0, sessionize_js_1.attachCommits)((0, sessionize_js_1.sessionize)(turns), commits);
141
144
  const fromCommits = (0, sessionize_js_1.withoutOverlap)((0, sessionize_js_1.sessionizeCommits)(commits), fromAgents);
142
- // Se agrupa por PROYECTO, no por ruta: el agente abierto en `repo/` y en
143
- // `repo/src/UI` son dos rutas del mismo proyecto, y agrupar por ruta
144
- // producía dos bloques que luego se pisaban al guardarse con el mismo id.
145
- const porProyecto = (b) => (b.repoPath ? store.projectForRepo(db, b.repoPath) ?? b.repoPath : "");
146
- for (const block of (0, sessionize_js_1.groupByBranchAndDay)([...fromAgents, ...fromCommits], porProyecto)) {
147
- const projectId = block.repoPath ? store.projectForRepo(db, block.repoPath) : null;
148
- if (!projectId)
149
- continue;
150
- const project = store.getProject(db, projectId);
151
- const day = (0, shared_1.localDate)(block.startedAt);
152
- const slug = (block.branch ?? "sin-rama").replace(/[^a-zA-Z0-9]+/g, "-");
153
- store.saveTimeEntry(db, {
154
- id: `te_${projectId}_${day}_${slug}`,
155
- projectId,
156
- startedAt: block.startedAt, endedAt: block.endedAt, seconds: block.seconds,
157
- description: (0, sessionize_js_1.describeBlock)(block),
158
- billable: project.billable, invoiceId: null,
159
- aiCost: block.aiCost,
160
- // Sin agente no hay segundos de agente que atribuir.
161
- agentSeconds: block.turnCount > 0 ? block.seconds : 0,
162
- commitHashes: block.commits.map((c) => c.hash),
163
- agents: block.turnCount > 0 ? [...(block.agents ?? ["claude-code"])] : [],
164
- source: block.turnCount > 0 ? "agent" : "commit", kind: "development",
165
- branch: block.branch,
166
- workItems: (0, shared_1.extractWorkItems)(block.branch, block.commits.map((c) => c.subject), project.tracker),
167
- });
145
+ // Las mismas reglas que `estela import` (billing/assign.ts). Las horas de
146
+ // subcarpetas y worktrees solo se recuperan si ya se confirmó una vez
147
+ // desde la terminal: el panel no cambia horas importadas en segundo plano
148
+ // sin que nadie haya visto antes qué iba a cambiar.
149
+ const recover = (0, node_fs_1.existsSync)((0, node_path_1.join)((0, node_path_1.dirname)(dbPath), ".recover-git-root"));
150
+ const plan = (0, assign_js_1.planEntries)(db, [...fromAgents, ...fromCommits], { recover });
151
+ for (const { entry } of plan.entries) {
152
+ store.saveTimeEntry(db, entry);
168
153
  imputed++;
169
154
  }
170
155
  return imputed;
@@ -319,6 +304,12 @@ async function api(req, res, url, dbPath) {
319
304
  const to = url.searchParams.get("to") ?? "";
320
305
  return json(res, 200, buildSummary(db, from, to));
321
306
  }
307
+ // Qué proyecto se come la cuota esta semana. Sin refrescar transcripts:
308
+ // el panel ya importa solo cada pocos minutos, y una petición web no debe
309
+ // ponerse a leer el disco entero.
310
+ if (path === "/api/quota" && req.method === "GET") {
311
+ return json(res, 200, (0, quota_js_1.quotaToJson)((0, quota_js_2.loadQuotaReport)(db, new Date(), { dbPath })));
312
+ }
322
313
  if (path === "/api/day" && req.method === "GET") {
323
314
  const date = url.searchParams.get("date") ?? todayIso();
324
315
  return json(res, 200, buildDay(db, date));