@basou/core 0.42.0 → 0.42.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2140,6 +2140,15 @@ type ViewStrings = {
2140
2140
  headingForward: string;
2141
2141
  headingCurrency: string;
2142
2142
  inFlightTasksHeading: (n: number) => string;
2143
+ /**
2144
+ * Body line under the in-flight-tasks heading when NO task was ever
2145
+ * recorded here. "(none)" states that nothing is pending — a claim about
2146
+ * the work. This one claims only what it can see: that the record is
2147
+ * empty. It says nothing about whether the workspace should use tasks,
2148
+ * and names no command: the renderers report position, and a nudge that
2149
+ * cannot be silenced is noise (see `trackNudge`, which is gated).
2150
+ */
2151
+ noTasksRecorded: string;
2143
2152
  pendingApprovalsHeading: (n: number) => string;
2144
2153
  suspectSessionsHeading: (n: number) => string;
2145
2154
  openTracksHeading: (n: number) => string;
@@ -2188,6 +2197,10 @@ type ViewStrings = {
2188
2197
  headingNextWork: string;
2189
2198
  headingSessions: string;
2190
2199
  lastTaskLabel: string;
2200
+ /** "Work to do next" placeholder: tasks exist, none are open. */
2201
+ noPendingTasks: string;
2202
+ /** "Work to do next" placeholder: no task was ever recorded. */
2203
+ noTasksRecorded: string;
2191
2204
  decisionStaleNote: string;
2192
2205
  trackCloseInstruction: string;
2193
2206
  };
@@ -4374,6 +4387,10 @@ type OrientationSummary = {
4374
4387
  };
4375
4388
  /** Tasks whose status is `planned` or `in_progress`. */
4376
4389
  inFlightTasks: InFlightTask[];
4390
+ /** Whether any task was ever recorded here, by any surviving trace — lets a
4391
+ * zero in-flight count distinguish "all closed" from "never used here".
4392
+ * See {@link anyTaskEverRecorded}: a live count is NOT this. */
4393
+ anyTaskEverRecorded: boolean;
4377
4394
  /** Tasks whose status is `planned` ("where am I heading"). */
4378
4395
  plannedTasks: PlannedTask[];
4379
4396
  pendingApprovals: PendingApproval[];
package/dist/index.js CHANGED
@@ -2150,6 +2150,7 @@ var EN = {
2150
2150
  headingForward: "## Where you are heading",
2151
2151
  headingCurrency: "## Is this current",
2152
2152
  inFlightTasksHeading: (n) => `### In-flight tasks (${n})`,
2153
+ noTasksRecorded: "(no tasks recorded)",
2153
2154
  pendingApprovalsHeading: (n) => `### Pending approvals (${n})`,
2154
2155
  suspectSessionsHeading: (n) => `### Suspect sessions (${n})`,
2155
2156
  openTracksHeading: (n) => `### Open tracks (shown until closed) (${n})`,
@@ -2211,6 +2212,8 @@ var EN = {
2211
2212
  headingNextWork: "## Work to do next",
2212
2213
  headingSessions: "## Sessions",
2213
2214
  lastTaskLabel: "Last task",
2215
+ noPendingTasks: "(no pending tasks)",
2216
+ noTasksRecorded: "(no tasks recorded)",
2214
2217
  decisionStaleNote: "Note: the latest activity postdates this decision. It may already be resolved in conversation \u2014 confirm the continuation point before resuming (conversational decisions are not captured automatically; record them with `basou decision capture`).",
2215
2218
  trackCloseInstruction: "When finished, close it with `basou decision void <decision_id>`."
2216
2219
  },
@@ -2246,6 +2249,7 @@ var JA = {
2246
2249
  headingForward: "## \u3069\u3053\u3078\u5411\u304B\u3046",
2247
2250
  headingCurrency: "## \u3053\u308C\u306F\u6700\u65B0\u304B",
2248
2251
  inFlightTasksHeading: (n) => `### \u9032\u884C\u4E2D task (${n})`,
2252
+ noTasksRecorded: "(task \u304C 1 \u4EF6\u3082\u8A18\u9332\u3055\u308C\u3066\u3044\u307E\u305B\u3093)",
2249
2253
  pendingApprovalsHeading: (n) => `### \u627F\u8A8D\u5F85\u3061 (${n})`,
2250
2254
  suspectSessionsHeading: (n) => `### \u8981\u6CE8\u610F session (${n})`,
2251
2255
  openTracksHeading: (n) => `### \u672A\u5B8C\u30C8\u30E9\u30C3\u30AF (close \u307E\u3067\u7D99\u7D9A\u8868\u793A) (${n})`,
@@ -2307,6 +2311,8 @@ var JA = {
2307
2311
  headingNextWork: "## \u6B21\u306B\u5B9F\u884C\u3059\u3079\u304D\u4F5C\u696D",
2308
2312
  headingSessions: "## \u30BB\u30C3\u30B7\u30E7\u30F3\u4E00\u89A7",
2309
2313
  lastTaskLabel: "\u6700\u7D42 task",
2314
+ noPendingTasks: "(\u672A\u5B8C\u4E86\u306E task \u306F\u3042\u308A\u307E\u305B\u3093)",
2315
+ noTasksRecorded: "(task \u304C 1 \u4EF6\u3082\u8A18\u9332\u3055\u308C\u3066\u3044\u307E\u305B\u3093)",
2310
2316
  decisionStaleNote: "\u6CE8: \u6700\u7D42\u6D3B\u52D5\u306F\u3053\u306E\u5224\u65AD\u3088\u308A\u5F8C\u3067\u3059\u3002\u4F1A\u8A71\u3067\u65E2\u306B\u89E3\u6C7A\u6E08\u307F\u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u3001\u518D\u958B\u524D\u306B\u7D99\u7D9A\u70B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044(\u4F1A\u8A71\u3067\u306E\u610F\u601D\u6C7A\u5B9A\u306F\u81EA\u52D5\u8A18\u9332\u3055\u308C\u307E\u305B\u3093\u3002`basou decision capture` \u3067\u8A18\u9332\u3067\u304D\u307E\u3059)\u3002",
2311
2317
  trackCloseInstruction: "\u5B8C\u4E86\u3057\u305F\u3089 `basou decision void <decision_id>` \u3067\u9589\u3058\u3066\u304F\u3060\u3055\u3044\u3002"
2312
2318
  },
@@ -5395,6 +5401,14 @@ async function archiveTaskLocked(input) {
5395
5401
  eventId
5396
5402
  };
5397
5403
  }
5404
+ async function anyTaskEverRecorded(input) {
5405
+ if (input.liveCount > 0 || input.taskCreatedSeen || input.skippedCount > 0) return true;
5406
+ try {
5407
+ return (await enumerateArchivedTaskIds(input.paths)).length > 0;
5408
+ } catch {
5409
+ return true;
5410
+ }
5411
+ }
5398
5412
 
5399
5413
  // src/handoff/handoff-renderer.ts
5400
5414
  async function renderHandoff(input) {
@@ -5491,8 +5505,13 @@ async function renderHandoff(input) {
5491
5505
  const c = Date.parse(a.occurredAt) - Date.parse(b.occurredAt);
5492
5506
  return c !== 0 ? c : a.taskId.localeCompare(b.taskId);
5493
5507
  });
5494
- const taskLoadOpts = {};
5495
- if (input.onTaskSkip !== void 0) taskLoadOpts.onSkip = input.onTaskSkip;
5508
+ let skippedTaskCount = 0;
5509
+ const taskLoadOpts = {
5510
+ onSkip: (taskId, reason) => {
5511
+ skippedTaskCount += 1;
5512
+ input.onTaskSkip?.(taskId, reason);
5513
+ }
5514
+ };
5496
5515
  const taskEntries = await loadTaskEntries(input.paths, taskLoadOpts);
5497
5516
  const taskById = /* @__PURE__ */ new Map();
5498
5517
  for (const t of taskEntries) taskById.set(t.task.task.id, t);
@@ -5540,7 +5559,13 @@ async function renderHandoff(input) {
5540
5559
  latestActivityRecord,
5541
5560
  latestTaskDoc,
5542
5561
  pendingTasks,
5543
- totalTaskCount: taskEntries.length
5562
+ totalTaskCount: taskEntries.length,
5563
+ anyTaskEverRecorded: await anyTaskEverRecorded({
5564
+ paths: input.paths,
5565
+ liveCount: taskEntries.length,
5566
+ taskCreatedSeen: tasksCreated.length > 0,
5567
+ skippedCount: skippedTaskCount
5568
+ })
5544
5569
  });
5545
5570
  return {
5546
5571
  body,
@@ -5651,7 +5676,7 @@ function formatHandoffBody(args) {
5651
5676
  lines.push(t.handoff.headingNextWork);
5652
5677
  lines.push("");
5653
5678
  if (args.pendingTasks.length === 0) {
5654
- lines.push("(no pending tasks)");
5679
+ lines.push(args.anyTaskEverRecorded ? t.handoff.noPendingTasks : t.handoff.noTasksRecorded);
5655
5680
  } else {
5656
5681
  for (const t2 of args.pendingTasks) {
5657
5682
  lines.push(
@@ -5940,6 +5965,7 @@ async function summarizeOrientation(input) {
5940
5965
  else if (kind === "note" && typeof value === "string") bucket.notes.push(value);
5941
5966
  };
5942
5967
  let latestActivityAt = null;
5968
+ let taskCreatedSeen = false;
5943
5969
  let latestNote = null;
5944
5970
  const noteActivity = (iso) => {
5945
5971
  if (latestActivityAt === null || Date.parse(iso) > Date.parse(latestActivityAt)) {
@@ -5978,6 +6004,8 @@ async function summarizeOrientation(input) {
5978
6004
  host: entry.host
5979
6005
  });
5980
6006
  }
6007
+ } else if (ev.type === "task_created") {
6008
+ taskCreatedSeen = true;
5981
6009
  } else if (ev.type === "decision_voided") {
5982
6010
  voidedDecisionIds.add(ev.decision_id);
5983
6011
  }
@@ -6043,8 +6071,13 @@ async function summarizeOrientation(input) {
6043
6071
  files
6044
6072
  };
6045
6073
  });
6046
- const taskLoadOpts = {};
6047
- if (input.onTaskSkip !== void 0) taskLoadOpts.onSkip = input.onTaskSkip;
6074
+ let skippedTaskCount = 0;
6075
+ const taskLoadOpts = {
6076
+ onSkip: (taskId, reason) => {
6077
+ skippedTaskCount += 1;
6078
+ input.onTaskSkip?.(taskId, reason);
6079
+ }
6080
+ };
6048
6081
  const taskEntries = await loadTaskEntries(input.paths, taskLoadOpts);
6049
6082
  const inFlightTasks = taskEntries.filter((t) => t.task.task.status === "in_progress" || t.task.task.status === "planned").map((t) => ({
6050
6083
  id: t.task.task.id,
@@ -6138,6 +6171,12 @@ async function summarizeOrientation(input) {
6138
6171
  recentDirection,
6139
6172
  relatedFiles: { displayed, overflow, outOfRoot, omitted: omittedFiles },
6140
6173
  inFlightTasks,
6174
+ anyTaskEverRecorded: await anyTaskEverRecorded({
6175
+ paths: input.paths,
6176
+ liveCount: taskEntries.length,
6177
+ taskCreatedSeen,
6178
+ skippedCount: skippedTaskCount
6179
+ }),
6141
6180
  plannedTasks,
6142
6181
  pendingApprovals,
6143
6182
  suspects,
@@ -6274,7 +6313,7 @@ function formatOrientationBody(summary, opts) {
6274
6313
  lines.push("");
6275
6314
  lines.push(t.orientation.inFlightTasksHeading(summary.inFlightTasks.length));
6276
6315
  if (summary.inFlightTasks.length === 0) {
6277
- lines.push("- (none)");
6316
+ lines.push(summary.anyTaskEverRecorded ? "- (none)" : `- ${t.orientation.noTasksRecorded}`);
6278
6317
  } else {
6279
6318
  for (const t2 of summary.inFlightTasks) {
6280
6319
  const linkedSuffix = t2.linkedSessions > 1 ? ` \u2014 linked_sessions: ${t2.linkedSessions}` : "";