estela 0.1.40 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/README.md +46 -2
  2. package/dist/billing/assign.d.ts +45 -0
  3. package/dist/billing/assign.js +159 -0
  4. package/dist/bin.js +23 -1
  5. package/dist/cli.js +220 -57
  6. package/dist/db/store.d.ts +2 -0
  7. package/dist/db/store.js +24 -1
  8. package/dist/demo.js +1 -1
  9. package/dist/i18n/en.js +39 -0
  10. package/dist/metrics/quota.d.ts +44 -4
  11. package/dist/metrics/quota.js +60 -14
  12. package/dist/project-of.d.ts +52 -0
  13. package/dist/project-of.js +124 -0
  14. package/dist/quota.d.ts +10 -1
  15. package/dist/quota.js +14 -20
  16. package/dist/server.js +10 -27
  17. package/dist/statusline-cache.d.ts +35 -0
  18. package/dist/statusline-cache.js +57 -0
  19. package/dist/statusline-install.d.ts +52 -0
  20. package/dist/statusline-install.js +115 -0
  21. package/dist/statusline-run.d.ts +8 -0
  22. package/dist/statusline-run.js +256 -0
  23. package/dist/statusline.d.ts +71 -0
  24. package/dist/statusline.js +152 -0
  25. package/dist/watchers/claude.d.ts +11 -1
  26. package/dist/watchers/claude.js +32 -15
  27. package/package.json +3 -1
  28. package/dist/billing/amortize.d.ts.map +0 -1
  29. package/dist/billing/amortize.js.map +0 -1
  30. package/dist/billing/amortize.test.d.ts +0 -2
  31. package/dist/billing/amortize.test.d.ts.map +0 -1
  32. package/dist/billing/amortize.test.js +0 -121
  33. package/dist/billing/amortize.test.js.map +0 -1
  34. package/dist/billing/format.test.d.ts +0 -2
  35. package/dist/billing/format.test.d.ts.map +0 -1
  36. package/dist/billing/format.test.js +0 -110
  37. package/dist/billing/format.test.js.map +0 -1
  38. package/dist/billing/invoice.d.ts.map +0 -1
  39. package/dist/billing/invoice.js.map +0 -1
  40. package/dist/billing/invoice.test.d.ts +0 -2
  41. package/dist/billing/invoice.test.d.ts.map +0 -1
  42. package/dist/billing/invoice.test.js +0 -200
  43. package/dist/billing/invoice.test.js.map +0 -1
  44. package/dist/billing/localize.d.ts.map +0 -1
  45. package/dist/billing/localize.js.map +0 -1
  46. package/dist/billing/localize.test.d.ts +0 -2
  47. package/dist/billing/localize.test.d.ts.map +0 -1
  48. package/dist/billing/localize.test.js +0 -144
  49. package/dist/billing/localize.test.js.map +0 -1
  50. package/dist/billing/sessionize.d.ts.map +0 -1
  51. package/dist/billing/sessionize.js.map +0 -1
  52. package/dist/billing/sessionize.test.d.ts +0 -2
  53. package/dist/billing/sessionize.test.d.ts.map +0 -1
  54. package/dist/billing/sessionize.test.js +0 -187
  55. package/dist/billing/sessionize.test.js.map +0 -1
  56. package/dist/billing.d.ts.map +0 -1
  57. package/dist/billing.js.map +0 -1
  58. package/dist/bin.d.ts.map +0 -1
  59. package/dist/bin.js.map +0 -1
  60. package/dist/cli-badge.test.d.ts +0 -2
  61. package/dist/cli-badge.test.d.ts.map +0 -1
  62. package/dist/cli-badge.test.js +0 -118
  63. package/dist/cli-badge.test.js.map +0 -1
  64. package/dist/cli-idioma.test.d.ts +0 -2
  65. package/dist/cli-idioma.test.d.ts.map +0 -1
  66. package/dist/cli-idioma.test.js +0 -190
  67. package/dist/cli-idioma.test.js.map +0 -1
  68. package/dist/cli-quota.test.d.ts +0 -2
  69. package/dist/cli-quota.test.d.ts.map +0 -1
  70. package/dist/cli-quota.test.js +0 -216
  71. package/dist/cli-quota.test.js.map +0 -1
  72. package/dist/cli.d.ts.map +0 -1
  73. package/dist/cli.js.map +0 -1
  74. package/dist/cloud/auth.d.ts.map +0 -1
  75. package/dist/cloud/auth.js.map +0 -1
  76. package/dist/cloud/client.d.ts.map +0 -1
  77. package/dist/cloud/client.js.map +0 -1
  78. package/dist/cloud/errors.test.d.ts +0 -2
  79. package/dist/cloud/errors.test.d.ts.map +0 -1
  80. package/dist/cloud/errors.test.js +0 -34
  81. package/dist/cloud/errors.test.js.map +0 -1
  82. package/dist/db/schema.d.ts.map +0 -1
  83. package/dist/db/schema.js.map +0 -1
  84. package/dist/db/schema.test.d.ts +0 -2
  85. package/dist/db/schema.test.d.ts.map +0 -1
  86. package/dist/db/schema.test.js +0 -825
  87. package/dist/db/schema.test.js.map +0 -1
  88. package/dist/db/store.d.ts.map +0 -1
  89. package/dist/db/store.js.map +0 -1
  90. package/dist/demo.d.ts.map +0 -1
  91. package/dist/demo.js.map +0 -1
  92. package/dist/demo.test.d.ts +0 -2
  93. package/dist/demo.test.d.ts.map +0 -1
  94. package/dist/demo.test.js +0 -148
  95. package/dist/demo.test.js.map +0 -1
  96. package/dist/doctor.d.ts.map +0 -1
  97. package/dist/doctor.js.map +0 -1
  98. package/dist/doctor.test.d.ts +0 -2
  99. package/dist/doctor.test.d.ts.map +0 -1
  100. package/dist/doctor.test.js +0 -167
  101. package/dist/doctor.test.js.map +0 -1
  102. package/dist/export/badge.d.ts.map +0 -1
  103. package/dist/export/badge.js.map +0 -1
  104. package/dist/export/badge.test.d.ts +0 -2
  105. package/dist/export/badge.test.d.ts.map +0 -1
  106. package/dist/export/badge.test.js +0 -32
  107. package/dist/export/badge.test.js.map +0 -1
  108. package/dist/export/clockify.d.ts.map +0 -1
  109. package/dist/export/clockify.js.map +0 -1
  110. package/dist/export/clockify.test.d.ts +0 -2
  111. package/dist/export/clockify.test.d.ts.map +0 -1
  112. package/dist/export/clockify.test.js +0 -51
  113. package/dist/export/clockify.test.js.map +0 -1
  114. package/dist/export/csv.d.ts.map +0 -1
  115. package/dist/export/csv.js.map +0 -1
  116. package/dist/export/dates.d.ts.map +0 -1
  117. package/dist/export/dates.js.map +0 -1
  118. package/dist/export/idioma.test.d.ts +0 -2
  119. package/dist/export/idioma.test.d.ts.map +0 -1
  120. package/dist/export/idioma.test.js +0 -255
  121. package/dist/export/idioma.test.js.map +0 -1
  122. package/dist/export/invoice-pdf.d.ts.map +0 -1
  123. package/dist/export/invoice-pdf.js.map +0 -1
  124. package/dist/export/panel.d.ts.map +0 -1
  125. package/dist/export/panel.js.map +0 -1
  126. package/dist/export/panel.test.d.ts +0 -2
  127. package/dist/export/panel.test.d.ts.map +0 -1
  128. package/dist/export/panel.test.js +0 -386
  129. package/dist/export/panel.test.js.map +0 -1
  130. package/dist/export/pdf.d.ts.map +0 -1
  131. package/dist/export/pdf.js.map +0 -1
  132. package/dist/export/pdf.test.d.ts +0 -2
  133. package/dist/export/pdf.test.d.ts.map +0 -1
  134. package/dist/export/pdf.test.js +0 -172
  135. package/dist/export/pdf.test.js.map +0 -1
  136. package/dist/export/pixelfont.d.ts.map +0 -1
  137. package/dist/export/pixelfont.js.map +0 -1
  138. package/dist/export/png.d.ts.map +0 -1
  139. package/dist/export/png.js.map +0 -1
  140. package/dist/export/receipt.d.ts.map +0 -1
  141. package/dist/export/receipt.js.map +0 -1
  142. package/dist/export/receipt.test.d.ts +0 -2
  143. package/dist/export/receipt.test.d.ts.map +0 -1
  144. package/dist/export/receipt.test.js +0 -207
  145. package/dist/export/receipt.test.js.map +0 -1
  146. package/dist/export/share.d.ts.map +0 -1
  147. package/dist/export/share.js.map +0 -1
  148. package/dist/export/share.test.d.ts +0 -2
  149. package/dist/export/share.test.d.ts.map +0 -1
  150. package/dist/export/share.test.js +0 -116
  151. package/dist/export/share.test.js.map +0 -1
  152. package/dist/i18n/en.d.ts.map +0 -1
  153. package/dist/i18n/en.js.map +0 -1
  154. package/dist/i18n/i18n.test.d.ts +0 -2
  155. package/dist/i18n/i18n.test.d.ts.map +0 -1
  156. package/dist/i18n/i18n.test.js +0 -226
  157. package/dist/i18n/i18n.test.js.map +0 -1
  158. package/dist/i18n/index.d.ts.map +0 -1
  159. package/dist/i18n/index.js.map +0 -1
  160. package/dist/i18n/labels.d.ts.map +0 -1
  161. package/dist/i18n/labels.js.map +0 -1
  162. package/dist/metrics/index.d.ts.map +0 -1
  163. package/dist/metrics/index.js.map +0 -1
  164. package/dist/metrics/metrics.test.d.ts +0 -2
  165. package/dist/metrics/metrics.test.d.ts.map +0 -1
  166. package/dist/metrics/metrics.test.js +0 -162
  167. package/dist/metrics/metrics.test.js.map +0 -1
  168. package/dist/metrics/people.d.ts.map +0 -1
  169. package/dist/metrics/people.js.map +0 -1
  170. package/dist/metrics/people.test.d.ts +0 -2
  171. package/dist/metrics/people.test.d.ts.map +0 -1
  172. package/dist/metrics/people.test.js +0 -92
  173. package/dist/metrics/people.test.js.map +0 -1
  174. package/dist/metrics/quota.d.ts.map +0 -1
  175. package/dist/metrics/quota.js.map +0 -1
  176. package/dist/metrics/quota.test.d.ts +0 -2
  177. package/dist/metrics/quota.test.d.ts.map +0 -1
  178. package/dist/metrics/quota.test.js +0 -262
  179. package/dist/metrics/quota.test.js.map +0 -1
  180. package/dist/metrics/team.d.ts.map +0 -1
  181. package/dist/metrics/team.js.map +0 -1
  182. package/dist/metrics/team.test.d.ts +0 -2
  183. package/dist/metrics/team.test.d.ts.map +0 -1
  184. package/dist/metrics/team.test.js +0 -90
  185. package/dist/metrics/team.test.js.map +0 -1
  186. package/dist/node-version.d.ts.map +0 -1
  187. package/dist/node-version.js.map +0 -1
  188. package/dist/node-version.test.d.ts +0 -2
  189. package/dist/node-version.test.d.ts.map +0 -1
  190. package/dist/node-version.test.js +0 -53
  191. package/dist/node-version.test.js.map +0 -1
  192. package/dist/paths.d.ts.map +0 -1
  193. package/dist/paths.js.map +0 -1
  194. package/dist/paths.test.d.ts +0 -2
  195. package/dist/paths.test.d.ts.map +0 -1
  196. package/dist/paths.test.js +0 -32
  197. package/dist/paths.test.js.map +0 -1
  198. package/dist/pricing/catalog.d.ts.map +0 -1
  199. package/dist/pricing/catalog.js.map +0 -1
  200. package/dist/pricing/cost.d.ts.map +0 -1
  201. package/dist/pricing/cost.js.map +0 -1
  202. package/dist/pricing/cost.test.d.ts +0 -2
  203. package/dist/pricing/cost.test.d.ts.map +0 -1
  204. package/dist/pricing/cost.test.js +0 -100
  205. package/dist/pricing/cost.test.js.map +0 -1
  206. package/dist/publish.d.ts.map +0 -1
  207. package/dist/publish.js.map +0 -1
  208. package/dist/publish.test.d.ts +0 -2
  209. package/dist/publish.test.d.ts.map +0 -1
  210. package/dist/publish.test.js +0 -113
  211. package/dist/publish.test.js.map +0 -1
  212. package/dist/quota.d.ts.map +0 -1
  213. package/dist/quota.js.map +0 -1
  214. package/dist/server.d.ts.map +0 -1
  215. package/dist/server.js.map +0 -1
  216. package/dist/server.test.d.ts +0 -2
  217. package/dist/server.test.d.ts.map +0 -1
  218. package/dist/server.test.js +0 -402
  219. package/dist/server.test.js.map +0 -1
  220. package/dist/setup.d.ts.map +0 -1
  221. package/dist/setup.js.map +0 -1
  222. package/dist/setup.test.d.ts +0 -2
  223. package/dist/setup.test.d.ts.map +0 -1
  224. package/dist/setup.test.js +0 -144
  225. package/dist/setup.test.js.map +0 -1
  226. package/dist/sync/team.d.ts.map +0 -1
  227. package/dist/sync/team.js.map +0 -1
  228. package/dist/sync/team.test.d.ts +0 -2
  229. package/dist/sync/team.test.d.ts.map +0 -1
  230. package/dist/sync/team.test.js +0 -102
  231. package/dist/sync/team.test.js.map +0 -1
  232. package/dist/sync.d.ts.map +0 -1
  233. package/dist/sync.js.map +0 -1
  234. package/dist/sync.test.d.ts +0 -2
  235. package/dist/sync.test.d.ts.map +0 -1
  236. package/dist/sync.test.js +0 -151
  237. package/dist/sync.test.js.map +0 -1
  238. package/dist/team.d.ts.map +0 -1
  239. package/dist/team.js.map +0 -1
  240. package/dist/team.test.d.ts +0 -2
  241. package/dist/team.test.d.ts.map +0 -1
  242. package/dist/team.test.js +0 -163
  243. package/dist/team.test.js.map +0 -1
  244. package/dist/updateCheck.d.ts.map +0 -1
  245. package/dist/updateCheck.js.map +0 -1
  246. package/dist/updateCheck.test.d.ts +0 -2
  247. package/dist/updateCheck.test.d.ts.map +0 -1
  248. package/dist/updateCheck.test.js +0 -27
  249. package/dist/updateCheck.test.js.map +0 -1
  250. package/dist/watchers/agents.d.ts.map +0 -1
  251. package/dist/watchers/agents.js.map +0 -1
  252. package/dist/watchers/agents.test.d.ts +0 -2
  253. package/dist/watchers/agents.test.d.ts.map +0 -1
  254. package/dist/watchers/agents.test.js +0 -96
  255. package/dist/watchers/agents.test.js.map +0 -1
  256. package/dist/watchers/claude.d.ts.map +0 -1
  257. package/dist/watchers/claude.js.map +0 -1
  258. package/dist/watchers/claude.test.d.ts +0 -2
  259. package/dist/watchers/claude.test.d.ts.map +0 -1
  260. package/dist/watchers/claude.test.js +0 -180
  261. package/dist/watchers/claude.test.js.map +0 -1
  262. package/dist/watchers/codex.d.ts.map +0 -1
  263. package/dist/watchers/codex.js.map +0 -1
  264. package/dist/watchers/codex.test.d.ts +0 -2
  265. package/dist/watchers/codex.test.d.ts.map +0 -1
  266. package/dist/watchers/codex.test.js +0 -207
  267. package/dist/watchers/codex.test.js.map +0 -1
  268. package/dist/watchers/copilot.d.ts.map +0 -1
  269. package/dist/watchers/copilot.js.map +0 -1
  270. package/dist/watchers/copilot.test.d.ts +0 -2
  271. package/dist/watchers/copilot.test.d.ts.map +0 -1
  272. package/dist/watchers/copilot.test.js +0 -98
  273. package/dist/watchers/copilot.test.js.map +0 -1
  274. package/dist/watchers/git.d.ts.map +0 -1
  275. package/dist/watchers/git.js.map +0 -1
  276. package/dist/watchers/git.test.d.ts +0 -2
  277. package/dist/watchers/git.test.d.ts.map +0 -1
  278. package/dist/watchers/git.test.js +0 -75
  279. package/dist/watchers/git.test.js.map +0 -1
  280. package/dist/watchers/identity.d.ts.map +0 -1
  281. package/dist/watchers/identity.js.map +0 -1
  282. package/dist/watchers/identity.test.d.ts +0 -2
  283. package/dist/watchers/identity.test.d.ts.map +0 -1
  284. package/dist/watchers/identity.test.js +0 -48
  285. package/dist/watchers/identity.test.js.map +0 -1
  286. package/dist/web-ui.test.d.ts +0 -2
  287. package/dist/web-ui.test.d.ts.map +0 -1
  288. package/dist/web-ui.test.js +0 -414
  289. package/dist/web-ui.test.js.map +0 -1
  290. package/dist/workitems.test.d.ts +0 -2
  291. package/dist/workitems.test.d.ts.map +0 -1
  292. package/dist/workitems.test.js +0 -59
  293. package/dist/workitems.test.js.map +0 -1
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OUR_COMMAND = void 0;
4
+ exports.claudeSettingsPath = claudeSettingsPath;
5
+ exports.isOurs = isOurs;
6
+ exports.shellQuote = shellQuote;
7
+ exports.appendedCommand = appendedCommand;
8
+ exports.planInstall = planInstall;
9
+ exports.planUninstall = planUninstall;
10
+ exports.estelaOnPath = estelaOnPath;
11
+ exports.backupName = backupName;
12
+ const node_fs_1 = require("node:fs");
13
+ const node_os_1 = require("node:os");
14
+ const node_path_1 = require("node:path");
15
+ /**
16
+ * `estela statusline install | uninstall`: el bloque `statusLine` de
17
+ * `~/.claude/settings.json`.
18
+ *
19
+ * Ese fichero es de quien usa Claude Code, con sus permisos, sus hooks y sus
20
+ * plugins. Se toca lo justo: se lee, se cambia una clave y se reescribe el
21
+ * resto tal cual; antes, una copia. Si ya hay otra status line, no se pisa.
22
+ *
23
+ * Funciones puras sobre el texto del fichero: quien llama lee y escribe.
24
+ */
25
+ exports.OUR_COMMAND = "estela statusline";
26
+ /** Dónde vive la configuración de Claude Code (`CLAUDE_CONFIG_DIR` la mueve). */
27
+ function claudeSettingsPath(env = process.env) {
28
+ return (0, node_path_1.join)(env["CLAUDE_CONFIG_DIR"] || (0, node_path_1.join)((0, node_os_1.homedir)(), ".claude"), "settings.json");
29
+ }
30
+ function parse(text) {
31
+ if (text === null || !text.trim())
32
+ return {};
33
+ try {
34
+ const v = JSON.parse(text);
35
+ return v && typeof v === "object" && !Array.isArray(v) ? v : null;
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ function commandOf(statusLine) {
42
+ if (!statusLine || typeof statusLine !== "object")
43
+ return null;
44
+ const c = statusLine["command"];
45
+ return typeof c === "string" ? c : null;
46
+ }
47
+ function isOurs(command) {
48
+ return !!command && /(^|[\s/\\])estela(\.cmd)?\s+statusline(\s|$)/.test(command);
49
+ }
50
+ /** Comillas simples de shell: lo que va dentro se pasa tal cual. */
51
+ function shellQuote(text) {
52
+ return `'${text.replace(/'/g, `'\\''`)}'`;
53
+ }
54
+ /** El comando encadenado dentro de `--append '…'`, si lo hay. */
55
+ function appendedCommand(command) {
56
+ const m = /--append\s+'((?:[^']|'\\'')*)'\s*$/.exec(command);
57
+ return m ? m[1].replace(/'\\''/g, "'") : null;
58
+ }
59
+ function write(settings) {
60
+ return JSON.stringify(settings, null, 2) + "\n";
61
+ }
62
+ function planInstall(text, options = {}) {
63
+ const settings = parse(text);
64
+ if (!settings)
65
+ return { status: "invalid" };
66
+ const existing = commandOf(settings["statusLine"]);
67
+ if (existing && isOurs(existing) && !options.force)
68
+ return { status: "already" };
69
+ let command = exports.OUR_COMMAND;
70
+ let status = "installed";
71
+ if (existing && !isOurs(existing)) {
72
+ if (options.append) {
73
+ command = `${exports.OUR_COMMAND} --append ${shellQuote(existing)}`;
74
+ status = "chained";
75
+ }
76
+ else if (options.force)
77
+ status = "replaced";
78
+ else
79
+ return { status: "conflict", existing };
80
+ }
81
+ settings["statusLine"] = { type: "command", command, padding: 0 };
82
+ return { status, text: write(settings), previous: existing };
83
+ }
84
+ function planUninstall(text) {
85
+ const settings = parse(text);
86
+ if (!settings)
87
+ return { status: "invalid" };
88
+ const existing = commandOf(settings["statusLine"]);
89
+ if (!existing)
90
+ return { status: "absent" };
91
+ if (!isOurs(existing))
92
+ return { status: "foreign", existing };
93
+ // Si al instalar se encadenó otra, se devuelve esa: quitar Estela no puede
94
+ // dejarte sin la status line que ya tenías.
95
+ const before = appendedCommand(existing);
96
+ if (before) {
97
+ settings["statusLine"] = { type: "command", command: before };
98
+ return { status: "restored", text: write(settings), restored: before };
99
+ }
100
+ delete settings["statusLine"];
101
+ return { status: "removed", text: write(settings), restored: null };
102
+ }
103
+ /** `estela` en el PATH. Con `npx` cada evento tardaría cientos de milisegundos. */
104
+ function estelaOnPath(env = process.env, platform = process.platform) {
105
+ const names = platform === "win32" ? ["estela.cmd", "estela.exe", "estela"] : ["estela"];
106
+ return (env["PATH"] ?? "").split(node_path_1.delimiter).filter(Boolean)
107
+ .some((dir) => names.some((n) => (0, node_fs_1.existsSync)((0, node_path_1.join)(dir, n))));
108
+ }
109
+ /** "settings.json.bak-20261014-161230": una copia por instalación, sin pisar las anteriores. */
110
+ function backupName(path, now = new Date()) {
111
+ const p = (n) => String(n).padStart(2, "0");
112
+ return `${path}.bak-${now.getFullYear()}${p(now.getMonth() + 1)}${p(now.getDate())}-` +
113
+ `${p(now.getHours())}${p(now.getMinutes())}${p(now.getSeconds())}`;
114
+ }
115
+ //# sourceMappingURL=statusline-install.js.map
@@ -0,0 +1,8 @@
1
+ import { type StatusData, type StatusInput } from "./statusline.js";
2
+ export declare function runStatusline(argv: readonly string[]): Promise<void>;
3
+ /**
4
+ * Los datos de la línea para un directorio. Sin base de Estela no se crea
5
+ * ninguna: la status line no es quien debe empezar a guardar datos.
6
+ */
7
+ export declare function computeStatus(input: StatusInput, dbPath: string, now: Date): StatusData;
8
+ //# sourceMappingURL=statusline-run.d.ts.map
@@ -0,0 +1,256 @@
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.runStatusline = runStatusline;
37
+ exports.computeStatus = computeStatus;
38
+ const node_child_process_1 = require("node:child_process");
39
+ const node_fs_1 = require("node:fs");
40
+ const sessionize_js_1 = require("./billing/sessionize.js");
41
+ const schema_js_1 = require("./db/schema.js");
42
+ const store = __importStar(require("./db/store.js"));
43
+ const quota_js_1 = require("./metrics/quota.js");
44
+ const paths_js_1 = require("./paths.js");
45
+ const project_of_js_1 = require("./project-of.js");
46
+ const statusline_cache_js_1 = require("./statusline-cache.js");
47
+ const statusline_js_1 = require("./statusline.js");
48
+ const claude_js_1 = require("./watchers/claude.js");
49
+ async function runStatusline(argv) {
50
+ try {
51
+ const flags = parseFlags(argv);
52
+ const text = await readStdin();
53
+ const input = text.trim() ? (0, statusline_js_1.parseStatusInput)(text) : manualInput();
54
+ const extra = flags.append ? runAppended(flags.append, text) : null;
55
+ const reserved = extra ? (0, statusline_js_1.stripAnsi)(extra).length + 3 : 0;
56
+ const columns = Number(process.env["COLUMNS"]) || null;
57
+ const now = new Date();
58
+ if (input.fiveHourResetsAt) {
59
+ try {
60
+ (0, statusline_cache_js_1.recordFiveHourReset)(flags.db, input.fiveHourResetsAt, now);
61
+ }
62
+ catch { /* es una caché */ }
63
+ }
64
+ const data = computeStatus(input, flags.db, now);
65
+ const ours = (0, statusline_js_1.renderStatus)(data, { columns, color: flags.color, reserved });
66
+ process.stdout.write((extra ? `${ours}${flags.color ? "\x1b[90m | \x1b[0m" : " | "}${extra}` : ours) + "\n");
67
+ }
68
+ catch {
69
+ process.stdout.write("estela\n");
70
+ }
71
+ process.exitCode = 0;
72
+ }
73
+ function parseFlags(argv) {
74
+ const value = (name) => {
75
+ const i = argv.indexOf(`--${name}`);
76
+ return i >= 0 && i + 1 < argv.length ? argv[i + 1] : null;
77
+ };
78
+ return {
79
+ db: value("db") ?? schema_js_1.DEFAULT_DB_PATH,
80
+ color: !argv.includes("--no-color") && !process.env["NO_COLOR"],
81
+ append: value("append"),
82
+ };
83
+ }
84
+ /** Ejecutado a mano en una terminal, sin nada por stdin: el directorio actual. */
85
+ function manualInput() {
86
+ return { dir: process.cwd(), transcriptPath: null, fiveHour: null, sevenDay: null, fiveHourResetsAt: null };
87
+ }
88
+ function readStdin() {
89
+ if (process.stdin.isTTY)
90
+ return Promise.resolve("");
91
+ return new Promise((resolve) => {
92
+ let data = "";
93
+ process.stdin.setEncoding("utf8");
94
+ process.stdin.on("data", (chunk) => { data += chunk; });
95
+ process.stdin.on("end", () => resolve(data));
96
+ process.stdin.on("error", () => resolve(data));
97
+ });
98
+ }
99
+ /**
100
+ * Otra status line encadenada (la que había antes de instalar la de Estela).
101
+ * Recibe el mismo stdin. Si tarda o falla, se enseña solo la nuestra.
102
+ */
103
+ function runAppended(command, stdin) {
104
+ try {
105
+ const r = (0, node_child_process_1.spawnSync)(command, { shell: true, input: stdin, encoding: "utf8", timeout: 1500 });
106
+ const line = (r.stdout ?? "").split("\n")[0]?.trimEnd();
107
+ return line ? line : null;
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ // ---------------------------------------------------------------------------
114
+ /**
115
+ * Los datos de la línea para un directorio. Sin base de Estela no se crea
116
+ * ninguna: la status line no es quien debe empezar a guardar datos.
117
+ */
118
+ function computeStatus(input, dbPath, now) {
119
+ const sinProyecto = (root) => ({
120
+ project: null, unassignedRoot: root, todaySeconds: 0, projectShare: null,
121
+ fiveHour: input.fiveHour, sevenDay: input.sevenDay
122
+ });
123
+ if (!input.dir)
124
+ return sinProyecto(null);
125
+ if (!(0, node_fs_1.existsSync)(dbPath)) {
126
+ const root = (0, project_of_js_1.gitRoot)(input.dir);
127
+ return sinProyecto(root ? (0, project_of_js_1.folderName)(root) : null);
128
+ }
129
+ const db = (0, schema_js_1.openDatabase)(dbPath);
130
+ try {
131
+ // Si `import` o el panel están escribiendo, se espera muy poco y se sigue.
132
+ db.exec("PRAGMA busy_timeout = 50");
133
+ const dir = (0, paths_js_1.normalizePath)(input.dir);
134
+ // La carpeta, y si no, su raíz git (worktrees, subcarpetas): ver project-of.ts.
135
+ const ownerOf = (0, project_of_js_1.ownerResolver)(db);
136
+ const owner = ownerOf(dir);
137
+ if (owner.kind !== "project")
138
+ return sinProyecto(owner.kind === "folder" && owner.inGit ? owner.name : null);
139
+ const projectId = owner.projectId;
140
+ const project = store.getProject(db, projectId);
141
+ if (!project)
142
+ return sinProyecto(null);
143
+ const client = project.kind === "client" ? store.getClient(db, project.clientId) : null;
144
+ const fresh = input.transcriptPath ? readNewTurns(db, dbPath, input.transcriptPath, dir) : [];
145
+ const projectOf = (repo) => {
146
+ const o = ownerOf(repo);
147
+ return o.kind === "project" ? o.projectId : null;
148
+ };
149
+ // Horas medidas de hoy: lo mismo que hace `import` — sessionize y luego
150
+ // la unión de intervalos por proyecto, día y rama — sobre los turnos de
151
+ // hoy de este proyecto. Solo medidas: nada estimado ni anotado a mano.
152
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
153
+ const todayTurns = merge(store.turnsBetween(db, today, new Date(now.getTime() + 1)), fresh, today, now)
154
+ .filter((t) => projectOf(t.repoPath) === projectId);
155
+ const blocks = (0, sessionize_js_1.groupByBranchAndDay)((0, sessionize_js_1.sessionize)(todayTurns), () => projectId);
156
+ const todaySeconds = blocks.reduce((s, b) => s + b.seconds, 0);
157
+ // Parte de la semana: la misma suma de tokens que `estela quota`, solo de
158
+ // Claude Code (Codex gasta otra cuota).
159
+ const monday = (0, quota_js_1.weekStart)(now);
160
+ const week = merge(store.turnsBetween(db, monday, new Date(now.getTime() + 1)), fresh, monday, now)
161
+ .filter((t) => t.agent === "claude-code");
162
+ const bucketOf = (repo) => {
163
+ const p = projectOf(repo);
164
+ return p ? { kind: "project", projectId: p, projectName: p } : { kind: "none" };
165
+ };
166
+ const split = (0, quota_js_1.breakdown)(week, monday, new Date(now.getTime() + 1), bucketOf);
167
+ const row = split.rows.find((r) => r.bucket.kind === "project" && r.bucket.projectId === projectId);
168
+ const projectShare = split.total.total > 0 ? (row?.share ?? 0) : null;
169
+ return {
170
+ project: { name: project.name, client: client?.name ?? null },
171
+ todaySeconds, projectShare, fiveHour: input.fiveHour, sevenDay: input.sevenDay,
172
+ };
173
+ }
174
+ finally {
175
+ db.close();
176
+ }
177
+ }
178
+ /** Los turnos guardados más los recién leídos, sin repetir y dentro del rango. */
179
+ function merge(saved, fresh, from, to) {
180
+ const seen = new Set(saved.map((t) => t.turnId));
181
+ return [...saved, ...fresh.filter((t) => !seen.has(t.turnId) && t.at >= from && t.at <= to)]
182
+ .sort((a, b) => a.at.getTime() - b.at.getTime());
183
+ }
184
+ // ---------------------------------------------------------------------------
185
+ // Lectura incremental del transcript de la sesión
186
+ // ---------------------------------------------------------------------------
187
+ /** Lo más que se lee de un transcript que se ve por primera vez. */
188
+ const FIRST_READ_BYTES = 4 * 1024 * 1024;
189
+ /**
190
+ * Lee solo lo nuevo del transcript de esta sesión desde la última vez, y lo
191
+ * guarda en la base.
192
+ *
193
+ * - Se avanza hasta el último salto de línea: Claude Code puede estar
194
+ * escribiendo la última, y una línea a medias se leerá entera la próxima.
195
+ * - Si el fichero encoge, se empieza de nuevo.
196
+ * - La primera vez se leen como mucho los últimos 4 MB: el resto ya lo trajo
197
+ * `import`, y una sesión larga no puede costar segundos.
198
+ * - `INSERT OR IGNORE` sobre el `turn_id`: el siguiente `import` no duplica.
199
+ * - Un turno de scratchpad que no se pudo devolver a su repositorio NO se
200
+ * guarda: con esa ruta se quedaría así para siempre, porque el `import`
201
+ * que sí sabría devolverlo ya no podría reescribirlo.
202
+ */
203
+ function readNewTurns(db, dbPath, file, dir) {
204
+ const cache = (0, statusline_cache_js_1.loadCache)(dbPath);
205
+ const entry = cache.files[file];
206
+ let fd;
207
+ try {
208
+ fd = (0, node_fs_1.openSync)(file, "r");
209
+ }
210
+ catch {
211
+ return [];
212
+ }
213
+ try {
214
+ const size = (0, node_fs_1.fstatSync)(fd).size;
215
+ let start = entry && entry.offset <= size ? entry.offset : Math.max(0, size - FIRST_READ_BYTES);
216
+ const midFile = !entry && start > 0;
217
+ if (start >= size) {
218
+ cache.files[file] = { offset: size, seenAt: new Date().toISOString() };
219
+ (0, statusline_cache_js_1.saveCache)(dbPath, cache);
220
+ return [];
221
+ }
222
+ const buf = Buffer.alloc(size - start);
223
+ (0, node_fs_1.readSync)(fd, buf, 0, buf.length, start);
224
+ const lastNl = buf.lastIndexOf(0x0a);
225
+ if (lastNl < 0)
226
+ return [];
227
+ let text = buf.subarray(0, lastNl + 1).toString("utf8");
228
+ // Empezando a mitad de fichero, la primera línea casi seguro está cortada.
229
+ if (midFile)
230
+ text = text.slice(text.indexOf("\n") + 1);
231
+ const byId = new Map();
232
+ for (const line of text.split("\n")) {
233
+ const t = (0, claude_js_1.parseTranscriptLine)(line);
234
+ if (t && typeof t === "object" && !byId.has(t.turnId))
235
+ byId.set(t.turnId, t);
236
+ }
237
+ const known = [...store.allProjectRepoPaths(db), dir];
238
+ const turns = (0, claude_js_1.resolveScratchpads)([...byId.values()], known)
239
+ .filter((t) => !t.repoPath || !(0, claude_js_1.isScratchpad)(t.repoPath));
240
+ try {
241
+ store.saveTurns(db, turns);
242
+ start += lastNl + 1;
243
+ cache.files[file] = { offset: start, seenAt: new Date().toISOString() };
244
+ (0, statusline_cache_js_1.saveCache)(dbPath, cache);
245
+ }
246
+ catch {
247
+ // Base ocupada: no se avanza, para volver a intentarlo. Los turnos sirven
248
+ // igual para esta línea, desde la memoria.
249
+ }
250
+ return turns;
251
+ }
252
+ finally {
253
+ (0, node_fs_1.closeSync)(fd);
254
+ }
255
+ }
256
+ //# sourceMappingURL=statusline-run.js.map
@@ -0,0 +1,71 @@
1
+ /**
2
+ * `estela statusline`: la línea que Claude Code pinta bajo cada sesión.
3
+ *
4
+ * Funciones puras, sin disco ni base de datos: qué llega por stdin, qué se
5
+ * enseña y cómo se recorta. Lo que lee datos vive en `statusline-run.ts`.
6
+ *
7
+ * La regla de siempre: nada de "te queda X" ni cuentas atrás. Los porcentajes
8
+ * de límite son los que manda Claude Code (`rate_limits`), tal cual; si no
9
+ * los manda, no se enseña nada de límites. Estela no estima ninguno.
10
+ */
11
+ /** Lo que interesa del JSON que Claude Code pasa por stdin. Todo opcional. */
12
+ export interface StatusInput {
13
+ readonly dir: string | null;
14
+ readonly transcriptPath: string | null;
15
+ /** 0–100, de `rate_limits.five_hour.used_percentage`. */
16
+ readonly fiveHour: number | null;
17
+ /** 0–100, de `rate_limits.seven_day.used_percentage`. */
18
+ readonly sevenDay: number | null;
19
+ /**
20
+ * `rate_limits.five_hour.resets_at`. No se enseña nunca (nada de cuentas
21
+ * atrás): se guarda para que `estela quota` sepa dónde empieza la ventana.
22
+ */
23
+ readonly fiveHourResetsAt?: Date | null;
24
+ }
25
+ /**
26
+ * Lee la entrada. Lanza si no es un objeto JSON: quien llama imprime
27
+ * "estela" y sale con 0, que es lo que hay que hacer con una entrada rota.
28
+ */
29
+ export declare function parseStatusInput(text: string): StatusInput;
30
+ /** Lo que se sabe del proyecto del directorio actual. */
31
+ export interface StatusData {
32
+ /** null: el directorio no es de ningún proyecto de Estela. */
33
+ readonly project: {
34
+ readonly name: string;
35
+ readonly client: string | null;
36
+ } | null;
37
+ /**
38
+ * Sin proyecto: el nombre de la raíz git de la carpeta, para decir cuál
39
+ * es. null si está fuera de git.
40
+ */
41
+ readonly unassignedRoot?: string | null;
42
+ /** Horas medidas hoy en este proyecto. */
43
+ readonly todaySeconds: number;
44
+ /** Parte de los tokens de Claude Code de esta semana que son de este proyecto (0–1), o null si no hubo consumo. */
45
+ readonly projectShare: number | null;
46
+ readonly fiveHour: number | null;
47
+ readonly sevenDay: number | null;
48
+ }
49
+ export interface RenderOptions {
50
+ /** Ancho del terminal (`COLUMNS`). Sin él, no se recorta. */
51
+ readonly columns?: number | null;
52
+ readonly color?: boolean;
53
+ /** Ancho que ya ocupa otra status line encadenada con --append. */
54
+ readonly reserved?: number;
55
+ }
56
+ /** Desde qué porcentaje la ventana de 5 h se pinta en ámbar. */
57
+ export declare const FIVE_HOUR_WARN = 80;
58
+ /** "2h14", "3h", "45m": corto, que la línea es estrecha. */
59
+ export declare function compactDuration(seconds: number): string;
60
+ /**
61
+ * La línea, ya recortada al ancho.
62
+ *
63
+ * Orden visual: estela · nombre · hoy · este proyecto · semana · 5 h.
64
+ * Lo que se quita si no cabe, en este orden: la 5 h, la semana, el nombre se
65
+ * queda en el cliente y luego se acorta con "…", "este proyecto" y "hoy".
66
+ * "estela" no se quita nunca: es lo que anuncia la herramienta en cada captura.
67
+ */
68
+ export declare function renderStatus(data: StatusData, options?: RenderOptions): string;
69
+ /** Lo visible de una cadena con color: para medir y para los tests. */
70
+ export declare function stripAnsi(text: string): string;
71
+ //# sourceMappingURL=statusline.d.ts.map
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FIVE_HOUR_WARN = void 0;
4
+ exports.parseStatusInput = parseStatusInput;
5
+ exports.compactDuration = compactDuration;
6
+ exports.renderStatus = renderStatus;
7
+ exports.stripAnsi = stripAnsi;
8
+ const index_js_1 = require("./i18n/index.js");
9
+ /**
10
+ * Lee la entrada. Lanza si no es un objeto JSON: quien llama imprime
11
+ * "estela" y sale con 0, que es lo que hay que hacer con una entrada rota.
12
+ */
13
+ function parseStatusInput(text) {
14
+ const raw = JSON.parse(text);
15
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
16
+ throw new Error("bad-input");
17
+ const o = raw;
18
+ const ws = obj(o["workspace"]);
19
+ const limits = obj(o["rate_limits"]);
20
+ return {
21
+ dir: str(ws["project_dir"]) ?? str(ws["current_dir"]) ?? str(o["cwd"]),
22
+ transcriptPath: str(o["transcript_path"]),
23
+ fiveHour: pct(obj(limits["five_hour"])["used_percentage"]),
24
+ sevenDay: pct(obj(limits["seven_day"])["used_percentage"]),
25
+ fiveHourResetsAt: epoch(obj(limits["five_hour"])["resets_at"]),
26
+ };
27
+ }
28
+ /** Segundos desde 1970 (lo que manda Claude Code); por si acaso, también milisegundos. */
29
+ function epoch(v) {
30
+ if (typeof v !== "number" || !Number.isFinite(v) || v <= 0)
31
+ return null;
32
+ return new Date(v > 1e12 ? v : v * 1000);
33
+ }
34
+ function obj(v) {
35
+ return v && typeof v === "object" && !Array.isArray(v) ? v : {};
36
+ }
37
+ function str(v) {
38
+ return typeof v === "string" && v ? v : null;
39
+ }
40
+ function pct(v) {
41
+ return typeof v === "number" && Number.isFinite(v) && v >= 0 ? Math.min(v, 100) : null;
42
+ }
43
+ /** Desde qué porcentaje la ventana de 5 h se pinta en ámbar. */
44
+ exports.FIVE_HOUR_WARN = 80;
45
+ const SEP = " · ";
46
+ const ESC = "\x1b[";
47
+ const JADE = `${ESC}38;2;70;192;167m`; // #46C0A7
48
+ const GRAY = `${ESC}90m`;
49
+ const AMBER = `${ESC}38;2;221;168;90m`; // el ámbar del panel en modo oscuro
50
+ const RESET = `${ESC}0m`;
51
+ /** "2h14", "3h", "45m": corto, que la línea es estrecha. */
52
+ function compactDuration(seconds) {
53
+ const total = Math.round(seconds / 60);
54
+ const h = Math.floor(total / 60), m = total % 60;
55
+ if (h === 0)
56
+ return `${m}m`;
57
+ return m === 0 ? `${h}h` : `${h}h${String(m).padStart(2, "0")}`;
58
+ }
59
+ /**
60
+ * La línea, ya recortada al ancho.
61
+ *
62
+ * Orden visual: estela · nombre · hoy · este proyecto · semana · 5 h.
63
+ * Lo que se quita si no cabe, en este orden: la 5 h, la semana, el nombre se
64
+ * queda en el cliente y luego se acorta con "…", "este proyecto" y "hoy".
65
+ * "estela" no se quita nunca: es lo que anuncia la herramienta en cada captura.
66
+ */
67
+ function renderStatus(data, options = {}) {
68
+ const color = options.color !== false;
69
+ const paint = (c, t) => (color ? `${c}${t}${RESET}` : t);
70
+ const width = options.columns && options.columns > 0
71
+ ? Math.max(0, options.columns - (options.reserved ?? 0)) : Infinity;
72
+ const line = (shown, kept) => paint(JADE, "estela") + paint(GRAY, SEP + shown) +
73
+ kept.map((x) => paint(GRAY, SEP) + paint(x.warn ? AMBER : GRAY, x.text)).join("");
74
+ const tailOf = (kept) => kept.map((x) => SEP + x.text).join("").length;
75
+ if (!data.project) {
76
+ // "estela · web (sin proyecto) · semana 38 % · 5 h 62 % · estela setup".
77
+ // Fuera de git no hay nombre que dar ni nada que configurar ahí, así que
78
+ // sin raíz y sin pista: "estela · sin proyecto · semana 38 % · 5 h 62 %".
79
+ // Se recorta la pista, luego 5 h y semana, y por último se acorta la raíz.
80
+ const root = data.unassignedRoot ?? null;
81
+ const segs = [...limitSegments(data), ...(root ? [{ key: "hint", text: "estela setup" }] : [])];
82
+ const steps = [[], ["hint"], ["hint", "fiveHour"], ["hint", "fiveHour", "week"]];
83
+ for (const drop of steps) {
84
+ const kept = segs.filter((x) => !drop.includes(x.key));
85
+ const shown = root ? (0, index_js_1.tr) `${root} (sin proyecto)` : (0, index_js_1.tr) `sin proyecto`;
86
+ if ("estela".length + SEP.length + shown.length + tailOf(kept) <= width)
87
+ return line(shown, kept);
88
+ }
89
+ if (root) {
90
+ const room = width - "estela".length - SEP.length - (0, index_js_1.tr) `${""} (sin proyecto)`.length;
91
+ if (room >= 2)
92
+ return line((0, index_js_1.tr) `${root.slice(0, room - 1).trimEnd() + "…"} (sin proyecto)`, []);
93
+ }
94
+ return paint(JADE, "estela");
95
+ }
96
+ const segs = [{ key: "today", text: (0, index_js_1.tr) `hoy ${compactDuration(data.todaySeconds)}` }];
97
+ if (data.projectShare !== null)
98
+ segs.push({ key: "project", text: (0, index_js_1.tr) `este proyecto ${Math.round(data.projectShare * 100)} %` });
99
+ segs.push(...limitSegments(data));
100
+ const { name, client } = data.project;
101
+ const full = client ? `${client} › ${name}` : name;
102
+ const short = client ?? name;
103
+ const steps = [
104
+ { drop: [], name: "full" },
105
+ { drop: ["fiveHour"], name: "full" },
106
+ { drop: ["fiveHour", "week"], name: "full" },
107
+ { drop: ["fiveHour", "week"], name: "short" },
108
+ { drop: ["fiveHour", "week"], name: "trunc", min: 6 },
109
+ { drop: ["fiveHour", "week", "project"], name: "trunc", min: 6 },
110
+ { drop: ["fiveHour", "week", "project", "today"], name: "trunc", min: 2 },
111
+ ];
112
+ for (const step of steps) {
113
+ const kept = segs.filter((s) => !step.drop.includes(s.key));
114
+ const tail = kept.map((s) => SEP + s.text).join("");
115
+ const fixed = "estela".length + SEP.length + tail.length;
116
+ let shown;
117
+ if (step.name === "full")
118
+ shown = full;
119
+ else if (step.name === "short")
120
+ shown = short;
121
+ else {
122
+ const room = width - fixed;
123
+ if (room < (step.min ?? 1))
124
+ continue;
125
+ shown = short.length <= room ? short : short.slice(0, Math.max(0, room - 1)).trimEnd() + "…";
126
+ }
127
+ if (fixed + shown.length > width)
128
+ continue;
129
+ return line(shown, kept);
130
+ }
131
+ return paint(JADE, "estela");
132
+ }
133
+ /**
134
+ * Los porcentajes de límite que manda Claude Code, tal cual: semana y 5 h, la
135
+ * de 5 h en ámbar desde el 80 %. Sin rate_limits, ninguno. Los comparten la
136
+ * línea con proyecto y la de sin proyecto.
137
+ */
138
+ function limitSegments(data) {
139
+ const out = [];
140
+ if (data.sevenDay !== null)
141
+ out.push({ key: "week", text: (0, index_js_1.tr) `semana ${Math.round(data.sevenDay)} %` });
142
+ if (data.fiveHour !== null) {
143
+ out.push({ key: "fiveHour", text: (0, index_js_1.tr) `5 h ${Math.round(data.fiveHour)} %`, warn: data.fiveHour >= exports.FIVE_HOUR_WARN });
144
+ }
145
+ return out;
146
+ }
147
+ /** Lo visible de una cadena con color: para medir y para los tests. */
148
+ function stripAnsi(text) {
149
+ // eslint-disable-next-line no-control-regex
150
+ return text.replace(/\x1b\[[0-9;]*m/g, "");
151
+ }
152
+ //# sourceMappingURL=statusline.js.map
@@ -12,6 +12,13 @@ export interface ScanResult {
12
12
  readonly report: ParseReport;
13
13
  }
14
14
  export declare function scanClaudeCode(options?: ScanOptions): Promise<ScanResult>;
15
+ /**
16
+ * Una línea del transcript: un turno, `"other"` si es de otro tipo (maquinaria
17
+ * interna que se ignora), `"malformed"` si no se entiende, o null si está en
18
+ * blanco. Es lo que usan tanto el escaneo completo como `estela statusline`,
19
+ * que lee solo las líneas nuevas: los dos tienen que entender lo mismo.
20
+ */
21
+ export declare function parseTranscriptLine(line: string): AgentTurn | "other" | "malformed" | null;
15
22
  /**
16
23
  * Devuelve al repositorio de origen los turnos ocurridos en un scratchpad.
17
24
  *
@@ -30,5 +37,8 @@ export declare function scanClaudeCode(options?: ScanOptions): Promise<ScanResul
30
37
  * es generar ese mismo identificador para cada repositorio conocido y ver cuál
31
38
  * coincide.
32
39
  */
33
- export declare function resolveScratchpads(turns: readonly AgentTurn[]): AgentTurn[];
40
+ export declare function resolveScratchpads(turns: readonly AgentTurn[],
41
+ /** Repositorios ya conocidos, para cuando el lote no trae la ruta real (la status line lee pocas líneas). */
42
+ knownRepos?: readonly string[]): AgentTurn[];
43
+ export declare function isScratchpad(path: string): boolean;
34
44
  //# sourceMappingURL=claude.d.ts.map