estela 0.1.34 → 0.1.36
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/dist/billing/sessionize.d.ts.map +1 -1
- package/dist/billing/sessionize.js +3 -2
- package/dist/billing/sessionize.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +210 -13
- package/dist/cli.js.map +1 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +47 -1
- package/dist/db/schema.js.map +1 -1
- package/dist/db/schema.test.js +102 -0
- package/dist/db/schema.test.js.map +1 -1
- package/dist/db/store.d.ts +12 -1
- package/dist/db/store.d.ts.map +1 -1
- package/dist/db/store.js +43 -8
- package/dist/db/store.js.map +1 -1
- package/dist/export/clockify.d.ts +32 -0
- package/dist/export/clockify.d.ts.map +1 -0
- package/dist/export/clockify.js +57 -0
- package/dist/export/clockify.js.map +1 -0
- package/dist/export/clockify.test.d.ts +2 -0
- package/dist/export/clockify.test.d.ts.map +1 -0
- package/dist/export/clockify.test.js +51 -0
- package/dist/export/clockify.test.js.map +1 -0
- package/dist/export/csv.d.ts.map +1 -1
- package/dist/export/csv.js +6 -2
- package/dist/export/csv.js.map +1 -1
- package/dist/export/idioma.test.js +2 -2
- package/dist/export/idioma.test.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +22 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/paths.d.ts +21 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +52 -0
- package/dist/paths.js.map +1 -0
- package/dist/paths.test.d.ts +2 -0
- package/dist/paths.test.d.ts.map +1 -0
- package/dist/paths.test.js +32 -0
- package/dist/paths.test.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +7 -2
- package/dist/server.js.map +1 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +2 -1
- package/dist/setup.js.map +1 -1
- package/dist/watchers/claude.d.ts.map +1 -1
- package/dist/watchers/claude.js +3 -2
- package/dist/watchers/claude.js.map +1 -1
- package/dist/watchers/codex.d.ts.map +1 -1
- package/dist/watchers/codex.js +3 -2
- package/dist/watchers/codex.js.map +1 -1
- package/dist/watchers/git.d.ts.map +1 -1
- package/dist/watchers/git.js +2 -1
- package/dist/watchers/git.js.map +1 -1
- package/dist/workitems.test.d.ts +2 -0
- package/dist/workitems.test.d.ts.map +1 -0
- package/dist/workitems.test.js +59 -0
- package/dist/workitems.test.js.map +1 -0
- package/node_modules/@estela/shared/dist/index.d.ts +1 -0
- package/node_modules/@estela/shared/dist/index.d.ts.map +1 -1
- package/node_modules/@estela/shared/dist/index.js +1 -0
- package/node_modules/@estela/shared/dist/index.js.map +1 -1
- package/node_modules/@estela/shared/dist/types.d.ts +13 -0
- package/node_modules/@estela/shared/dist/types.d.ts.map +1 -1
- package/node_modules/@estela/shared/dist/types.js.map +1 -1
- package/node_modules/@estela/shared/dist/workitems.d.ts +44 -0
- package/node_modules/@estela/shared/dist/workitems.d.ts.map +1 -0
- package/node_modules/@estela/shared/dist/workitems.js +137 -0
- package/node_modules/@estela/shared/dist/workitems.js.map +1 -0
- package/package.json +1 -1
- package/web/app.css +7 -0
- package/web/app.js +8 -1
- package/web/i18n.js +4 -0
- package/web/index.html +2 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionize.d.ts","sourceRoot":"","sources":["../../src/billing/sessionize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"sessionize.d.ts","sourceRoot":"","sources":["../../src/billing/sessionize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAMtE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IAC1C,gFAAgF;IAChF,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAKD,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,OAAO,GAAE,iBAAsB,GAC9B,SAAS,EAAE,CAkCb;AAqCD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,SAAS,EAAE,EAC5B,MAAM,GAAE,CAAC,KAAK,EAAE,SAAS,KAAK,MAAgC,GAC7D,SAAS,EAAE,CAiEb;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAStD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,SAAS,EAAE,EAC5B,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,YAAY,SAAK,GAChB,SAAS,EAAE,CAcb;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,SAAS,EAAE,CAgDb;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,SAAS,SAAS,EAAE,EAClC,WAAW,EAAE,SAAS,SAAS,EAAE,GAChC,SAAS,EAAE,CAKb"}
|
|
@@ -8,6 +8,7 @@ exports.sessionizeCommits = sessionizeCommits;
|
|
|
8
8
|
exports.withoutOverlap = withoutOverlap;
|
|
9
9
|
const shared_1 = require("@estela/shared");
|
|
10
10
|
const cost_js_1 = require("../pricing/cost.js");
|
|
11
|
+
const paths_js_1 = require("../paths.js");
|
|
11
12
|
const localize_js_1 = require("./localize.js");
|
|
12
13
|
const DEFAULT_GAP_MINUTES = 30;
|
|
13
14
|
const DEFAULT_TAIL_MINUTES = 2;
|
|
@@ -191,8 +192,8 @@ function attachCommits(blocks, commits, graceMinutes = 10) {
|
|
|
191
192
|
const graceMs = graceMinutes * 60_000;
|
|
192
193
|
return blocks.map((block) => {
|
|
193
194
|
const matched = commits.filter((commit) => {
|
|
194
|
-
if (block.repoPath && !commit.repoPath
|
|
195
|
-
!block.repoPath
|
|
195
|
+
if (block.repoPath && !(0, paths_js_1.isSameOrInside)(commit.repoPath, block.repoPath) &&
|
|
196
|
+
!(0, paths_js_1.isSameOrInside)(block.repoPath, commit.repoPath)) {
|
|
196
197
|
return false;
|
|
197
198
|
}
|
|
198
199
|
const t = commit.at.getTime();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionize.js","sourceRoot":"","sources":["../../src/billing/sessionize.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"sessionize.js","sourceRoot":"","sources":["../../src/billing/sessionize.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAyCA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAu2DpD,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -54,6 +54,8 @@ const demo_js_1 = require("./demo.js");
|
|
|
54
54
|
const doctor_js_1 = require("./doctor.js");
|
|
55
55
|
const setup_js_1 = require("./setup.js");
|
|
56
56
|
const csv_js_1 = require("./export/csv.js");
|
|
57
|
+
const paths_js_1 = require("./paths.js");
|
|
58
|
+
const clockify_js_1 = require("./export/clockify.js");
|
|
57
59
|
const invoice_pdf_js_1 = require("./export/invoice-pdf.js");
|
|
58
60
|
const share_js_1 = require("./export/share.js");
|
|
59
61
|
const server_js_1 = require("./server.js");
|
|
@@ -102,6 +104,11 @@ estela — registro de horas para desarrollo asistido por IA
|
|
|
102
104
|
vuelve a haber actividad ahí — "estela doctor" avisa en ese caso, en
|
|
103
105
|
vez de perder el bloque o facturarlo por sorpresa.
|
|
104
106
|
estela project reopen --project <id>
|
|
107
|
+
estela project tracker --project <id> [--system jira|azure|github|gitlab|none]
|
|
108
|
+
[--prefix PROJ,OPS]
|
|
109
|
+
El gestor de tareas del proyecto, para reconocer sus tickets en la
|
|
110
|
+
rama y los commits (feature/1234-login, AB#1234, PROJ-12). Luego
|
|
111
|
+
"estela import" lo aplica a lo ya capturado.
|
|
105
112
|
estela rate set --project <id> --rate <importe> [--from YYYY-MM-DD]
|
|
106
113
|
estela budget --project <id> [--amount <dólares>|none]
|
|
107
114
|
Presupuesto mensual de IA. Sin --amount, consulta el actual. Alimenta
|
|
@@ -128,7 +135,11 @@ estela — registro de horas para desarrollo asistido por IA
|
|
|
128
135
|
estela doctor Revisa los datos y avisa de lo que
|
|
129
136
|
rompería una demo. Úsalo antes de publicar.
|
|
130
137
|
estela status Qué hay capturado y sin imputar.
|
|
131
|
-
estela entries --project <id>
|
|
138
|
+
estela entries --project <id> [--ids]
|
|
139
|
+
Bloques imputados a un proyecto, con sus tickets. --ids enseña el id
|
|
140
|
+
de cada uno, para "estela entry link".
|
|
141
|
+
estela entry link --entry <id> --items PROJ-12[,AB#1234] | --clear
|
|
142
|
+
Pone a mano los tickets de un bloque. El import ya no los cambia.
|
|
132
143
|
estela ai-cost Reparto de tu cuota entre proyectos.
|
|
133
144
|
estela share --project <id> [--from YYYY-MM-DD] [--to YYYY-MM-DD]
|
|
134
145
|
[--author <tu nombre>] [--with-amounts] [--out <fichero.html>]
|
|
@@ -186,7 +197,12 @@ estela — registro de horas para desarrollo asistido por IA
|
|
|
186
197
|
estela account
|
|
187
198
|
Tu correo, tu plan, y desde qué máquinas te has conectado.
|
|
188
199
|
|
|
189
|
-
estela export --project <id> [--out <fichero.csv>]
|
|
200
|
+
estela export --project <id> [--out <fichero.csv>] [--month YYYY-MM]
|
|
201
|
+
[--from YYYY-MM-DD] [--to YYYY-MM-DD] [--format csv|clockify]
|
|
202
|
+
Tus bloques en CSV. --format clockify (Pro) sale listo para importar en
|
|
203
|
+
Clockify; --email es tu correo allí (por defecto el de tu cuenta de
|
|
204
|
+
Estela), y --date-format/--time-format tienen que coincidir con tu
|
|
205
|
+
perfil de Clockify (MM/DD/YYYY y 12h por defecto).
|
|
190
206
|
|
|
191
207
|
estela report --project <id> --cutoff YYYY-MM-DD [--dry-run]
|
|
192
208
|
[--pdf <fichero.pdf>] [--csv <fichero.csv>] [--fx <tipo>]
|
|
@@ -236,6 +252,11 @@ estela — time tracking for AI-assisted development
|
|
|
236
252
|
there's activity there again — "estela doctor" flags that instead of
|
|
237
253
|
silently dropping the block or billing it by surprise.
|
|
238
254
|
estela project reopen --project <id>
|
|
255
|
+
estela project tracker --project <id> [--system jira|azure|github|gitlab|none]
|
|
256
|
+
[--prefix PROJ,OPS]
|
|
257
|
+
The project's issue tracker, to recognise its tickets in the branch
|
|
258
|
+
and commits (feature/1234-login, AB#1234, PROJ-12). Then
|
|
259
|
+
"estela import" applies it to what's already captured.
|
|
239
260
|
estela rate set --project <id> --rate <amount> [--from YYYY-MM-DD]
|
|
240
261
|
estela budget --project <id> [--amount <dollars>|none]
|
|
241
262
|
Monthly AI budget. Without --amount, shows the current one. Feeds the
|
|
@@ -262,7 +283,11 @@ estela — time tracking for AI-assisted development
|
|
|
262
283
|
estela doctor Checks your data and flags anything that
|
|
263
284
|
would ruin a demo. Run it before publishing.
|
|
264
285
|
estela status What's been captured and not yet assigned.
|
|
265
|
-
estela entries --project <id>
|
|
286
|
+
estela entries --project <id> [--ids]
|
|
287
|
+
Blocks assigned to a project, with their tickets. --ids shows each
|
|
288
|
+
one's id, for "estela entry link".
|
|
289
|
+
estela entry link --entry <id> --items PROJ-12[,AB#1234] | --clear
|
|
290
|
+
Sets a block's tickets by hand. Imports won't change them anymore.
|
|
266
291
|
estela ai-cost How your subscription splits across projects.
|
|
267
292
|
estela share --project <id> [--from YYYY-MM-DD] [--to YYYY-MM-DD]
|
|
268
293
|
[--author <your name>] [--with-amounts] [--out <file.html>]
|
|
@@ -320,7 +345,12 @@ estela — time tracking for AI-assisted development
|
|
|
320
345
|
estela account
|
|
321
346
|
Your email, your plan, and which machines you've signed in from.
|
|
322
347
|
|
|
323
|
-
estela export --project <id> [--out <file.csv>]
|
|
348
|
+
estela export --project <id> [--out <file.csv>] [--month YYYY-MM]
|
|
349
|
+
[--from YYYY-MM-DD] [--to YYYY-MM-DD] [--format csv|clockify]
|
|
350
|
+
Your blocks as CSV. --format clockify (Pro) comes out ready to import
|
|
351
|
+
into Clockify; --email is your email there (your Estela account's by
|
|
352
|
+
default), and --date-format/--time-format have to match your Clockify
|
|
353
|
+
profile (MM/DD/YYYY and 12h by default).
|
|
324
354
|
|
|
325
355
|
estela report --project <id> --cutoff YYYY-MM-DD [--dry-run]
|
|
326
356
|
[--pdf <file.pdf>] [--csv <file.csv>] [--fx <rate>]
|
|
@@ -613,7 +643,7 @@ async function cmdImport(args, dbPath) {
|
|
|
613
643
|
if (since && Number.isNaN(since.getTime()))
|
|
614
644
|
throw new UserError((0, index_js_1.tr) `Fecha inválida: ${sinceRaw}`);
|
|
615
645
|
const repoFilter = str(args, "repo");
|
|
616
|
-
const repoPaths = repoFilter ? [(0, node_path_1.resolve)(repoFilter)] : undefined;
|
|
646
|
+
const repoPaths = repoFilter ? [(0, paths_js_1.normalizePath)((0, node_path_1.resolve)(repoFilter))] : undefined;
|
|
617
647
|
console.log((0, index_js_1.tr) `Leyendo transcripts de agentes…`);
|
|
618
648
|
const scans = await (0, agents_js_1.scanAgents)({
|
|
619
649
|
...(since ? { since } : {}),
|
|
@@ -715,6 +745,9 @@ async function cmdImport(args, dbPath) {
|
|
|
715
745
|
source: block.turnCount > 0 ? "agent" : "commit",
|
|
716
746
|
kind: "development",
|
|
717
747
|
branch: block.branch,
|
|
748
|
+
// El ticket se saca aquí y no más tarde: en la base solo quedan los
|
|
749
|
+
// hashes de los commits, y es en sus mensajes donde va el `AB#1234`.
|
|
750
|
+
workItems: (0, shared_1.extractWorkItems)(block.branch, block.commits.map((c) => c.subject), project.tracker),
|
|
718
751
|
};
|
|
719
752
|
// El id es determinista (proyecto + día + rama) para que reimportar
|
|
720
753
|
// actualice la imputación en vez de duplicarla. La fecha tiene que ser la
|
|
@@ -794,7 +827,7 @@ function cmdProjectAdd(args, dbPath) {
|
|
|
794
827
|
id: required(args, "id"),
|
|
795
828
|
clientId,
|
|
796
829
|
name: required(args, "name"),
|
|
797
|
-
repoPaths: repo ? [(0, node_path_1.resolve)(repo)] : [],
|
|
830
|
+
repoPaths: repo ? [(0, paths_js_1.normalizePath)((0, node_path_1.resolve)(repo))] : [],
|
|
798
831
|
billable: str(args, "billable") !== "false",
|
|
799
832
|
roundingMinutes: Number(str(args, "rounding") ?? 0),
|
|
800
833
|
aiCostPolicy: (str(args, "ai-cost") ?? "absorbed"),
|
|
@@ -802,7 +835,7 @@ function cmdProjectAdd(args, dbPath) {
|
|
|
802
835
|
});
|
|
803
836
|
console.log((0, index_js_1.tr) `Proyecto "${required(args, "name")}" guardado.`);
|
|
804
837
|
if (repo)
|
|
805
|
-
console.log((0, index_js_1.tr) ` repositorio: ${(0, node_path_1.resolve)(repo)}`);
|
|
838
|
+
console.log((0, index_js_1.tr) ` repositorio: ${(0, paths_js_1.normalizePath)((0, node_path_1.resolve)(repo))}`);
|
|
806
839
|
}
|
|
807
840
|
finally {
|
|
808
841
|
db.close();
|
|
@@ -869,6 +902,83 @@ function cmdProjectReopen(args, dbPath) {
|
|
|
869
902
|
db.close();
|
|
870
903
|
}
|
|
871
904
|
}
|
|
905
|
+
/**
|
|
906
|
+
* `estela project tracker` — qué gestor de tareas usa un proyecto, para
|
|
907
|
+
* reconocer sus tickets en ramas y commits. Sin --system enseña el actual.
|
|
908
|
+
*
|
|
909
|
+
* No recalcula nada por sí mismo: `estela import` ya rehace todos los bloques
|
|
910
|
+
* no facturados, y así solo hay un camino que decide los tickets.
|
|
911
|
+
*/
|
|
912
|
+
function cmdProjectTracker(args, dbPath) {
|
|
913
|
+
const db = (0, schema_js_1.openDatabase)(dbPath);
|
|
914
|
+
try {
|
|
915
|
+
const projectId = required(args, "project");
|
|
916
|
+
const project = store.getProject(db, projectId);
|
|
917
|
+
if (!project)
|
|
918
|
+
throw new UserError((0, index_js_1.tr) `No existe el proyecto "${projectId}".`);
|
|
919
|
+
const system = str(args, "system");
|
|
920
|
+
if (!system) {
|
|
921
|
+
console.log(project.tracker
|
|
922
|
+
? (0, index_js_1.tr) `"${project.name}" usa ${project.tracker.system}${project.tracker.prefixes.length ? " (" + project.tracker.prefixes.join(", ") + ")" : ""}.`
|
|
923
|
+
: (0, index_js_1.tr) `"${project.name}" no tiene gestor de tareas. Solo se reconocen AB#1234 y claves de Jira en mayúscula en la rama.`);
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
if (system === "none") {
|
|
927
|
+
store.setProjectTracker(db, projectId, null);
|
|
928
|
+
console.log((0, index_js_1.tr) `"${project.name}" ya no tiene gestor de tareas.`);
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
if (!shared_1.TRACKER_SYSTEMS.includes(system)) {
|
|
932
|
+
throw new UserError((0, index_js_1.tr) `Gestor desconocido: ${system}. Usa jira, azure, github, gitlab o none.`);
|
|
933
|
+
}
|
|
934
|
+
const prefixes = (str(args, "prefix") ?? "").split(",").map((p) => p.trim().toUpperCase()).filter(Boolean);
|
|
935
|
+
if (prefixes.some((p) => !/^[A-Z][A-Z0-9]*$/.test(p))) {
|
|
936
|
+
throw new UserError((0, index_js_1.tr) `Prefijo inválido: tienen que ser letras y números, como PROJ u OPS.`);
|
|
937
|
+
}
|
|
938
|
+
store.setProjectTracker(db, projectId, { system: system, prefixes });
|
|
939
|
+
console.log((0, index_js_1.tr) `"${project.name}" usa ${system}${prefixes.length ? " (" + prefixes.join(", ") + ")" : ""}.`);
|
|
940
|
+
}
|
|
941
|
+
console.log((0, index_js_1.tr) `Para aplicarlo a lo ya capturado: estela import`);
|
|
942
|
+
}
|
|
943
|
+
finally {
|
|
944
|
+
db.close();
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* `estela entry link` — pone a mano los tickets de un bloque, cuando la rama
|
|
949
|
+
* no lo decía o lo decía mal. Desde entonces el import no los toca;
|
|
950
|
+
* `--clear` los devuelve a lo que se detecte solo.
|
|
951
|
+
*/
|
|
952
|
+
function cmdEntryLink(args, dbPath) {
|
|
953
|
+
const db = (0, schema_js_1.openDatabase)(dbPath);
|
|
954
|
+
try {
|
|
955
|
+
const entryId = required(args, "entry");
|
|
956
|
+
const row = db.prepare("SELECT project_id FROM time_entries WHERE id = ?").get(entryId);
|
|
957
|
+
if (!row)
|
|
958
|
+
throw new UserError((0, index_js_1.tr) `No existe el bloque "${entryId}". Los ids salen con: estela entries --project <id> --ids`);
|
|
959
|
+
if (args.flags["clear"] === true) {
|
|
960
|
+
store.setEntryWorkItems(db, entryId, null);
|
|
961
|
+
console.log((0, index_js_1.tr) `Tickets de "${entryId}" devueltos a lo que detecte el import.`);
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
const tracker = store.getProject(db, row.project_id)?.tracker ?? null;
|
|
965
|
+
const raw = required(args, "items").split(",").map((t) => t.trim()).filter(Boolean);
|
|
966
|
+
const keys = [];
|
|
967
|
+
for (const text of raw) {
|
|
968
|
+
const key = (0, shared_1.parseWorkItem)(text, tracker);
|
|
969
|
+
if (!key) {
|
|
970
|
+
throw new UserError((0, index_js_1.tr) `No sé de qué gestor es "${text}". Escríbelo como PROJ-12, AB#1234, o configura el del proyecto con: estela project tracker`);
|
|
971
|
+
}
|
|
972
|
+
if (!keys.includes(key))
|
|
973
|
+
keys.push(key);
|
|
974
|
+
}
|
|
975
|
+
store.setEntryWorkItems(db, entryId, keys);
|
|
976
|
+
console.log(`"${entryId}" → ${keys.map(shared_1.formatWorkItem).join(", ")}`);
|
|
977
|
+
}
|
|
978
|
+
finally {
|
|
979
|
+
db.close();
|
|
980
|
+
}
|
|
981
|
+
}
|
|
872
982
|
/**
|
|
873
983
|
* Presupuesto mensual de IA de un proyecto.
|
|
874
984
|
*
|
|
@@ -987,13 +1097,17 @@ function cmdEntries(args, dbPath) {
|
|
|
987
1097
|
console.log((0, index_js_1.tr) `Sin bloques imputados. Ejecuta: estela import`);
|
|
988
1098
|
return;
|
|
989
1099
|
}
|
|
1100
|
+
const ids = args.flags["ids"] === true;
|
|
990
1101
|
console.log(`${project.name}\n`);
|
|
991
1102
|
for (const e of entries) {
|
|
992
1103
|
const flag = e.invoiceId ? (0, index_js_1.tr) `facturado` : e.billable ? (0, index_js_1.tr) `pendiente` : (0, index_js_1.tr) `no facturable`;
|
|
1104
|
+
const tickets = (e.workItems ?? []).map(shared_1.formatWorkItem).join(",");
|
|
993
1105
|
console.log(`${e.startedAt.toISOString().slice(0, 16).replace("T", " ")} ` +
|
|
994
1106
|
`${(0, shared_1.formatDuration)(e.seconds).padStart(8)} ` +
|
|
995
1107
|
`${(0, shared_1.formatAiCost)(e.aiCost).padStart(9)} ` +
|
|
996
|
-
`${flag.padEnd(14)} ${e.description.slice(0, 44)}`);
|
|
1108
|
+
`${flag.padEnd(14)} ${tickets ? tickets.padEnd(10) + " " : ""}${e.description.slice(0, 44)}`);
|
|
1109
|
+
if (ids)
|
|
1110
|
+
console.log(` ${e.id}`);
|
|
997
1111
|
}
|
|
998
1112
|
}
|
|
999
1113
|
finally {
|
|
@@ -1351,7 +1465,7 @@ function cmdTeamRepo(args, dbPath) {
|
|
|
1351
1465
|
if (!store.getProject(db, projectId))
|
|
1352
1466
|
throw new UserError((0, index_js_1.tr) `No existe el proyecto "${projectId}".`);
|
|
1353
1467
|
store.addProjectRepo(db, projectId, (0, node_path_1.resolve)(repo));
|
|
1354
|
-
console.log((0, index_js_1.tr) `Repositorio vinculado a "${projectId}": ${(0, node_path_1.resolve)(repo)}`);
|
|
1468
|
+
console.log((0, index_js_1.tr) `Repositorio vinculado a "${projectId}": ${(0, paths_js_1.normalizePath)((0, node_path_1.resolve)(repo))}`);
|
|
1355
1469
|
}
|
|
1356
1470
|
finally {
|
|
1357
1471
|
db.close();
|
|
@@ -1526,7 +1640,7 @@ function cmdDoctor(dbPath) {
|
|
|
1526
1640
|
db.close();
|
|
1527
1641
|
}
|
|
1528
1642
|
}
|
|
1529
|
-
function cmdExport(args, dbPath) {
|
|
1643
|
+
async function cmdExport(args, dbPath) {
|
|
1530
1644
|
const db = (0, schema_js_1.openDatabase)(dbPath);
|
|
1531
1645
|
try {
|
|
1532
1646
|
const projectId = required(args, "project");
|
|
@@ -1535,15 +1649,44 @@ function cmdExport(args, dbPath) {
|
|
|
1535
1649
|
throw new UserError((0, index_js_1.tr) `No existe el proyecto "${projectId}".`);
|
|
1536
1650
|
const client = store.getClient(db, project.clientId);
|
|
1537
1651
|
const rates = store.getRates(db, projectId);
|
|
1652
|
+
const format = str(args, "format") ?? "csv";
|
|
1653
|
+
if (format !== "csv" && format !== "clockify") {
|
|
1654
|
+
throw new UserError((0, index_js_1.tr) `Formato desconocido: ${format}. Usa csv o clockify.`);
|
|
1655
|
+
}
|
|
1656
|
+
const entries = entriesInRange(store.getTimeEntries(db, projectId), args);
|
|
1538
1657
|
const lang = docLangOf(args, client);
|
|
1539
|
-
|
|
1658
|
+
let csv;
|
|
1659
|
+
if (format === "clockify") {
|
|
1660
|
+
const account = await requirePaidPlan(db, (0, index_js_1.tr) `Exportar a Clockify`);
|
|
1661
|
+
const email = str(args, "email") ?? account?.email;
|
|
1662
|
+
if (!email)
|
|
1663
|
+
throw new UserError((0, index_js_1.tr) `Falta --email: el correo de tu cuenta de Clockify.`);
|
|
1664
|
+
const dateFormat = (str(args, "date-format") ?? "MM/DD/YYYY").toUpperCase();
|
|
1665
|
+
if (!clockify_js_1.CLOCKIFY_DATE_FORMATS.includes(dateFormat)) {
|
|
1666
|
+
throw new UserError((0, index_js_1.tr) `--date-format admite ${clockify_js_1.CLOCKIFY_DATE_FORMATS.join(", ")}.`);
|
|
1667
|
+
}
|
|
1668
|
+
const timeFormat = str(args, "time-format") ?? "12h";
|
|
1669
|
+
if (timeFormat !== "12h" && timeFormat !== "24h")
|
|
1670
|
+
throw new UserError((0, index_js_1.tr) `--time-format admite 12h o 24h.`);
|
|
1671
|
+
csv = (0, index_js_1.withLang)(lang, () => (0, clockify_js_1.timeEntriesToClockifyCsv)(entries, project, client, { email, dateFormat, timeFormat }));
|
|
1672
|
+
}
|
|
1673
|
+
else {
|
|
1674
|
+
csv = (0, index_js_1.withLang)(lang, () => (0, csv_js_1.timeEntriesToCsv)(entries, project, client, (at) => (0, invoice_js_1.rateAt)(rates, projectId, at)));
|
|
1675
|
+
}
|
|
1540
1676
|
const out = str(args, "out");
|
|
1541
1677
|
if (out) {
|
|
1542
1678
|
(0, node_fs_1.writeFileSync)(out, csv, "utf8");
|
|
1543
1679
|
console.log((0, index_js_1.tr) `CSV: ${out}`);
|
|
1544
1680
|
// Solo si va a un fichero: por la salida estándar el aviso se colaría
|
|
1545
1681
|
// dentro del propio CSV.
|
|
1546
|
-
|
|
1682
|
+
if (format === "clockify") {
|
|
1683
|
+
console.log((0, index_js_1.tr) ` ${entries.length} bloques. En Clockify: Settings → Import → Timesheets.`);
|
|
1684
|
+
console.log((0, index_js_1.tr) ` La fecha y la hora tienen que coincidir con el formato de tu perfil de Clockify;`);
|
|
1685
|
+
console.log((0, index_js_1.tr) ` si no, repítelo con --date-format DD/MM/YYYY o --time-format 24h.`);
|
|
1686
|
+
}
|
|
1687
|
+
else {
|
|
1688
|
+
hintDocLang(args, client, lang);
|
|
1689
|
+
}
|
|
1547
1690
|
}
|
|
1548
1691
|
else {
|
|
1549
1692
|
process.stdout.write(csv);
|
|
@@ -1553,6 +1696,54 @@ function cmdExport(args, dbPath) {
|
|
|
1553
1696
|
db.close();
|
|
1554
1697
|
}
|
|
1555
1698
|
}
|
|
1699
|
+
/**
|
|
1700
|
+
* `--month YYYY-MM`, o `--from`/`--to` en fechas locales. Sin ninguno, todo:
|
|
1701
|
+
* es lo que hacía `estela export` antes de tener rango.
|
|
1702
|
+
*/
|
|
1703
|
+
function entriesInRange(entries, args) {
|
|
1704
|
+
const month = str(args, "month");
|
|
1705
|
+
if (month && !/^\d{4}-\d{2}$/.test(month))
|
|
1706
|
+
throw new UserError((0, index_js_1.tr) `--month va como YYYY-MM.`);
|
|
1707
|
+
const from = month ? `${month}-01` : str(args, "from");
|
|
1708
|
+
const to = month ? `${month}-31` : str(args, "to");
|
|
1709
|
+
for (const d of [from, to]) {
|
|
1710
|
+
if (d && !/^\d{4}-\d{2}-\d{2}$/.test(d))
|
|
1711
|
+
throw new UserError((0, index_js_1.tr) `Fecha inválida: ${d}`);
|
|
1712
|
+
}
|
|
1713
|
+
return entries.filter((e) => {
|
|
1714
|
+
const day = (0, shared_1.localDate)(e.startedAt);
|
|
1715
|
+
return (!from || day >= from) && (!to || day <= to);
|
|
1716
|
+
});
|
|
1717
|
+
}
|
|
1718
|
+
/**
|
|
1719
|
+
* Lo de Pro, comprobado contra la cuenta y no contra lo guardado aquí: el plan
|
|
1720
|
+
* local se anota "free" al hacer login y nadie lo actualiza después de pagar.
|
|
1721
|
+
* Sin conexión se deja pasar — mejor regalar un export que bloquear a quien
|
|
1722
|
+
* paga porque está en un avión — y se aprovecha la respuesta para dejar el
|
|
1723
|
+
* plan local al día.
|
|
1724
|
+
*/
|
|
1725
|
+
async function requirePaidPlan(db, what) {
|
|
1726
|
+
const account = store.getCloudAccount(db);
|
|
1727
|
+
if (!account) {
|
|
1728
|
+
throw new UserError((0, index_js_1.tr) `${what} es de Pro. Vincula tu cuenta con: estela login --email tu@correo.com`);
|
|
1729
|
+
}
|
|
1730
|
+
try {
|
|
1731
|
+
const info = await (0, client_js_1.cloudGet)(account.apiBaseUrl, "/account", { deviceToken: account.deviceToken });
|
|
1732
|
+
store.setCloudAccount(db, { ...account, plan: info.plan });
|
|
1733
|
+
if (info.plan === "free") {
|
|
1734
|
+
throw new UserError((0, index_js_1.tr) `${what} es de Pro. Actualiza con: estela upgrade --plan pro`);
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
catch (error) {
|
|
1738
|
+
if (error instanceof client_js_1.CloudError && error.status === 401) {
|
|
1739
|
+
throw new UserError((0, index_js_1.tr) `Tu sesión ya no vale. Vuelve a vincular la máquina:\n\n estela login --email tu@correo.com\n`);
|
|
1740
|
+
}
|
|
1741
|
+
if (!(error instanceof client_js_1.CloudError) || error.status !== undefined)
|
|
1742
|
+
throw error;
|
|
1743
|
+
// Sin conexión: se deja pasar.
|
|
1744
|
+
}
|
|
1745
|
+
return account;
|
|
1746
|
+
}
|
|
1556
1747
|
function cmdSubscriptionAdd(args, dbPath) {
|
|
1557
1748
|
const db = (0, schema_js_1.openDatabase)(dbPath);
|
|
1558
1749
|
try {
|
|
@@ -1754,6 +1945,12 @@ async function main() {
|
|
|
1754
1945
|
case "project reopen":
|
|
1755
1946
|
cmdProjectReopen(args, dbPath);
|
|
1756
1947
|
break;
|
|
1948
|
+
case "project tracker":
|
|
1949
|
+
cmdProjectTracker(args, dbPath);
|
|
1950
|
+
break;
|
|
1951
|
+
case "entry link":
|
|
1952
|
+
cmdEntryLink(args, dbPath);
|
|
1953
|
+
break;
|
|
1757
1954
|
case "rate set":
|
|
1758
1955
|
cmdRateSet(args, dbPath);
|
|
1759
1956
|
break;
|
|
@@ -1788,7 +1985,7 @@ async function main() {
|
|
|
1788
1985
|
await cmdPublish(args, dbPath);
|
|
1789
1986
|
break;
|
|
1790
1987
|
case "export":
|
|
1791
|
-
cmdExport(args, dbPath);
|
|
1988
|
+
await cmdExport(args, dbPath);
|
|
1792
1989
|
break;
|
|
1793
1990
|
case "report":
|
|
1794
1991
|
cmdInvoice(args, dbPath);
|