@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 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 terminal = i === fullpath.length - 1;
2411
+ const terminal2 = i === fullpath.length - 1;
2412
2412
  if (el === "_errors") {
2413
- if (terminal)
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 (terminal) {
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 terminal = i === fullpath.length - 1;
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 (terminal) {
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 cap2 = Math.min(...caps.map((c) => c[0]));
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 > cap2 && !ctx?.skipChecks && ctx?.direction !== "backward") {
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 join8(chunks, separator) {
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 = join8;
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((join8) => join8.alias === tableName)) {
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((join8) => join8.alias === tableName)) {
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 join8 of this.config.joins) {
28880
- const tableName2 = getTableLikeName(join8.table);
28881
- if (typeof tableName2 === "string" && !is(join8.table, SQL)) {
28882
- const fromFields = this.getTableLikeFields(join8.table);
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 at3 = (n) => {
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 ?? []) at3(n).done = true;
30118
- for (const n of e.uncheck ?? []) at3(n).done = false;
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) at3(n);
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 at3 = now();
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: at3,
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 } : {} }, at3);
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, [...new Set(ids)]));
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(and(eq(taskEvent.taskId, taskId.toUpperCase()), eq(taskEvent.kind, kind))).orderBy(sql`${taskEvent.seq} desc`).limit(1);
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 at3 = (t) => t.updatedAt ?? t.createdAt;
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) || at3(y.task).localeCompare(at3(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 ? at2(o.now()) : sql`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, at2, num, textArr;
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
- at2 = (v) => sql`to_timestamp(${v}::float8 / 1000)`;
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 dirname3, join as join6 } from "node:path";
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(dirname3(file2), { recursive: true, mode: 448 });
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 = () => join6(homedir3(), ".config", "aerie", "env");
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 join7 } from "node:path";
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, at3) => {
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: at3, title: task2.title, span: task2.span });
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: at3,
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: join8 } = await import("node:path");
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(join8(tmpdir2(), "aerie-hear-"));
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 cap2 = o.cap === void 0 ? caps[name] : Number(o.cap);
41570
- if (cap2 !== void 0 && !(Number.isInteger(cap2) && cap2 > 0))
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"}: ${cap2} is not a whole number above 0`
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
- ...cap2 === void 0 ? {} : { cap: cap2 },
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 DONE = "Done";
41846
- function readiness(t, status) {
41847
- const missing = t.dependencies.filter((d) => !status.has(d));
41848
- const blocking = t.dependencies.filter((d) => status.has(d) && status.get(d) !== DONE);
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: t.status !== DONE && !isBlocked,
41923
+ isReady: !isBlocked,
41852
41924
  isBlocked,
41853
41925
  blockingDependencies: blocking,
41854
41926
  missingDependencies: missing
41855
41927
  };
41856
41928
  }
41857
- function listItem(t, status) {
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
- id: t.id,
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.startsWith("archive"),
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 ?? null,
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, status).isReady,
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, status, subtasks) {
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, status),
41889
- description: t.description ?? null,
42153
+ ...listItem(t, resolve, v.statuses),
42154
+ path: v.path ?? null,
42155
+ description: t.description || null,
41890
42156
  dependencies: t.dependencies,
41891
- readiness: readiness(t, status),
42157
+ dependencyGraph: { root: g.rootId, nodes: g.nodes, edges: g.edges },
42158
+ readiness: readiness(t, resolve, v.statuses),
41892
42159
  documentation: [],
41893
- subtasks: subtasks.map((x) => ({ id: x.id, title: x.title, status: x.status })),
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
- author: c.author ?? null,
41902
- createdAt: c.created
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 cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
41912
- function viewPlain(t, subtasks) {
41913
- const out = [`Task ${t.id} - ${t.title}`, "=".repeat(50), "", `Status: ${t.status}`];
41914
- if (t.priority) out.push(`Priority: ${cap(t.priority)}`);
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) out.push(`Parent: ${t.parentId}`);
41923
- if (t.dependencies.length) out.push(`Dependencies: ${t.dependencies.join(", ")}`);
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
- `Area: ${t.area}${t.aliases.length ? ` (also ${t.aliases.join(", ")})` : ""}`,
41926
- `Version: ${t.version}`
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
- if (body) out.push("", `${head}:`, RULE, body);
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
- block(
41940
- "Comments",
41941
- t.comments.map((c, i) => `#${i + 1} - ${c.author ? `${c.author}, ` : ""}${when(c.created)}
41942
- ${c.body}`).join("\n\n")
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) groups.set(t.status, [...groups.get(t.status) ?? [], t]);
41951
- const order = [...statuses, ...[...groups.keys()].filter((s) => !statuses.includes(s))];
41952
- const out = [];
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
- const g = groups.get(s);
41955
- if (!g?.length) continue;
41956
- out.push(`${s}:`);
41957
- for (const t of g)
41958
- out.push(
41959
- ` ${t.priority ? `[${t.priority.toUpperCase()}] ` : ""}${t.type ? `[${t.type}] ` : ""}${t.id} - ${t.title}`
41960
- );
41961
- out.push("");
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.length ? out.join("\n") : "No tasks found.\n";
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 status = await a.statusOf(t.dependencies);
42080
- const subs = await a.list({ parent: t.id, place: ["tasks", "drafts"] });
42081
- if (o.json) print3({ schemaVersion: 1, kind, task: viewItem(t, status, subs) });
42082
- else print3(viewPlain(t, subs));
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({ schemaVersion: 1, kind: "task-list", tasks: ts.map((t) => listItem(t, status)) });
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 ?? join7(homedir4(), ".aerie"));
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) {