@basou/core 0.40.0 → 0.41.0

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
@@ -2111,6 +2111,8 @@ type ViewStrings = {
2111
2111
  recentDecisionsLabel: string;
2112
2112
  recentNextStepLabel: string;
2113
2113
  recentChangedLabel: string;
2114
+ /** Trails the recent-files line when scratch paths were left out of it. */
2115
+ scratchOmitted: (count: number) => string;
2114
2116
  trackCloseInstruction: string;
2115
2117
  nextStepRecordedLabel: (age: string) => string;
2116
2118
  noteStaleNote: (activityAge: string) => string;
@@ -4328,6 +4330,8 @@ type OrientationSummary = {
4328
4330
  displayed: string[];
4329
4331
  overflow: number;
4330
4332
  outOfRoot: string[];
4333
+ /** Scratch paths left out of `displayed` (see `isTransientToolPath`). */
4334
+ omitted: number;
4331
4335
  };
4332
4336
  /** Tasks whose status is `planned` or `in_progress`. */
4333
4337
  inFlightTasks: InFlightTask[];
package/dist/index.js CHANGED
@@ -2098,6 +2098,7 @@ var EN = {
2098
2098
  recentDecisionsLabel: "Decisions",
2099
2099
  recentNextStepLabel: "Next step",
2100
2100
  recentChangedLabel: "Changed",
2101
+ scratchOmitted: (count) => `(+${count} scratch omitted)`,
2101
2102
  trackCloseInstruction: "When finished, close it with `basou decision void <decision_id>`. It stays listed here every time until closed.",
2102
2103
  nextStepRecordedLabel: (age) => `Next step (recorded, ${age})`,
2103
2104
  noteStaleNote: (age) => `Note: work continued after this was recorded (latest activity ${age}), so this starting point may be stale.`,
@@ -2193,6 +2194,7 @@ var JA = {
2193
2194
  recentDecisionsLabel: "\u5224\u65AD",
2194
2195
  recentNextStepLabel: "\u6B21\u306E\u8D77\u70B9",
2195
2196
  recentChangedLabel: "\u5909\u66F4",
2197
+ scratchOmitted: (count) => `(\u4F5C\u696D\u7528\u4E00\u6642\u30D5\u30A1\u30A4\u30EB ${count} \u4EF6\u306F\u9664\u5916)`,
2196
2198
  trackCloseInstruction: "\u5B8C\u4E86\u3057\u305F\u3089 `basou decision void <decision_id>` \u3067\u9589\u3058\u3066\u304F\u3060\u3055\u3044\u3002\u9589\u3058\u308B\u307E\u3067\u6BCE\u56DE\u3053\u3053\u306B\u8868\u793A\u3055\u308C\u307E\u3059\u3002",
2197
2199
  nextStepRecordedLabel: (age) => `\u6B21\u306E\u8D77\u70B9 (\u8A18\u9332\u6E08\u307F, ${age})`,
2198
2200
  noteStaleNote: (age) => `\u6CE8: \u3053\u306E\u8D77\u70B9\u306E\u8A18\u9332\u5F8C (\u6700\u7D42\u6D3B\u52D5 ${age}) \u3082\u4F5C\u696D\u304C\u7D9A\u3044\u3066\u3044\u307E\u3059\u3002\u518D\u958B\u70B9\u304C\u53E4\u3044\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002`,
@@ -2533,8 +2535,8 @@ async function isStaleLock(lockPath) {
2533
2535
  }
2534
2536
  }
2535
2537
  function lockfilePath(paths, scope, resourceId) {
2536
- const sep = resourceId.indexOf("_");
2537
- const ulid2 = sep >= 0 ? resourceId.slice(sep + 1) : resourceId;
2538
+ const sep2 = resourceId.indexOf("_");
2539
+ const ulid2 = sep2 >= 0 ? resourceId.slice(sep2 + 1) : resourceId;
2538
2540
  return join3(paths.locks, `${scope}_${ulid2}.lock`);
2539
2541
  }
2540
2542
 
@@ -3597,6 +3599,29 @@ function pickLatestSubstantiveEntry(entries) {
3597
3599
  })[0];
3598
3600
  }
3599
3601
 
3602
+ // src/lib/transient-paths.ts
3603
+ import { tmpdir } from "os";
3604
+ import { normalize, sep } from "path";
3605
+ var TEMP_ROOTS = ["/tmp", "/var/tmp"];
3606
+ var MIN_ENCODED_DASHES = 3;
3607
+ function isEncodedWorkingDirectory(segment) {
3608
+ return segment.startsWith("-") && segment.split("-").length - 1 >= MIN_ENCODED_DASHES;
3609
+ }
3610
+ function withPrivateAlias(root) {
3611
+ const normalized = normalize(root);
3612
+ if (normalized.startsWith(`${sep}private${sep}`)) {
3613
+ return [normalized, normalized.slice(`${sep}private`.length)];
3614
+ }
3615
+ return [normalized, `${sep}private${normalized}`];
3616
+ }
3617
+ function isTransientToolPath(filePath, temp = tmpdir()) {
3618
+ const candidate = normalize(filePath);
3619
+ if (!candidate.startsWith(sep)) return false;
3620
+ const root = [...TEMP_ROOTS, temp].flatMap(withPrivateAlias).find((r) => candidate === r || candidate.startsWith(r + sep));
3621
+ if (root === void 0) return false;
3622
+ return candidate.slice(root.length).split(sep).some(isEncodedWorkingDirectory);
3623
+ }
3624
+
3600
3625
  // src/storage/tasks.ts
3601
3626
  import { createHash as createHash2 } from "crypto";
3602
3627
  import { mkdir as mkdir3, readdir as readdir4, readFile as readFile7, rename as rename2, stat as stat3, unlink as unlink3 } from "fs/promises";
@@ -5416,7 +5441,9 @@ async function renderHandoff(input) {
5416
5441
  (e) => e.session.session.status !== "archived" && e.session.session.source.kind !== "import"
5417
5442
  );
5418
5443
  const latestSession = pickLatestSubstantiveEntry(liveEntries);
5419
- const latestFiles = latestSession?.session.session.related_files ?? [];
5444
+ const latestFiles = (latestSession?.session.session.related_files ?? []).filter(
5445
+ (file) => !isTransientToolPath(file)
5446
+ );
5420
5447
  const sortedFiles = [...new Set(latestFiles)].sort();
5421
5448
  const displayedFiles = sortedFiles.slice(0, limit);
5422
5449
  const overflow = Math.max(0, sortedFiles.length - limit);
@@ -5634,9 +5661,9 @@ function shortHandoffId(sessionId) {
5634
5661
  return sessionId.slice(0, 10);
5635
5662
  }
5636
5663
  function shortIdWithPrefix(id) {
5637
- const sep = id.indexOf("_");
5638
- if (sep === -1) return id.slice(0, 10);
5639
- return id.slice(0, sep + 1) + id.slice(sep + 1, sep + 1 + 10);
5664
+ const sep2 = id.indexOf("_");
5665
+ if (sep2 === -1) return id.slice(0, 10);
5666
+ return id.slice(0, sep2 + 1) + id.slice(sep2 + 1, sep2 + 1 + 10);
5640
5667
  }
5641
5668
 
5642
5669
  // src/lib/duration.ts
@@ -5743,10 +5770,10 @@ async function resolveIdInternal(paths, input, kind, options = {}) {
5743
5770
  // src/lib/source-root-scope.ts
5744
5771
  import { promises as fs } from "fs";
5745
5772
  import { homedir as osHomedir } from "os";
5746
- import { basename as basename2, dirname as dirname3, isAbsolute, join as join14, normalize, relative, resolve as resolve2 } from "path";
5773
+ import { basename as basename2, dirname as dirname3, isAbsolute, join as join14, normalize as normalize2, relative, resolve as resolve2 } from "path";
5747
5774
  var AGENT_INFRA_DIRS = ["~/.claude", "~/.codex", "~/.basou"];
5748
5775
  async function realpathBestEffort(absPath) {
5749
- let current = normalize(absPath);
5776
+ let current = normalize2(absPath);
5750
5777
  const tail = [];
5751
5778
  for (let guard = 0; guard < 4096; guard += 1) {
5752
5779
  try {
@@ -5755,15 +5782,15 @@ async function realpathBestEffort(absPath) {
5755
5782
  } catch (error) {
5756
5783
  const code = error?.code;
5757
5784
  if (code !== "ENOENT" && code !== "ENOTDIR") {
5758
- return normalize(absPath);
5785
+ return normalize2(absPath);
5759
5786
  }
5760
5787
  const parent = dirname3(current);
5761
- if (parent === current) return normalize(absPath);
5788
+ if (parent === current) return normalize2(absPath);
5762
5789
  tail.push(basename2(current));
5763
5790
  current = parent;
5764
5791
  }
5765
5792
  }
5766
- return normalize(absPath);
5793
+ return normalize2(absPath);
5767
5794
  }
5768
5795
  function expandTilde(p, homedir5) {
5769
5796
  if (p === "~") return homedir5;
@@ -5772,8 +5799,8 @@ function expandTilde(p, homedir5) {
5772
5799
  }
5773
5800
  function toAbsolute(p, workingDirAbs, homedir5) {
5774
5801
  const expanded = expandTilde(p, homedir5);
5775
- if (isAbsolute(expanded)) return normalize(expanded);
5776
- return normalize(resolve2(workingDirAbs, expanded));
5802
+ if (isAbsolute(expanded)) return normalize2(expanded);
5803
+ return normalize2(resolve2(workingDirAbs, expanded));
5777
5804
  }
5778
5805
  function isUnder(child, parent) {
5779
5806
  if (child === parent) return true;
@@ -5790,12 +5817,12 @@ async function classifyFilesBySourceRoot(input) {
5790
5817
  const rootsAbs = [];
5791
5818
  for (const r of declared) {
5792
5819
  const expanded = expandTilde(r, homedir5);
5793
- const abs = isAbsolute(expanded) ? normalize(expanded) : normalize(resolve2(input.masterRoot, expanded));
5820
+ const abs = isAbsolute(expanded) ? normalize2(expanded) : normalize2(resolve2(input.masterRoot, expanded));
5794
5821
  rootsAbs.push(await realpathBestEffort(abs));
5795
5822
  }
5796
5823
  for (const e of input.extraInRoot ?? []) {
5797
5824
  const expanded = expandTilde(e, homedir5);
5798
- const abs = isAbsolute(expanded) ? normalize(expanded) : normalize(resolve2(homedir5, expanded));
5825
+ const abs = isAbsolute(expanded) ? normalize2(expanded) : normalize2(resolve2(homedir5, expanded));
5799
5826
  rootsAbs.push(await realpathBestEffort(abs));
5800
5827
  }
5801
5828
  if (rootsAbs.length === 0) {
@@ -5928,7 +5955,13 @@ async function summarizeOrientation(input) {
5928
5955
  const decisionTitles = (bucket?.decisions ?? []).filter((d) => !voidedDecisionIds.has(d.decisionId)).map((d) => d.title);
5929
5956
  const notes = bucket?.notes ?? [];
5930
5957
  const hasIntent = decisionTitles.length > 0 || notes.length > 0;
5931
- const files = hasIntent ? [] : [...new Set(entry.session.session.related_files ?? [])].sort().slice(0, FILES_PER_DIGEST);
5958
+ const files = hasIntent ? [] : [
5959
+ ...new Set(
5960
+ (entry.session.session.related_files ?? []).filter(
5961
+ (file) => !isTransientToolPath(file)
5962
+ )
5963
+ )
5964
+ ].sort().slice(0, FILES_PER_DIGEST);
5932
5965
  return {
5933
5966
  sessionId: entry.sessionId,
5934
5967
  label: entry.session.session.label ?? null,
@@ -5999,8 +6032,10 @@ async function summarizeOrientation(input) {
5999
6032
  } catch {
6000
6033
  sourceRoots = null;
6001
6034
  }
6002
- const latestFiles = latestEntry?.session.session.related_files ?? [];
6035
+ const recordedFiles = latestEntry?.session.session.related_files ?? [];
6036
+ const latestFiles = recordedFiles.filter((file) => !isTransientToolPath(file));
6003
6037
  const uniqueFiles = new Set(latestFiles);
6038
+ const omittedFiles = new Set(recordedFiles).size - uniqueFiles.size;
6004
6039
  const sortedFiles = [...uniqueFiles].sort();
6005
6040
  const displayed = sortedFiles.slice(0, limit);
6006
6041
  const overflow = Math.max(0, uniqueFiles.size - limit);
@@ -6031,7 +6066,7 @@ async function summarizeOrientation(input) {
6031
6066
  openTracks,
6032
6067
  latestNote,
6033
6068
  recentDirection,
6034
- relatedFiles: { displayed, overflow, outOfRoot },
6069
+ relatedFiles: { displayed, overflow, outOfRoot, omitted: omittedFiles },
6035
6070
  inFlightTasks,
6036
6071
  plannedTasks,
6037
6072
  pendingApprovals,
@@ -6119,10 +6154,16 @@ function formatOrientationBody(summary, opts) {
6119
6154
  `- ${t.common.latestDecisionLabel}: (no decisions recorded yet; capture with \`basou decision capture\`)`
6120
6155
  );
6121
6156
  }
6122
- if (summary.relatedFiles.displayed.length > 0) {
6123
- const shown = summary.relatedFiles.displayed.join(", ");
6124
- const more = summary.relatedFiles.overflow > 0 ? ` (... +${summary.relatedFiles.overflow} more)` : "";
6125
- lines.push(`- ${t.common.recentFilesLabel}: ${shown}${more}`);
6157
+ if (summary.relatedFiles.displayed.length > 0 || summary.relatedFiles.omitted > 0) {
6158
+ const parts = [];
6159
+ if (summary.relatedFiles.displayed.length > 0) {
6160
+ const more = summary.relatedFiles.overflow > 0 ? ` (... +${summary.relatedFiles.overflow} more)` : "";
6161
+ parts.push(`${summary.relatedFiles.displayed.join(", ")}${more}`);
6162
+ }
6163
+ if (summary.relatedFiles.omitted > 0) {
6164
+ parts.push(t.orientation.scratchOmitted(summary.relatedFiles.omitted));
6165
+ }
6166
+ lines.push(`- ${t.common.recentFilesLabel}: ${parts.join(" ")}`);
6126
6167
  if (summary.relatedFiles.outOfRoot.length > 0) {
6127
6168
  const OUT_OF_ROOT_DISPLAY = 10;
6128
6169
  const out = summary.relatedFiles.outOfRoot;
@@ -6371,9 +6412,9 @@ function suspectText(reason) {
6371
6412
  return "suspect";
6372
6413
  }
6373
6414
  function shortId(id) {
6374
- const sep = id.indexOf("_");
6375
- if (sep === -1) return id.slice(0, 10);
6376
- return id.slice(0, sep + 1) + id.slice(sep + 1, sep + 1 + 10);
6415
+ const sep2 = id.indexOf("_");
6416
+ if (sep2 === -1) return id.slice(0, 10);
6417
+ return id.slice(0, sep2 + 1) + id.slice(sep2 + 1, sep2 + 1 + 10);
6377
6418
  }
6378
6419
 
6379
6420
  // src/project/anchor-starter.ts