@wrenautomation/aerie 0.8.1 → 0.8.3
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/bin.js +434 -103
- package/dist/bin.js.map +4 -4
- package/dist/cli.d.ts +2 -4
- package/dist/cli.js +27 -8
- package/dist/cli.js.map +1 -1
- package/dist/mirror.js +13 -3
- package/dist/mirror.js.map +1 -1
- package/dist/peers-coord.js +20 -3
- package/dist/peers-coord.js.map +2 -2
- package/dist/remote.js +1 -0
- package/dist/remote.js.map +1 -1
- package/dist/shape.d.ts +64 -8
- package/dist/shape.js +374 -52
- package/dist/shape.js.map +1 -1
- package/dist/shim.js +1 -21
- package/dist/shim.js.map +2 -2
- package/dist/store.d.ts +10 -0
- package/dist/store.js +18 -4
- package/dist/store.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -2408,9 +2408,9 @@ function formatError2(error62, mapper = (issue2) => issue2.message) {
|
|
|
2408
2408
|
let i = 0;
|
|
2409
2409
|
while (i < fullpath.length) {
|
|
2410
2410
|
const el = fullpath[i];
|
|
2411
|
-
const
|
|
2411
|
+
const terminal2 = i === fullpath.length - 1;
|
|
2412
2412
|
if (el === "_errors") {
|
|
2413
|
-
if (
|
|
2413
|
+
if (terminal2)
|
|
2414
2414
|
curr._errors.push(mapper(issue2));
|
|
2415
2415
|
i++;
|
|
2416
2416
|
continue;
|
|
@@ -2424,7 +2424,7 @@ function formatError2(error62, mapper = (issue2) => issue2.message) {
|
|
|
2424
2424
|
});
|
|
2425
2425
|
}
|
|
2426
2426
|
const node2 = curr[el];
|
|
2427
|
-
if (
|
|
2427
|
+
if (terminal2) {
|
|
2428
2428
|
node2._errors.push(mapper(issue2));
|
|
2429
2429
|
}
|
|
2430
2430
|
curr = node2;
|
|
@@ -2458,7 +2458,7 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
|
2458
2458
|
let i = 0;
|
|
2459
2459
|
while (i < fullpath.length) {
|
|
2460
2460
|
const el = fullpath[i];
|
|
2461
|
-
const
|
|
2461
|
+
const terminal2 = i === fullpath.length - 1;
|
|
2462
2462
|
if (typeof el === "string") {
|
|
2463
2463
|
curr.properties ?? (curr.properties = {});
|
|
2464
2464
|
if (!Object.prototype.hasOwnProperty.call(curr.properties, el)) {
|
|
@@ -2475,7 +2475,7 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
|
2475
2475
|
(_a3 = curr.items)[el] ?? (_a3[el] = { errors: [] });
|
|
2476
2476
|
curr = curr.items[el];
|
|
2477
2477
|
}
|
|
2478
|
-
if (
|
|
2478
|
+
if (terminal2) {
|
|
2479
2479
|
curr.errors.push(mapper(issue2));
|
|
2480
2480
|
}
|
|
2481
2481
|
i++;
|
|
@@ -3606,11 +3606,11 @@ function capSize(inst, size) {
|
|
|
3606
3606
|
const caps = sizeCaps(inst._zod.def.checks);
|
|
3607
3607
|
if (!caps.length)
|
|
3608
3608
|
return;
|
|
3609
|
-
const
|
|
3609
|
+
const cap = Math.min(...caps.map((c) => c[0]));
|
|
3610
3610
|
const parse6 = inst._zod.parse;
|
|
3611
3611
|
inst._zod.parse = (payload, ctx) => {
|
|
3612
3612
|
const n = size(payload.value);
|
|
3613
|
-
if (n >
|
|
3613
|
+
if (n > cap && !ctx?.skipChecks && ctx?.direction !== "backward") {
|
|
3614
3614
|
for (const [max, ch] of sizeCaps(inst._zod.def.checks)) {
|
|
3615
3615
|
if (n > max && ch._zod.def.when(payload)) {
|
|
3616
3616
|
const start = payload.issues.length;
|
|
@@ -22965,7 +22965,7 @@ var init_sql = __esm({
|
|
|
22965
22965
|
return new SQL([new StringChunk(str2)]);
|
|
22966
22966
|
}
|
|
22967
22967
|
sql2.raw = raw;
|
|
22968
|
-
function
|
|
22968
|
+
function join9(chunks, separator) {
|
|
22969
22969
|
const result = [];
|
|
22970
22970
|
for (const [i, chunk] of chunks.entries()) {
|
|
22971
22971
|
if (i > 0 && separator !== void 0) {
|
|
@@ -22975,7 +22975,7 @@ var init_sql = __esm({
|
|
|
22975
22975
|
}
|
|
22976
22976
|
return new SQL(result);
|
|
22977
22977
|
}
|
|
22978
|
-
sql2.join =
|
|
22978
|
+
sql2.join = join9;
|
|
22979
22979
|
function identifier(value) {
|
|
22980
22980
|
return new Name(value);
|
|
22981
22981
|
}
|
|
@@ -27253,7 +27253,7 @@ var init_select2 = __esm({
|
|
|
27253
27253
|
const baseTableName = this.tableName;
|
|
27254
27254
|
const tableName = getTableLikeName(table);
|
|
27255
27255
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
27256
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
27256
|
+
if (typeof tableName === "string" && this.config.joins?.some((join9) => join9.alias === tableName)) {
|
|
27257
27257
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
27258
27258
|
}
|
|
27259
27259
|
if (!this.isPartialSelect) {
|
|
@@ -28780,7 +28780,7 @@ var init_update = __esm({
|
|
|
28780
28780
|
createJoin(joinType) {
|
|
28781
28781
|
return (table, on) => {
|
|
28782
28782
|
const tableName = getTableLikeName(table);
|
|
28783
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
28783
|
+
if (typeof tableName === "string" && this.config.joins.some((join9) => join9.alias === tableName)) {
|
|
28784
28784
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
28785
28785
|
}
|
|
28786
28786
|
if (typeof on === "function") {
|
|
@@ -28876,10 +28876,10 @@ var init_update = __esm({
|
|
|
28876
28876
|
const fromFields = this.getTableLikeFields(this.config.from);
|
|
28877
28877
|
fields[tableName] = fromFields;
|
|
28878
28878
|
}
|
|
28879
|
-
for (const
|
|
28880
|
-
const tableName2 = getTableLikeName(
|
|
28881
|
-
if (typeof tableName2 === "string" && !is(
|
|
28882
|
-
const fromFields = this.getTableLikeFields(
|
|
28879
|
+
for (const join9 of this.config.joins) {
|
|
28880
|
+
const tableName2 = getTableLikeName(join9.table);
|
|
28881
|
+
if (typeof tableName2 === "string" && !is(join9.table, SQL)) {
|
|
28882
|
+
const fromFields = this.getTableLikeFields(join9.table);
|
|
28883
28883
|
fields[tableName2] = fromFields;
|
|
28884
28884
|
}
|
|
28885
28885
|
}
|
|
@@ -30104,7 +30104,7 @@ var init_address = __esm({
|
|
|
30104
30104
|
function checks4(cs, e, what) {
|
|
30105
30105
|
if (!e) return cs;
|
|
30106
30106
|
let out = cs.map((c) => ({ ...c }));
|
|
30107
|
-
const
|
|
30107
|
+
const at4 = (n) => {
|
|
30108
30108
|
const c = out[n - 1];
|
|
30109
30109
|
if (!c) throw new Error(`${what} #${n} does not exist (has ${out.length})`);
|
|
30110
30110
|
return c;
|
|
@@ -30114,10 +30114,10 @@ function checks4(cs, e, what) {
|
|
|
30114
30114
|
const was = new Map(out.map((c) => [c.text.trim(), c.done]));
|
|
30115
30115
|
out = e.replace.map((text3) => ({ text: text3.trim(), done: was.get(text3.trim()) ?? false }));
|
|
30116
30116
|
}
|
|
30117
|
-
for (const n of e.check ?? [])
|
|
30118
|
-
for (const n of e.uncheck ?? [])
|
|
30117
|
+
for (const n of e.check ?? []) at4(n).done = true;
|
|
30118
|
+
for (const n of e.uncheck ?? []) at4(n).done = false;
|
|
30119
30119
|
if (e.remove?.length) {
|
|
30120
|
-
for (const n of e.remove)
|
|
30120
|
+
for (const n of e.remove) at4(n);
|
|
30121
30121
|
const drop = new Set(e.remove);
|
|
30122
30122
|
out = out.filter((_, i) => !drop.has(i + 1));
|
|
30123
30123
|
}
|
|
@@ -31151,13 +31151,13 @@ function aerieStore(o) {
|
|
|
31151
31151
|
if (input2.milestone)
|
|
31152
31152
|
input2 = { ...input2, milestone: await milestoneOf(tx, input2.milestone) };
|
|
31153
31153
|
const id2 = await nextId(tx, parent?.id);
|
|
31154
|
-
const
|
|
31154
|
+
const at4 = now();
|
|
31155
31155
|
const blank = {
|
|
31156
31156
|
id: id2,
|
|
31157
31157
|
title: input2.title,
|
|
31158
31158
|
status: input2.status ?? "To Do",
|
|
31159
31159
|
assignees: [],
|
|
31160
|
-
createdAt:
|
|
31160
|
+
createdAt: at4,
|
|
31161
31161
|
labels: [],
|
|
31162
31162
|
dependencies: [],
|
|
31163
31163
|
references: [],
|
|
@@ -31166,7 +31166,7 @@ function aerieStore(o) {
|
|
|
31166
31166
|
comments: [],
|
|
31167
31167
|
extra: {}
|
|
31168
31168
|
};
|
|
31169
|
-
const t = applyEdit(blank, { ...input2, ...parent ? { parentId: parent.id } : {} },
|
|
31169
|
+
const t = applyEdit(blank, { ...input2, ...parent ? { parentId: parent.id } : {} }, at4);
|
|
31170
31170
|
delete t.updatedAt;
|
|
31171
31171
|
const area2 = input2.area ?? parent?.area ?? areaFor(t, rules);
|
|
31172
31172
|
await put(tx, t, await ensureArea(tx, area2), input2.place ?? "tasks");
|
|
@@ -31299,8 +31299,18 @@ function aerieStore(o) {
|
|
|
31299
31299
|
}
|
|
31300
31300
|
async function statusOf2(ids) {
|
|
31301
31301
|
if (!ids.length) return /* @__PURE__ */ new Map();
|
|
31302
|
-
const rows3 = await db.select({ id: task.id, status: task.status }).from(task).where(inArray(task.id
|
|
31303
|
-
return new Map(rows3.map((r) => [r.id, r.status]));
|
|
31302
|
+
const rows3 = await db.select({ id: task.id, status: task.status }).from(task).where(inArray(sql`upper(${task.id})`, [...new Set(ids.map((x) => x.toUpperCase()))]));
|
|
31303
|
+
return new Map(rows3.map((r) => [r.id.toUpperCase(), r.status]));
|
|
31304
|
+
}
|
|
31305
|
+
async function dependencyRows() {
|
|
31306
|
+
return db.select({
|
|
31307
|
+
id: task.id,
|
|
31308
|
+
title: task.title,
|
|
31309
|
+
status: task.status,
|
|
31310
|
+
place: task.place,
|
|
31311
|
+
parentId: task.parentId,
|
|
31312
|
+
dependencies: task.dependencies
|
|
31313
|
+
}).from(task);
|
|
31304
31314
|
}
|
|
31305
31315
|
async function getSetting(key) {
|
|
31306
31316
|
const r = await db.select({ v: setting.value }).from(setting).where(eq(setting.key, key));
|
|
@@ -31400,7 +31410,12 @@ function aerieStore(o) {
|
|
|
31400
31410
|
});
|
|
31401
31411
|
}
|
|
31402
31412
|
async function lastEvent(taskId, kind) {
|
|
31403
|
-
const [r] = await db.select().from(taskEvent).where(
|
|
31413
|
+
const [r] = await db.select().from(taskEvent).where(
|
|
31414
|
+
and(
|
|
31415
|
+
sql`upper(${taskEvent.taskId}) = ${taskId.toUpperCase()}`,
|
|
31416
|
+
eq(taskEvent.kind, kind)
|
|
31417
|
+
)
|
|
31418
|
+
).orderBy(sql`${taskEvent.seq} desc`).limit(1);
|
|
31404
31419
|
return r ?? null;
|
|
31405
31420
|
}
|
|
31406
31421
|
async function countEvents(taskId, kind, body, after = 0) {
|
|
@@ -31455,6 +31470,7 @@ function aerieStore(o) {
|
|
|
31455
31470
|
milestones,
|
|
31456
31471
|
putMilestones,
|
|
31457
31472
|
statusOf: statusOf2,
|
|
31473
|
+
dependencyRows,
|
|
31458
31474
|
mirrorFiles,
|
|
31459
31475
|
setMirrorFile,
|
|
31460
31476
|
setMirrorFiles,
|
|
@@ -31517,10 +31533,10 @@ function rank(ts, query) {
|
|
|
31517
31533
|
});
|
|
31518
31534
|
const q = query.trim().toLowerCase();
|
|
31519
31535
|
const inTitle = (t) => t.title.toLowerCase().includes(q) ? 1 : 0;
|
|
31520
|
-
const
|
|
31536
|
+
const at4 = (t) => t.updatedAt ?? t.createdAt;
|
|
31521
31537
|
return fuse.search(query).map((r) => ({ task: r.item, score: 1 - (r.score ?? 0) })).sort(
|
|
31522
31538
|
// ties (exact substrings all score 1): a title hit, then the newest
|
|
31523
|
-
(x, y) => y.score - x.score || inTitle(y.task) - inTitle(x.task) ||
|
|
31539
|
+
(x, y) => y.score - x.score || inTitle(y.task) - inTitle(x.task) || at4(y.task).localeCompare(at4(x.task))
|
|
31524
31540
|
);
|
|
31525
31541
|
}
|
|
31526
31542
|
function searchPlain(hits) {
|
|
@@ -32979,7 +32995,7 @@ async function rows2(q, query) {
|
|
|
32979
32995
|
function pgCoord(o) {
|
|
32980
32996
|
const db = o.db;
|
|
32981
32997
|
const ns = o.ns ?? "main";
|
|
32982
|
-
const clock = () => o.now ?
|
|
32998
|
+
const clock = () => o.now ? at3(o.now()) : sql`now()`;
|
|
32983
32999
|
const plus = (t, ms2) => sql`(${t} + ${ms2}::float8 * interval '1 millisecond')`;
|
|
32984
33000
|
const L = coordLease;
|
|
32985
33001
|
const C = coordClosing;
|
|
@@ -33299,7 +33315,7 @@ function pgCoord(o) {
|
|
|
33299
33315
|
};
|
|
33300
33316
|
return store;
|
|
33301
33317
|
}
|
|
33302
|
-
var COORD_CHANNEL, ms,
|
|
33318
|
+
var COORD_CHANNEL, ms, at3, num, textArr;
|
|
33303
33319
|
var init_postgres = __esm({
|
|
33304
33320
|
"src/coord/postgres.ts"() {
|
|
33305
33321
|
"use strict";
|
|
@@ -33309,7 +33325,7 @@ var init_postgres = __esm({
|
|
|
33309
33325
|
init_store();
|
|
33310
33326
|
COORD_CHANNEL = "aerie_coord";
|
|
33311
33327
|
ms = (v) => sql`(extract(epoch from ${v}) * 1000)::float8`;
|
|
33312
|
-
|
|
33328
|
+
at3 = (v) => sql`to_timestamp(${v}::float8 / 1000)`;
|
|
33313
33329
|
num = (v) => Math.round(Number(v));
|
|
33314
33330
|
textArr = (v) => sql`${`{${v.map((x) => JSON.stringify(x)).join(",")}}`}::text[]`;
|
|
33315
33331
|
}
|
|
@@ -33676,6 +33692,7 @@ var init_remote = __esm({
|
|
|
33676
33692
|
actors: read(),
|
|
33677
33693
|
milestones: read(),
|
|
33678
33694
|
statusOf: read([IDS]),
|
|
33695
|
+
dependencyRows: read(),
|
|
33679
33696
|
routeRules: read(),
|
|
33680
33697
|
lastEvent: read([ID2, KIND]),
|
|
33681
33698
|
countEvents: read([
|
|
@@ -33892,7 +33909,7 @@ import { spawnSync as spawnSync2 } from "node:child_process";
|
|
|
33892
33909
|
import { createHash as createHash2, createHmac, pbkdf2Sync, randomBytes } from "node:crypto";
|
|
33893
33910
|
import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
|
|
33894
33911
|
import { homedir as homedir3 } from "node:os";
|
|
33895
|
-
import { dirname as
|
|
33912
|
+
import { dirname as dirname4, join as join7 } from "node:path";
|
|
33896
33913
|
function aerieUrl(adminUrl, role = ROLE) {
|
|
33897
33914
|
const url2 = new URL(adminUrl);
|
|
33898
33915
|
if (!url2.password) throw new Error("admin URL has no password; aerie derives its own from it");
|
|
@@ -33950,7 +33967,7 @@ function writeSettings(set3, file2 = settingsFile(), drop = []) {
|
|
|
33950
33967
|
const lines = existsSync5(file2) ? readFileSync5(file2, "utf8").split("\n").filter(Boolean) : [];
|
|
33951
33968
|
const gone = [...Object.keys(set3), ...drop];
|
|
33952
33969
|
const kept = lines.filter((l) => !gone.some((k) => l.startsWith(`${k}=`)));
|
|
33953
|
-
mkdirSync3(
|
|
33970
|
+
mkdirSync3(dirname4(file2), { recursive: true, mode: 448 });
|
|
33954
33971
|
writeFileSync3(
|
|
33955
33972
|
file2,
|
|
33956
33973
|
`${[...kept, ...Object.entries(set3).map(([k, v]) => `${k}=${v}`)].join("\n")}
|
|
@@ -33989,14 +34006,14 @@ var init_setup = __esm({
|
|
|
33989
34006
|
ROLE = "aerie";
|
|
33990
34007
|
SCHEMA = "aerie";
|
|
33991
34008
|
ATTRS = "LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOREPLICATION NOBYPASSRLS";
|
|
33992
|
-
settingsFile = () =>
|
|
34009
|
+
settingsFile = () => join7(homedir3(), ".config", "aerie", "env");
|
|
33993
34010
|
}
|
|
33994
34011
|
});
|
|
33995
34012
|
|
|
33996
34013
|
// src/bin.ts
|
|
33997
34014
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
33998
34015
|
import { homedir as homedir4, userInfo } from "node:os";
|
|
33999
|
-
import { join as
|
|
34016
|
+
import { join as join8 } from "node:path";
|
|
34000
34017
|
|
|
34001
34018
|
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js
|
|
34002
34019
|
var CommanderError = class extends Error {
|
|
@@ -37366,6 +37383,9 @@ function useColor() {
|
|
|
37366
37383
|
// node_modules/.pnpm/commander@15.0.0/node_modules/commander/index.js
|
|
37367
37384
|
var program = new Command();
|
|
37368
37385
|
|
|
37386
|
+
// src/cli.ts
|
|
37387
|
+
import { dirname as dirname3, join as join6, relative } from "node:path";
|
|
37388
|
+
|
|
37369
37389
|
// src/backlog/files.ts
|
|
37370
37390
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
37371
37391
|
import { join } from "node:path";
|
|
@@ -40340,11 +40360,11 @@ function check3(words, split, o) {
|
|
|
40340
40360
|
const out = { ok: [], failedSpans: [], missed: [] };
|
|
40341
40361
|
const areas = new Set(o.areas);
|
|
40342
40362
|
const fuse = new Fuse(o.open, { keys: ["title"], includeScore: true, threshold: 0.3 });
|
|
40343
|
-
split.tasks.forEach((task2,
|
|
40363
|
+
split.tasks.forEach((task2, at4) => {
|
|
40344
40364
|
const span = normal(task2.span);
|
|
40345
40365
|
const i = span ? src.indexOf(span) : -1;
|
|
40346
40366
|
if (i < 0) {
|
|
40347
|
-
out.failedSpans.push({ at:
|
|
40367
|
+
out.failedSpans.push({ at: at4, title: task2.title, span: task2.span });
|
|
40348
40368
|
return;
|
|
40349
40369
|
}
|
|
40350
40370
|
covered.fill(1, i, i + span.length);
|
|
@@ -40352,7 +40372,7 @@ function check3(words, split, o) {
|
|
|
40352
40372
|
const best = fuse.search(task2.title, { limit: 1 })[0];
|
|
40353
40373
|
out.ok.push({
|
|
40354
40374
|
task: task2,
|
|
40355
|
-
at:
|
|
40375
|
+
at: at4,
|
|
40356
40376
|
area: area2,
|
|
40357
40377
|
dup: best && (best.score ?? 1) <= 0.25 ? { id: best.item.id, title: best.item.title, score: best.score ?? 0 } : void 0
|
|
40358
40378
|
});
|
|
@@ -40403,12 +40423,12 @@ async function hear(file2, o = {}) {
|
|
|
40403
40423
|
const { hearSpeech, speechHere } = await import("@wrenautomation/read/video");
|
|
40404
40424
|
const { mkdtemp: mkdtemp2, rm } = await import("node:fs/promises");
|
|
40405
40425
|
const { tmpdir: tmpdir2 } = await import("node:os");
|
|
40406
|
-
const { join:
|
|
40426
|
+
const { join: join9 } = await import("node:path");
|
|
40407
40427
|
const cohere = (process.env.COHERE_API_KEY ?? "").split(",").filter(Boolean);
|
|
40408
40428
|
const ear = speechHere(cohere);
|
|
40409
40429
|
if (!ear)
|
|
40410
40430
|
throw new AerieError("no ear: install whisper.cpp and its model, or set COHERE_API_KEY");
|
|
40411
|
-
const dir = await mkdtemp2(
|
|
40431
|
+
const dir = await mkdtemp2(join9(tmpdir2(), "aerie-hear-"));
|
|
40412
40432
|
const t0 = performance.now();
|
|
40413
40433
|
try {
|
|
40414
40434
|
const text3 = await hearSpeech(file2, dir, o.ffmpeg ?? "ffmpeg", ear, {
|
|
@@ -41566,10 +41586,10 @@ function registerRunCommands(program3, ctx) {
|
|
|
41566
41586
|
const runner = headlessRunners(aerieEnv()).get(name);
|
|
41567
41587
|
if (!runner) throw new Error(`${name} runs in a live session, not a worker`);
|
|
41568
41588
|
const caps = parseLanes(await a.getSetting("run_cap") ?? "", "run_cap");
|
|
41569
|
-
const
|
|
41570
|
-
if (
|
|
41589
|
+
const cap = o.cap === void 0 ? caps[name] : Number(o.cap);
|
|
41590
|
+
if (cap !== void 0 && !(Number.isInteger(cap) && cap > 0))
|
|
41571
41591
|
throw new Error(
|
|
41572
|
-
`${o.cap === void 0 ? `run_cap ${name}` : "--cap"}: ${
|
|
41592
|
+
`${o.cap === void 0 ? `run_cap ${name}` : "--cap"}: ${cap} is not a whole number above 0`
|
|
41573
41593
|
);
|
|
41574
41594
|
const stop = new AbortController();
|
|
41575
41595
|
const quit = () => stop.abort();
|
|
@@ -41585,7 +41605,7 @@ function registerRunCommands(program3, ctx) {
|
|
|
41585
41605
|
idleMs: Number(o.idle),
|
|
41586
41606
|
once: !!o.once,
|
|
41587
41607
|
signal: stop.signal,
|
|
41588
|
-
...
|
|
41608
|
+
...cap === void 0 ? {} : { cap },
|
|
41589
41609
|
onOutcome: (w) => print2(
|
|
41590
41610
|
o.json ? `${JSON.stringify(w)}
|
|
41591
41611
|
` : `${w.id} ${w.outcome}${"summary" in w ? `: ${w.summary.split("\n")[0]}` : ""}
|
|
@@ -41796,8 +41816,20 @@ async function mirror(a, root, o = {}) {
|
|
|
41796
41816
|
} else r.wrote.push(target);
|
|
41797
41817
|
touched.push(target);
|
|
41798
41818
|
}
|
|
41819
|
+
const ids = new Set(tasks.map((t) => t.id));
|
|
41820
|
+
const fresh = [...disk.values()].filter((f) => !ids.has(f.task.id) && !state.has(f.task.id));
|
|
41821
|
+
if (fresh.length && !o.dryRun) {
|
|
41822
|
+
await a.importTasks(
|
|
41823
|
+
fresh.map((f) => ({ task: f.task, place: f.where })),
|
|
41824
|
+
o.by ?? "@backlog"
|
|
41825
|
+
);
|
|
41826
|
+
for (const f of fresh) {
|
|
41827
|
+
const now = await a.get(f.task.id);
|
|
41828
|
+
if (now) await a.setMirrorFile(now.id, f.path, sha(f.text), now.version);
|
|
41829
|
+
}
|
|
41830
|
+
}
|
|
41831
|
+
r.imported.push(...fresh.map((f) => f.path));
|
|
41799
41832
|
if (!o.only) {
|
|
41800
|
-
const ids = new Set(tasks.map((t) => t.id));
|
|
41801
41833
|
for (const [id, m] of state) if (!ids.has(id)) r.left.push(m.path);
|
|
41802
41834
|
}
|
|
41803
41835
|
if (o.commit && touched.length && !o.dryRun) r.committed = commit(root, touched, o.commit);
|
|
@@ -41842,24 +41874,251 @@ init_schema2();
|
|
|
41842
41874
|
init_search();
|
|
41843
41875
|
|
|
41844
41876
|
// src/shape.ts
|
|
41845
|
-
var
|
|
41846
|
-
|
|
41847
|
-
|
|
41848
|
-
|
|
41877
|
+
var ARCHIVE = /* @__PURE__ */ new Set(["archive/tasks", "archive/drafts"]);
|
|
41878
|
+
var shown = (id, place) => ARCHIVE.has(place) ? id : id.toUpperCase();
|
|
41879
|
+
var terminal = (statuses) => (statuses.at(-1) ?? "Done").trim().toLowerCase();
|
|
41880
|
+
var finished = (status, statuses) => (status ?? "").trim().toLowerCase() === terminal(statuses);
|
|
41881
|
+
function parseTaskId(id) {
|
|
41882
|
+
const body = id.replace(/^[a-zA-Z]+-/i, "");
|
|
41883
|
+
const parts = body.split(".").map((p) => {
|
|
41884
|
+
const n = Number.parseInt(p, 10);
|
|
41885
|
+
return Number.isNaN(n) ? null : n;
|
|
41886
|
+
});
|
|
41887
|
+
if (parts.every((n) => n !== null)) return parts;
|
|
41888
|
+
const tail2 = body.match(/(\d+)$/);
|
|
41889
|
+
return [tail2 ? Number.parseInt(tail2[1] ?? "0", 10) : 0];
|
|
41890
|
+
}
|
|
41891
|
+
function compareTaskIds(a, b) {
|
|
41892
|
+
const x = parseTaskId(a);
|
|
41893
|
+
const y = parseTaskId(b);
|
|
41894
|
+
for (let i = 0; i < Math.max(x.length, y.length); i++) {
|
|
41895
|
+
const d = (x[i] ?? 0) - (y[i] ?? 0);
|
|
41896
|
+
if (d) return d;
|
|
41897
|
+
}
|
|
41898
|
+
return a.localeCompare(b, void 0, { sensitivity: "base", numeric: true });
|
|
41899
|
+
}
|
|
41900
|
+
var RANK = { high: 3, medium: 2, low: 1 };
|
|
41901
|
+
var rank2 = (p) => RANK[(p ?? "").trim().toLowerCase()] ?? 0;
|
|
41902
|
+
function backlogOrder(ts) {
|
|
41903
|
+
return [...ts].sort((a, b) => {
|
|
41904
|
+
if (a.ordinal !== void 0 && b.ordinal === void 0) return -1;
|
|
41905
|
+
if (a.ordinal === void 0 && b.ordinal !== void 0) return 1;
|
|
41906
|
+
if (a.ordinal !== void 0 && b.ordinal !== void 0 && a.ordinal !== b.ordinal)
|
|
41907
|
+
return a.ordinal - b.ordinal;
|
|
41908
|
+
return rank2(b.priority) - rank2(a.priority) || compareTaskIds(a.id, b.id);
|
|
41909
|
+
});
|
|
41910
|
+
}
|
|
41911
|
+
function readiness(t, resolve, statuses) {
|
|
41912
|
+
if (ARCHIVE.has(t.place) || finished(t.status, statuses))
|
|
41913
|
+
return { isReady: false, isBlocked: false, blockingDependencies: [], missingDependencies: [] };
|
|
41914
|
+
const blocking = [];
|
|
41915
|
+
const missing = [];
|
|
41916
|
+
for (const d of t.dependencies) {
|
|
41917
|
+
const r = resolve(d);
|
|
41918
|
+
if (!r) missing.push(d);
|
|
41919
|
+
else if (!finished(r.status, statuses)) blocking.push(r.id);
|
|
41920
|
+
}
|
|
41849
41921
|
const isBlocked = blocking.length > 0 || missing.length > 0;
|
|
41850
41922
|
return {
|
|
41851
|
-
isReady:
|
|
41923
|
+
isReady: !isBlocked,
|
|
41852
41924
|
isBlocked,
|
|
41853
41925
|
blockingDependencies: blocking,
|
|
41854
41926
|
missingDependencies: missing
|
|
41855
41927
|
};
|
|
41856
41928
|
}
|
|
41857
|
-
function
|
|
41929
|
+
function boardIndex(rows3) {
|
|
41930
|
+
const index2 = /* @__PURE__ */ new Map();
|
|
41931
|
+
for (const r of [
|
|
41932
|
+
...rows3.filter((x) => x.place === "tasks"),
|
|
41933
|
+
...rows3.filter((x) => x.place === "archive/tasks")
|
|
41934
|
+
]) {
|
|
41935
|
+
const k = canonicalId(r.id);
|
|
41936
|
+
index2.set(k, index2.has(k) ? "ambiguous" : r);
|
|
41937
|
+
}
|
|
41938
|
+
return index2;
|
|
41939
|
+
}
|
|
41940
|
+
var depthIn = (n, d) => d === "dependencies" ? n.dependencyDepth : n.dependentDepth;
|
|
41941
|
+
function canonicalId(id) {
|
|
41942
|
+
const t = id.trim();
|
|
41943
|
+
const m = /^([a-z]+)-([0-9]+(?:\.[0-9]+)*)$/i.exec(t);
|
|
41944
|
+
if (!m) return t.toUpperCase();
|
|
41945
|
+
const body = m[2].split(".").map((s) => s.replace(/^0+/, "") || "0").join(".");
|
|
41946
|
+
return `${m[1].toUpperCase()}-${body}`;
|
|
41947
|
+
}
|
|
41948
|
+
function dependencyGraph(root, rows3, statuses) {
|
|
41949
|
+
const index2 = boardIndex(rows3);
|
|
41950
|
+
const records = rows3.filter((x) => x.place === "tasks" || x.place === "archive/tasks");
|
|
41951
|
+
const rootKey = canonicalId(root.id);
|
|
41952
|
+
const entries = /* @__PURE__ */ new Map();
|
|
41953
|
+
const edges = /* @__PURE__ */ new Map();
|
|
41954
|
+
const rootRow = index2.get(rootKey);
|
|
41955
|
+
entries.set(rootKey, {
|
|
41956
|
+
id: shown(root.id, root.place),
|
|
41957
|
+
title: root.title,
|
|
41958
|
+
status: root.status,
|
|
41959
|
+
state: "resolved",
|
|
41960
|
+
completed: finished(
|
|
41961
|
+
rootRow && rootRow !== "ambiguous" ? rootRow.status : root.status,
|
|
41962
|
+
statuses
|
|
41963
|
+
),
|
|
41964
|
+
dependencyDepth: 0,
|
|
41965
|
+
dependentDepth: 0
|
|
41966
|
+
});
|
|
41967
|
+
const ensure = (key, ref) => {
|
|
41968
|
+
const have = entries.get(key);
|
|
41969
|
+
if (have) return have;
|
|
41970
|
+
const r = index2.get(key);
|
|
41971
|
+
const base = { completed: false, dependencyDepth: null, dependentDepth: null };
|
|
41972
|
+
const node2 = r === void 0 ? { id: ref.trim() || key, title: null, status: null, state: "missing", ...base } : r === "ambiguous" ? { id: key, title: null, status: null, state: "ambiguous", ...base } : {
|
|
41973
|
+
id: shown(r.id, r.place),
|
|
41974
|
+
title: r.title,
|
|
41975
|
+
status: r.status,
|
|
41976
|
+
state: "resolved",
|
|
41977
|
+
...base,
|
|
41978
|
+
completed: finished(r.status, statuses)
|
|
41979
|
+
};
|
|
41980
|
+
entries.set(key, node2);
|
|
41981
|
+
return node2;
|
|
41982
|
+
};
|
|
41983
|
+
const depsOf = (key) => {
|
|
41984
|
+
if (key === rootKey) return root.dependencies;
|
|
41985
|
+
const r = index2.get(key);
|
|
41986
|
+
return r && r !== "ambiguous" ? r.dependencies : [];
|
|
41987
|
+
};
|
|
41988
|
+
const declarers = /* @__PURE__ */ new Map();
|
|
41989
|
+
for (const r of records) {
|
|
41990
|
+
const from = canonicalId(r.id);
|
|
41991
|
+
for (const d of r.dependencies) {
|
|
41992
|
+
const to = canonicalId(d);
|
|
41993
|
+
declarers.set(to, (declarers.get(to) ?? /* @__PURE__ */ new Set()).add(from));
|
|
41994
|
+
}
|
|
41995
|
+
}
|
|
41996
|
+
const traverse2 = (dir, next) => {
|
|
41997
|
+
const queue = [{ key: rootKey, depth: 0 }];
|
|
41998
|
+
for (let i = 0; i < queue.length; i++) {
|
|
41999
|
+
const cur = queue[i];
|
|
42000
|
+
if (entries.get(cur.key)?.state !== "resolved") continue;
|
|
42001
|
+
for (const n of next(cur.key)) {
|
|
42002
|
+
const node2 = ensure(n.key, n.ref);
|
|
42003
|
+
const e = dir === "dependencies" ? { fromKey: cur.key, toKey: n.key } : { fromKey: n.key, toKey: cur.key };
|
|
42004
|
+
edges.set(`${e.fromKey} -> ${e.toKey}`, e);
|
|
42005
|
+
if (depthIn(node2, dir) !== null) continue;
|
|
42006
|
+
if (dir === "dependencies") node2.dependencyDepth = cur.depth + 1;
|
|
42007
|
+
else node2.dependentDepth = cur.depth + 1;
|
|
42008
|
+
queue.push({ key: n.key, depth: cur.depth + 1 });
|
|
42009
|
+
}
|
|
42010
|
+
}
|
|
42011
|
+
};
|
|
42012
|
+
traverse2("dependencies", (k) => depsOf(k).map((ref) => ({ key: canonicalId(ref), ref })));
|
|
42013
|
+
traverse2(
|
|
42014
|
+
"dependents",
|
|
42015
|
+
(k) => [...declarers.get(k) ?? []].sort(compareTaskIds).map((d) => ({ key: d, ref: d }))
|
|
42016
|
+
);
|
|
42017
|
+
const rootNode = entries.get(rootKey);
|
|
42018
|
+
const rest = [...entries.entries()].filter(([k]) => k !== rootKey).sort((a, b) => compareTaskIds(a[1].id, b[1].id));
|
|
42019
|
+
const ordered = [[rootKey, rootNode], ...rest];
|
|
42020
|
+
const idOf = new Map(ordered.map(([k, n]) => [k, n.id]));
|
|
41858
42021
|
return {
|
|
41859
|
-
|
|
42022
|
+
rootId: shown(root.id, root.place),
|
|
42023
|
+
nodes: ordered.map(([, n]) => n),
|
|
42024
|
+
edges: [...edges.values()].map((e) => ({ from: idOf.get(e.fromKey) ?? e.fromKey, to: idOf.get(e.toKey) ?? e.toKey })).sort((a, b) => compareTaskIds(a.from, b.from) || compareTaskIds(a.to, b.to))
|
|
42025
|
+
};
|
|
42026
|
+
}
|
|
42027
|
+
function dependencyTree(g, dir) {
|
|
42028
|
+
const byId = new Map(g.nodes.map((n) => [n.id, n]));
|
|
42029
|
+
const kids = /* @__PURE__ */ new Map();
|
|
42030
|
+
for (const e of g.edges) {
|
|
42031
|
+
const [p, c] = dir === "dependencies" ? [e.from, e.to] : [e.to, e.from];
|
|
42032
|
+
kids.set(p, [...kids.get(p) ?? [], c]);
|
|
42033
|
+
}
|
|
42034
|
+
for (const l of kids.values()) l.sort(compareTaskIds);
|
|
42035
|
+
const expanded = /* @__PURE__ */ new Set([g.rootId]);
|
|
42036
|
+
const branch = /* @__PURE__ */ new Set([g.rootId]);
|
|
42037
|
+
const roots = [];
|
|
42038
|
+
const stack = [{ id: g.rootId, ids: kids.get(g.rootId) ?? [], pos: 0, into: roots }];
|
|
42039
|
+
while (stack.length) {
|
|
42040
|
+
const f = stack[stack.length - 1];
|
|
42041
|
+
const id = f.ids[f.pos];
|
|
42042
|
+
if (id === void 0) {
|
|
42043
|
+
stack.pop();
|
|
42044
|
+
branch.delete(f.id);
|
|
42045
|
+
continue;
|
|
42046
|
+
}
|
|
42047
|
+
f.pos += 1;
|
|
42048
|
+
const node2 = byId.get(id);
|
|
42049
|
+
if (!node2) continue;
|
|
42050
|
+
if (branch.has(id)) {
|
|
42051
|
+
f.into.push({ node: node2, children: [], repeat: "cycle" });
|
|
42052
|
+
continue;
|
|
42053
|
+
}
|
|
42054
|
+
if (expanded.has(id)) {
|
|
42055
|
+
f.into.push({ node: node2, children: [], repeat: "repeat" });
|
|
42056
|
+
continue;
|
|
42057
|
+
}
|
|
42058
|
+
expanded.add(id);
|
|
42059
|
+
if (node2.state !== "resolved") {
|
|
42060
|
+
f.into.push({ node: node2, children: [], repeat: null });
|
|
42061
|
+
continue;
|
|
42062
|
+
}
|
|
42063
|
+
branch.add(id);
|
|
42064
|
+
const t = { node: node2, children: [], repeat: null };
|
|
42065
|
+
f.into.push(t);
|
|
42066
|
+
stack.push({ id, ids: kids.get(id) ?? [], pos: 0, into: t.children });
|
|
42067
|
+
}
|
|
42068
|
+
return roots;
|
|
42069
|
+
}
|
|
42070
|
+
function nodeLabel(n) {
|
|
42071
|
+
if (n.state !== "resolved")
|
|
42072
|
+
return `${n.id} - ${n.state === "missing" ? "unknown task ID" : "ambiguous task ID"}`;
|
|
42073
|
+
const state = n.completed ? "completed" : n.status;
|
|
42074
|
+
const suffix = state ? ` [${state}]` : "";
|
|
42075
|
+
const title = n.title?.trim();
|
|
42076
|
+
return title ? `${n.id} - ${title}${suffix}` : `${n.id}${suffix}`;
|
|
42077
|
+
}
|
|
42078
|
+
function graphSection(g, dir) {
|
|
42079
|
+
const reached = g.nodes.filter((n) => (depthIn(n, dir) ?? 0) > 0);
|
|
42080
|
+
if (!reached.length) return [];
|
|
42081
|
+
const direct2 = reached.filter((n) => depthIn(n, dir) === 1).length;
|
|
42082
|
+
const out = [
|
|
42083
|
+
`${dir === "dependencies" ? "Depends on" : "Dependents"} (${direct2} direct, ${reached.length} total):`
|
|
42084
|
+
];
|
|
42085
|
+
const stack = [{ kids: dependencyTree(g, dir), pos: 0, prefix: "" }];
|
|
42086
|
+
while (stack.length) {
|
|
42087
|
+
const f = stack[stack.length - 1];
|
|
42088
|
+
const c = f.kids[f.pos];
|
|
42089
|
+
if (!c) {
|
|
42090
|
+
stack.pop();
|
|
42091
|
+
continue;
|
|
42092
|
+
}
|
|
42093
|
+
f.pos += 1;
|
|
42094
|
+
const last = f.pos === f.kids.length;
|
|
42095
|
+
const rep = c.repeat === "cycle" ? " (cycle)" : c.repeat === "repeat" ? " (shown above)" : "";
|
|
42096
|
+
out.push(`${f.prefix}${last ? "\u2514\u2500 " : "\u251C\u2500 "}${nodeLabel(c.node)}${rep}`);
|
|
42097
|
+
if (c.children.length)
|
|
42098
|
+
stack.push({ kids: c.children, pos: 0, prefix: `${f.prefix}${last ? " " : "\u2502 "}` });
|
|
42099
|
+
}
|
|
42100
|
+
return out;
|
|
42101
|
+
}
|
|
42102
|
+
function graphLines(g) {
|
|
42103
|
+
const s = [graphSection(g, "dependencies"), graphSection(g, "dependents")].filter(
|
|
42104
|
+
(x) => x.length
|
|
42105
|
+
);
|
|
42106
|
+
return s.flatMap((x, i) => i === 0 ? x : ["", ...x]);
|
|
42107
|
+
}
|
|
42108
|
+
function subtasksOf(t, rows3) {
|
|
42109
|
+
const me = canonicalId(t.id);
|
|
42110
|
+
return rows3.filter((r) => r.place === "tasks" && r.parentId && canonicalId(r.parentId) === me).map((r) => ({ id: shown(r.id, r.place), title: r.title })).sort((a, b) => compareTaskIds(a.id, b.id));
|
|
42111
|
+
}
|
|
42112
|
+
function listItem(t, status, statuses) {
|
|
42113
|
+
const resolve = typeof status === "function" ? status : (d) => {
|
|
42114
|
+
const st = status.get(d.toUpperCase());
|
|
42115
|
+
return st === void 0 ? void 0 : { id: d, status: st };
|
|
42116
|
+
};
|
|
42117
|
+
return {
|
|
42118
|
+
id: shown(t.id, t.place),
|
|
41860
42119
|
title: t.title,
|
|
41861
42120
|
status: t.status,
|
|
41862
|
-
archived: t.place
|
|
42121
|
+
archived: ARCHIVE.has(t.place),
|
|
41863
42122
|
type: t.type ?? null,
|
|
41864
42123
|
priority: t.priority ?? null,
|
|
41865
42124
|
project: null,
|
|
@@ -41867,7 +42126,7 @@ function listItem(t, status) {
|
|
|
41867
42126
|
reporter: t.reporter ?? null,
|
|
41868
42127
|
labels: t.labels,
|
|
41869
42128
|
milestone: t.milestone ?? null,
|
|
41870
|
-
parentTaskId: t.parentId
|
|
42129
|
+
parentTaskId: t.parentId ? shown(t.parentId, t.place) : null,
|
|
41871
42130
|
acceptanceCriteriaCompleted: t.ac.filter((c) => c.done).length,
|
|
41872
42131
|
acceptanceCriteriaCount: t.ac.length,
|
|
41873
42132
|
references: t.references,
|
|
@@ -41876,21 +42135,29 @@ function listItem(t, status) {
|
|
|
41876
42135
|
createdAt: t.createdAt,
|
|
41877
42136
|
updatedAt: t.updatedAt ?? null,
|
|
41878
42137
|
dueDate: null,
|
|
41879
|
-
isReady: readiness(t,
|
|
42138
|
+
isReady: readiness(t, resolve, statuses).isReady,
|
|
41880
42139
|
area: t.area,
|
|
41881
42140
|
aliases: t.aliases,
|
|
41882
42141
|
version: t.version
|
|
41883
42142
|
};
|
|
41884
42143
|
}
|
|
41885
|
-
function viewItem(t,
|
|
42144
|
+
function viewItem(t, v) {
|
|
41886
42145
|
const checks5 = (cs) => cs.map((c, i) => ({ index: i + 1, text: c.text, checked: c.done }));
|
|
42146
|
+
const g = dependencyGraph(t, v.rows, v.statuses);
|
|
42147
|
+
const index2 = boardIndex(v.rows);
|
|
42148
|
+
const resolve = (d) => {
|
|
42149
|
+
const r = index2.get(canonicalId(d));
|
|
42150
|
+
return r && r !== "ambiguous" ? { id: shown(r.id, r.place), status: r.status } : void 0;
|
|
42151
|
+
};
|
|
41887
42152
|
return {
|
|
41888
|
-
...listItem(t,
|
|
41889
|
-
|
|
42153
|
+
...listItem(t, resolve, v.statuses),
|
|
42154
|
+
path: v.path ?? null,
|
|
42155
|
+
description: t.description || null,
|
|
41890
42156
|
dependencies: t.dependencies,
|
|
41891
|
-
|
|
42157
|
+
dependencyGraph: { root: g.rootId, nodes: g.nodes, edges: g.edges },
|
|
42158
|
+
readiness: readiness(t, resolve, v.statuses),
|
|
41892
42159
|
documentation: [],
|
|
41893
|
-
subtasks:
|
|
42160
|
+
subtasks: subtasksOf(t, v.rows),
|
|
41894
42161
|
acceptanceCriteria: checks5(t.ac),
|
|
41895
42162
|
definitionOfDone: checks5(t.dod),
|
|
41896
42163
|
implementationPlan: t.plan ?? null,
|
|
@@ -41898,69 +42165,118 @@ function viewItem(t, status, subtasks) {
|
|
|
41898
42165
|
comments: t.comments.map((c, i) => ({
|
|
41899
42166
|
index: i + 1,
|
|
41900
42167
|
body: c.body,
|
|
41901
|
-
|
|
41902
|
-
|
|
42168
|
+
createdAt: c.created,
|
|
42169
|
+
author: c.author ?? null
|
|
41903
42170
|
})),
|
|
41904
42171
|
finalSummary: t.finalSummary ?? null,
|
|
41905
42172
|
closedAt: t.closedAt ?? null,
|
|
41906
42173
|
extra: t.extra
|
|
41907
42174
|
};
|
|
41908
42175
|
}
|
|
41909
|
-
var RULE = "
|
|
42176
|
+
var RULE = "-".repeat(50);
|
|
41910
42177
|
var when = (iso2) => `${iso2.slice(0, 10)} ${iso2.slice(11, 16)} (UTC)`;
|
|
41911
|
-
var
|
|
41912
|
-
|
|
41913
|
-
|
|
41914
|
-
|
|
42178
|
+
var ICONS = {
|
|
42179
|
+
done: "\u2714",
|
|
42180
|
+
"in progress": "\u25D2",
|
|
42181
|
+
blocked: "\u25CF",
|
|
42182
|
+
"to do": "\u25CB",
|
|
42183
|
+
review: "\u25C6",
|
|
42184
|
+
testing: "\u25A3"
|
|
42185
|
+
};
|
|
42186
|
+
var withIcon = (s) => `${ICONS[s.trim().toLowerCase()] ?? "\u25CB"} ${s}`;
|
|
42187
|
+
var PRIORITY = { high: "High", medium: "Medium", low: "Low" };
|
|
42188
|
+
var priorityLabel = (p) => {
|
|
42189
|
+
const n = p.trim().toLowerCase();
|
|
42190
|
+
return PRIORITY[n] ?? n.split(" ").map((x) => x ? x[0]?.toUpperCase() + x.slice(1) : "").join(" ");
|
|
42191
|
+
};
|
|
42192
|
+
var at2 = (a) => a.startsWith("@") ? a : `@${a}`;
|
|
42193
|
+
function viewPlain(t, v) {
|
|
42194
|
+
const out = [];
|
|
42195
|
+
if (v.file) out.push(`File: ${v.file}`, "");
|
|
42196
|
+
out.push(`Task ${shown(t.id, t.place)} - ${t.title}`, "=".repeat(50), "");
|
|
42197
|
+
out.push(`Status: ${withIcon(t.status)}${ARCHIVE.has(t.place) ? " (archived)" : ""}`);
|
|
42198
|
+
if (t.priority) out.push(`Priority: ${priorityLabel(t.priority)}`);
|
|
41915
42199
|
if (t.type) out.push(`Type: ${t.type}`);
|
|
41916
42200
|
if (t.ordinal !== void 0) out.push(`Ordinal: ${t.ordinal}`);
|
|
41917
|
-
if (t.assignees.length) out.push(`Assignee: ${t.assignees.join(", ")}`);
|
|
42201
|
+
if (t.assignees.length) out.push(`Assignee: ${t.assignees.map(at2).join(", ")}`);
|
|
42202
|
+
if (t.reporter) out.push(`Reporter: ${at2(t.reporter)}`);
|
|
41918
42203
|
out.push(`Created: ${when(t.createdAt)}`);
|
|
41919
42204
|
if (t.updatedAt) out.push(`Updated: ${when(t.updatedAt)}`);
|
|
41920
42205
|
if (t.labels.length) out.push(`Labels: ${t.labels.join(", ")}`);
|
|
41921
42206
|
if (t.milestone) out.push(`Milestone: ${t.milestone}`);
|
|
41922
|
-
if (t.parentId)
|
|
41923
|
-
|
|
42207
|
+
if (t.parentId) {
|
|
42208
|
+
const key = canonicalId(t.parentId);
|
|
42209
|
+
const p = v.rows.find((r) => r.place === "tasks" && canonicalId(r.id) === key);
|
|
42210
|
+
out.push(`Parent: ${shown(t.parentId, t.place)}${p ? ` - ${p.title}` : ""}`);
|
|
42211
|
+
}
|
|
42212
|
+
const subs = subtasksOf(t, v.rows);
|
|
42213
|
+
if (subs.length)
|
|
42214
|
+
out.push(`Subtasks (${subs.length}):`, ...subs.map((x) => `- ${x.id} - ${x.title}`));
|
|
42215
|
+
if (t.references.length) out.push(`References: ${t.references.join(", ")}`);
|
|
42216
|
+
if (!v.exact)
|
|
42217
|
+
out.push(
|
|
42218
|
+
`Area: ${t.area}${t.aliases.length ? ` (also ${t.aliases.join(", ")})` : ""}`,
|
|
42219
|
+
`Version: ${t.version}`
|
|
42220
|
+
);
|
|
42221
|
+
const graph = graphLines(dependencyGraph(t, v.rows, v.statuses));
|
|
42222
|
+
if (graph.length) out.push("", "Dependency Graph:", RULE, ...graph);
|
|
42223
|
+
const checks5 = (cs, none) => cs.length ? cs.map((c, i) => `- [${c.done ? "x" : " "}] #${i + 1} ${c.text}`) : [none];
|
|
42224
|
+
out.push("", "Description:", RULE, t.description?.trim() || "No description provided", "");
|
|
42225
|
+
out.push("Acceptance Criteria:", RULE, ...checks5(t.ac, "No acceptance criteria defined"), "");
|
|
41924
42226
|
out.push(
|
|
41925
|
-
|
|
41926
|
-
|
|
42227
|
+
"Definition of Done:",
|
|
42228
|
+
RULE,
|
|
42229
|
+
...checks5(t.dod, "No Definition of Done items defined"),
|
|
42230
|
+
""
|
|
41927
42231
|
);
|
|
41928
|
-
if (subtasks.length)
|
|
41929
|
-
out.push("", "Subtasks:", RULE, ...subtasks.map((x) => `- ${x.id} - ${x.title} [${x.status}]`));
|
|
41930
42232
|
const block = (head, body) => {
|
|
41931
|
-
|
|
42233
|
+
const b = body?.trim();
|
|
42234
|
+
if (b) out.push(`${head}:`, RULE, b, "");
|
|
41932
42235
|
};
|
|
41933
|
-
const list2 = (cs) => cs.map((c, i) => `- [${c.done ? "x" : " "}] #${i + 1} ${c.text}`).join("\n");
|
|
41934
|
-
block("Description", t.description);
|
|
41935
|
-
block("Acceptance Criteria", list2(t.ac));
|
|
41936
|
-
block("Definition of Done", list2(t.dod));
|
|
41937
42236
|
block("Implementation Plan", t.plan);
|
|
41938
42237
|
block("Implementation Notes", t.notes);
|
|
41939
|
-
|
|
41940
|
-
|
|
41941
|
-
|
|
41942
|
-
|
|
41943
|
-
|
|
42238
|
+
const comments2 = t.comments.filter((c) => c.body.trim());
|
|
42239
|
+
if (comments2.length) {
|
|
42240
|
+
out.push("Comments:", RULE);
|
|
42241
|
+
comments2.forEach((c, i) => {
|
|
42242
|
+
out.push(
|
|
42243
|
+
[
|
|
42244
|
+
`#${i + 1}`,
|
|
42245
|
+
...c.author ? [c.author] : [],
|
|
42246
|
+
...c.created ? [when(c.created)] : []
|
|
42247
|
+
].join(" - ")
|
|
42248
|
+
);
|
|
42249
|
+
out.push(c.body.trim(), "");
|
|
42250
|
+
});
|
|
42251
|
+
}
|
|
41944
42252
|
block("Final Summary", t.finalSummary);
|
|
41945
42253
|
return `${out.join("\n")}
|
|
41946
42254
|
`;
|
|
41947
42255
|
}
|
|
41948
42256
|
function listPlain(ts, statuses) {
|
|
42257
|
+
if (!ts.length) return "No tasks found.\n";
|
|
42258
|
+
const canon = new Map(statuses.map((s) => [s.toLowerCase(), s]));
|
|
41949
42259
|
const groups = /* @__PURE__ */ new Map();
|
|
41950
|
-
for (const t of ts)
|
|
41951
|
-
|
|
41952
|
-
|
|
42260
|
+
for (const t of ts) {
|
|
42261
|
+
const s = canon.get(t.status.trim().toLowerCase()) ?? t.status.trim();
|
|
42262
|
+
groups.set(s, [...groups.get(s) ?? [], t]);
|
|
42263
|
+
}
|
|
42264
|
+
const order = [
|
|
42265
|
+
...statuses.filter((s) => groups.has(s)),
|
|
42266
|
+
...[...groups.keys()].filter((s) => !statuses.includes(s))
|
|
42267
|
+
];
|
|
42268
|
+
let out = "";
|
|
41953
42269
|
for (const s of order) {
|
|
41954
|
-
|
|
41955
|
-
|
|
41956
|
-
|
|
41957
|
-
|
|
41958
|
-
out.
|
|
41959
|
-
|
|
41960
|
-
|
|
41961
|
-
out
|
|
42270
|
+
out += `${s || "No Status"}:
|
|
42271
|
+
`;
|
|
42272
|
+
for (const t of groups.get(s) ?? []) {
|
|
42273
|
+
const ac = t.ac.length ? ` (ac: ${t.ac.filter((c) => c.done).length}/${t.ac.length})` : "";
|
|
42274
|
+
out += ` ${t.priority ? `[${t.priority.toUpperCase()}] ` : ""}${t.type ? `[${t.type}] ` : ""}${shown(t.id, t.place)} - ${t.title}${ac}
|
|
42275
|
+
`;
|
|
42276
|
+
}
|
|
42277
|
+
out += "\n";
|
|
41962
42278
|
}
|
|
41963
|
-
return out
|
|
42279
|
+
return out;
|
|
41964
42280
|
}
|
|
41965
42281
|
|
|
41966
42282
|
// src/sidecar.ts
|
|
@@ -42076,10 +42392,19 @@ function editFlags(c, create) {
|
|
|
42076
42392
|
function registerCommands(program3, ctx) {
|
|
42077
42393
|
program3.version(ctx.version, "-v, --version");
|
|
42078
42394
|
async function show(a, t, o, kind) {
|
|
42079
|
-
const
|
|
42080
|
-
|
|
42081
|
-
|
|
42082
|
-
|
|
42395
|
+
const [rows3, files] = await Promise.all([
|
|
42396
|
+
a.dependencyRows(),
|
|
42397
|
+
ctx.mirrorDir ? a.mirrorFiles([t.id]) : Promise.resolve([])
|
|
42398
|
+
]);
|
|
42399
|
+
const file2 = files[0] && ctx.mirrorDir ? join6(ctx.mirrorDir, files[0].path) : void 0;
|
|
42400
|
+
const v = {
|
|
42401
|
+
rows: rows3,
|
|
42402
|
+
statuses: STATUSES,
|
|
42403
|
+
...file2 ? { file: file2, path: relative(dirname3(ctx.mirrorDir), file2) } : {},
|
|
42404
|
+
...ctx.exact ? { exact: true } : {}
|
|
42405
|
+
};
|
|
42406
|
+
if (o.json) print3({ schemaVersion: 1, kind, task: viewItem(t, v) });
|
|
42407
|
+
else print3(viewPlain(t, v));
|
|
42083
42408
|
}
|
|
42084
42409
|
const withBoardOrStore = (fn) => ctx.withBoard ? ctx.withBoard(fn) : ctx.withStore((a) => fn(a, null));
|
|
42085
42410
|
async function after(a, id) {
|
|
@@ -42170,10 +42495,14 @@ function registerCommands(program3, ctx) {
|
|
|
42170
42495
|
if (!SORT_FIELDS.includes(field)) throw new Error(`cannot sort by ${field}`);
|
|
42171
42496
|
return { field, dir: dir === "desc" ? "desc" : "asc" };
|
|
42172
42497
|
});
|
|
42173
|
-
const ts = await a.list(f, sorts);
|
|
42498
|
+
const ts = sorts.length ? await a.list(f, sorts) : backlogOrder(await a.list(f));
|
|
42174
42499
|
if (o.json) {
|
|
42175
42500
|
const status = await a.statusOf(ts.flatMap((t) => t.dependencies));
|
|
42176
|
-
print3({
|
|
42501
|
+
print3({
|
|
42502
|
+
schemaVersion: 1,
|
|
42503
|
+
kind: "task-list",
|
|
42504
|
+
tasks: ts.map((t) => listItem(t, status, STATUSES))
|
|
42505
|
+
});
|
|
42177
42506
|
} else print3(listPlain(ts, STATUSES));
|
|
42178
42507
|
}
|
|
42179
42508
|
listCmd(task2.command("list").description("list tasks")).action(
|
|
@@ -42205,7 +42534,7 @@ function registerCommands(program3, ctx) {
|
|
|
42205
42534
|
print3({
|
|
42206
42535
|
schemaVersion: 1,
|
|
42207
42536
|
kind: "search",
|
|
42208
|
-
results: hits.map((h) => ({ type: "task", data: listItem(h.task, status) }))
|
|
42537
|
+
results: hits.map((h) => ({ type: "task", data: listItem(h.task, status, STATUSES) }))
|
|
42209
42538
|
});
|
|
42210
42539
|
} else print3(searchPlain(hits));
|
|
42211
42540
|
})
|
|
@@ -42535,7 +42864,7 @@ async function open2(migrateNow) {
|
|
|
42535
42864
|
}
|
|
42536
42865
|
const { PGlite: PGlite2 } = await import("@electric-sql/pglite");
|
|
42537
42866
|
const { drizzle: drizzle3 } = await Promise.resolve().then(() => (init_pglite(), pglite_exports));
|
|
42538
|
-
const pg = new PGlite2(cfg.dir ??
|
|
42867
|
+
const pg = new PGlite2(cfg.dir ?? join8(homedir4(), ".aerie"));
|
|
42539
42868
|
const db = drizzle3(pg);
|
|
42540
42869
|
await migrateAerie(db);
|
|
42541
42870
|
return { db, close: () => pg.close() };
|
|
@@ -42556,6 +42885,8 @@ registerCommands(program2, {
|
|
|
42556
42885
|
by: cfg.by ?? `@${userInfo().username}`,
|
|
42557
42886
|
// the mirror is the host's (its files and rows are host-only over the wire)
|
|
42558
42887
|
...cfg.mirrorDir && !cfg.remoteUrl ? { mirrorDir: cfg.mirrorDir } : {},
|
|
42888
|
+
// set by the `backlog` shim: Backlog.md's text, byte for byte
|
|
42889
|
+
...process.env.AERIE_BACKLOG_EXACT ? { exact: true } : {},
|
|
42559
42890
|
version: pkg.version,
|
|
42560
42891
|
local: !cfg.url && !cfg.remoteUrl,
|
|
42561
42892
|
async withStore(fn) {
|