@basou/cli 0.15.0 → 0.17.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.js CHANGED
@@ -1804,13 +1804,15 @@ async function assertWorkspaceInitialized4(basouRoot) {
1804
1804
  import { createReadStream } from "fs";
1805
1805
  import { readdir, readFile as readFile2, rm, stat as stat2 } from "fs/promises";
1806
1806
  import { homedir as homedir4 } from "os";
1807
- import { basename as basename2, join as join4, resolve as resolve4 } from "path";
1807
+ import { basename as basename2, dirname, join as join4, resolve as resolve4 } from "path";
1808
1808
  import { createInterface } from "readline";
1809
1809
  import {
1810
+ AGENT_INFRA_DIRS,
1810
1811
  assertBasouRootSafe as assertBasouRootSafe6,
1811
1812
  basouPaths as basouPaths7,
1812
1813
  CLAUDE_IMPORT_SOURCE,
1813
1814
  CODEX_IMPORT_SOURCE,
1815
+ classifyFilesBySourceRoot,
1814
1816
  claudeTranscriptToImportPayload,
1815
1817
  codexRolloutToImportPayload,
1816
1818
  enumerateSessionDirs,
@@ -1908,7 +1910,15 @@ async function doRunImportClaudeCode(options, ctx) {
1908
1910
  }
1909
1911
  };
1910
1912
  });
1911
- await importDerivedSessions(paths, manifest, options, CLAUDE_IMPORT_SOURCE, candidates);
1913
+ await importDerivedSessions(
1914
+ paths,
1915
+ manifest,
1916
+ options,
1917
+ CLAUDE_IMPORT_SOURCE,
1918
+ candidates,
1919
+ projectPaths,
1920
+ hasDeclaredBoundary(options, manifest)
1921
+ );
1912
1922
  }
1913
1923
  async function doRunImportCodex(options, ctx) {
1914
1924
  assertSelector(options);
@@ -1933,7 +1943,18 @@ async function doRunImportCodex(options, ctx) {
1933
1943
  });
1934
1944
  }
1935
1945
  }));
1936
- await importDerivedSessions(paths, manifest, options, CODEX_IMPORT_SOURCE, candidates);
1946
+ await importDerivedSessions(
1947
+ paths,
1948
+ manifest,
1949
+ options,
1950
+ CODEX_IMPORT_SOURCE,
1951
+ candidates,
1952
+ projectPaths,
1953
+ hasDeclaredBoundary(options, manifest)
1954
+ );
1955
+ }
1956
+ function hasDeclaredBoundary(options, manifest) {
1957
+ return (options.project?.length ?? 0) > 0 || (manifest.import?.source_roots?.length ?? 0) > 0;
1937
1958
  }
1938
1959
  function assertSelector(options) {
1939
1960
  if (options.session !== void 0 && options.all === true) {
@@ -1951,9 +1972,25 @@ async function resolveImportTarget(ctx) {
1951
1972
  const manifest = await readManifest4(paths);
1952
1973
  return { repositoryRoot, paths, manifest };
1953
1974
  }
1954
- async function importDerivedSessions(paths, manifest, options, sourceKind, candidates) {
1975
+ async function importDerivedSessions(paths, manifest, options, sourceKind, candidates, projectPaths, boundaryDeclared) {
1955
1976
  const existingByExternalId = await loadExistingByExternalId(paths, sourceKind);
1956
1977
  const seenThisRun = /* @__PURE__ */ new Set();
1978
+ const crossProjectCheck = boundaryDeclared;
1979
+ const crossProject = [];
1980
+ const noteCrossProject = async (externalId, payload) => {
1981
+ if (!crossProjectCheck) return;
1982
+ try {
1983
+ const scope = await classifyFilesBySourceRoot({
1984
+ files: payload.session.related_files ?? [],
1985
+ workingDirectory: payload.session.working_directory,
1986
+ sourceRoots: projectPaths,
1987
+ masterRoot: dirname(paths.root),
1988
+ extraInRoot: AGENT_INFRA_DIRS
1989
+ });
1990
+ if (scope.outOfRoot.length > 0) crossProject.push({ externalId, outOfRoot: scope.outOfRoot });
1991
+ } catch {
1992
+ }
1993
+ };
1957
1994
  const results = [];
1958
1995
  const counts = {
1959
1996
  skippedNoAction: 0,
@@ -2010,6 +2047,7 @@ async function importDerivedSessions(paths, manifest, options, sourceKind, candi
2010
2047
  }
2011
2048
  counts.reimported++;
2012
2049
  seenThisRun.add(externalId);
2050
+ await noteCrossProject(externalId, payload2);
2013
2051
  continue;
2014
2052
  }
2015
2053
  const payload = validate(await toPayload());
@@ -2031,10 +2069,21 @@ async function importDerivedSessions(paths, manifest, options, sourceKind, candi
2031
2069
  results.push(result);
2032
2070
  seenThisRun.add(externalId);
2033
2071
  sanitizedPaths += result.pathSanitizeReport.relatedFiles + (result.pathSanitizeReport.workingDirectoryRewritten ? 1 : 0);
2072
+ await noteCrossProject(externalId, payload);
2034
2073
  }
2035
2074
  if (sanitizedPaths > 0) {
2036
2075
  console.error(`Imported sessions: ${sanitizedPaths} path(s) sanitized`);
2037
2076
  }
2077
+ if (crossProject.length > 0) {
2078
+ const PATH_SAMPLE = 5;
2079
+ for (const { externalId, outOfRoot } of crossProject) {
2080
+ const sample = outOfRoot.slice(0, PATH_SAMPLE).join(", ");
2081
+ const more = outOfRoot.length > PATH_SAMPLE ? ` (... +${outOfRoot.length - PATH_SAMPLE} more)` : "";
2082
+ console.error(
2083
+ `basou: session ${externalId} edited ${outOfRoot.length} file(s) outside this project's source_roots: ${sample}${more} \u2014 they may belong to another project.`
2084
+ );
2085
+ }
2086
+ }
2038
2087
  printImportResult(options, results, counts);
2039
2088
  }
2040
2089
  async function classifyReimport(priors, sourcePath, externalId, counts) {
@@ -2620,6 +2669,62 @@ import {
2620
2669
  writeMarkdownFile as writeMarkdownFile4
2621
2670
  } from "@basou/core";
2622
2671
 
2672
+ // src/lib/hosts-config.ts
2673
+ import { homedir as homedir5 } from "os";
2674
+ import { isAbsolute as isAbsolute2, join as join5, resolve as resolve6 } from "path";
2675
+ import { readYamlFile as readYamlFile4 } from "@basou/core";
2676
+ var DEFAULT_HOSTS_CONFIG_PATH = join5(homedir5(), ".basou", "hosts.yaml");
2677
+ function expandTilde2(p) {
2678
+ if (p === "~") return homedir5();
2679
+ if (p.startsWith("~/")) return join5(homedir5(), p.slice(2));
2680
+ return p;
2681
+ }
2682
+ function isRecord2(value) {
2683
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2684
+ }
2685
+ async function loadHostsConfig(configPath = DEFAULT_HOSTS_CONFIG_PATH) {
2686
+ let raw;
2687
+ try {
2688
+ raw = await readYamlFile4(configPath);
2689
+ } catch (error) {
2690
+ if (error instanceof Error && error.message === "YAML file not found") {
2691
+ return null;
2692
+ }
2693
+ if (error instanceof Error && error.message === "Failed to parse YAML content") {
2694
+ throw new Error("~/.basou/hosts.yaml is not valid YAML.");
2695
+ }
2696
+ throw error;
2697
+ }
2698
+ if (!isRecord2(raw) || !Array.isArray(raw.hosts)) {
2699
+ throw new Error("~/.basou/hosts.yaml must contain a 'hosts:' list.");
2700
+ }
2701
+ const seenPaths = /* @__PURE__ */ new Set();
2702
+ const seenLabels = /* @__PURE__ */ new Set();
2703
+ const result = [];
2704
+ for (const entry of raw.hosts) {
2705
+ if (!isRecord2(entry) || typeof entry.label !== "string" || entry.label.trim().length === 0) {
2706
+ throw new Error("Each host needs a non-empty string 'label'.");
2707
+ }
2708
+ const label = entry.label.trim();
2709
+ if (typeof entry.path !== "string" || entry.path.trim().length === 0) {
2710
+ throw new Error("Each host needs a non-empty string 'path'.");
2711
+ }
2712
+ const expanded = expandTilde2(entry.path.trim());
2713
+ if (!isAbsolute2(expanded)) {
2714
+ throw new Error("Host paths must be absolute (or start with '~').");
2715
+ }
2716
+ const abs = resolve6(expanded);
2717
+ if (seenPaths.has(abs)) continue;
2718
+ if (seenLabels.has(label)) {
2719
+ throw new Error(`Duplicate host label '${label}'; each host needs a distinct label.`);
2720
+ }
2721
+ seenPaths.add(abs);
2722
+ seenLabels.add(label);
2723
+ result.push({ label, path: abs });
2724
+ }
2725
+ return result;
2726
+ }
2727
+
2623
2728
  // src/lib/provenance-actions.ts
2624
2729
  import {
2625
2730
  readMarkdownFile as readMarkdownFile3,
@@ -2826,14 +2931,29 @@ async function doRunOrient(options, ctx) {
2826
2931
  if (ctx.claudeProjectsDir !== void 0) probeCtx.claudeProjectsDir = ctx.claudeProjectsDir;
2827
2932
  if (ctx.codexSessionsDir !== void 0) probeCtx.codexSessionsDir = ctx.codexSessionsDir;
2828
2933
  const staleness = await probeStaleness({ ctx: probeCtx, paths, nowIso });
2934
+ let federatedRoots = [];
2935
+ try {
2936
+ const hosts = await loadHostsConfig(ctx.hostsConfigPath);
2937
+ if (hosts !== null) {
2938
+ federatedRoots = hosts.map((h) => ({ paths: basouPaths9(h.path), host: h.label }));
2939
+ }
2940
+ } catch (error) {
2941
+ console.error(
2942
+ `basou: ignoring ~/.basou/hosts.yaml (${error instanceof Error ? error.message : String(error)}); showing local sessions only.`
2943
+ );
2944
+ }
2829
2945
  const result = await renderOrientation2({
2830
2946
  paths,
2831
2947
  nowIso,
2832
2948
  staleness,
2833
2949
  verbose: options.verbose === true,
2950
+ federatedRoots,
2834
2951
  onWarning: (w, sid) => printReplayWarning(w, sid),
2835
2952
  onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),
2836
- onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason)
2953
+ onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason),
2954
+ onHostUnavailable: (host, error) => console.error(
2955
+ `basou: host '${host}' mirror unreadable (${error instanceof Error ? error.message : String(error)}); skipping it.`
2956
+ )
2837
2957
  });
2838
2958
  await writeMarkdownFile4(paths.files.orientation, `${result.body}
2839
2959
  `);
@@ -2870,7 +2990,7 @@ import {
2870
2990
  unlinkSync,
2871
2991
  writeFileSync
2872
2992
  } from "fs";
2873
- import { basename as basename4, dirname, isAbsolute as isAbsolute2, join as join5, relative as relative2, resolve as resolve6 } from "path";
2993
+ import { basename as basename4, dirname as dirname2, isAbsolute as isAbsolute3, join as join6, relative as relative2, resolve as resolve7 } from "path";
2874
2994
  import {
2875
2995
  basouPaths as basouPaths10,
2876
2996
  GENERATED_END,
@@ -3122,14 +3242,14 @@ async function runProjectAdopt(options, ctx = {}) {
3122
3242
  }
3123
3243
  }
3124
3244
  function classifySourceRoot(repositoryRoot, declaredPath) {
3125
- const absolute = resolve6(repositoryRoot, declaredPath);
3245
+ const absolute = resolve7(repositoryRoot, declaredPath);
3126
3246
  let real;
3127
3247
  try {
3128
3248
  real = realpathSync(absolute);
3129
3249
  } catch {
3130
3250
  return { path: declaredPath, kind: "unresolved" };
3131
3251
  }
3132
- return { path: declaredPath, kind: existsSync(join5(real, ".git")) ? "repo" : "non-repo" };
3252
+ return { path: declaredPath, kind: existsSync(join6(real, ".git")) ? "repo" : "non-repo" };
3133
3253
  }
3134
3254
  async function doRunProjectAdopt(options, ctx) {
3135
3255
  const cwd = ctx.cwd ?? process.cwd();
@@ -3224,11 +3344,11 @@ async function gatherRepoWiring(repositoryRoot, entry) {
3224
3344
  };
3225
3345
  let real;
3226
3346
  try {
3227
- real = realpathSync(resolve6(repositoryRoot, entry.path));
3347
+ real = realpathSync(resolve7(repositoryRoot, entry.path));
3228
3348
  } catch {
3229
3349
  return { ...base, reachable: false, instructionFiles: [] };
3230
3350
  }
3231
- if (!existsSync(join5(real, ".git"))) {
3351
+ if (!existsSync(join6(real, ".git"))) {
3232
3352
  return { ...base, reachable: false, instructionFiles: [] };
3233
3353
  }
3234
3354
  try {
@@ -3236,7 +3356,7 @@ async function gatherRepoWiring(repositoryRoot, entry) {
3236
3356
  for (const name of INSTRUCTION_FILES) {
3237
3357
  let present = true;
3238
3358
  try {
3239
- lstatSync(join5(real, name));
3359
+ lstatSync(join6(real, name));
3240
3360
  } catch {
3241
3361
  present = false;
3242
3362
  }
@@ -3329,14 +3449,14 @@ function gatherRepoGitignore(repositoryRoot, entry) {
3329
3449
  };
3330
3450
  let real;
3331
3451
  try {
3332
- real = realpathSync(resolve6(repositoryRoot, entry.path));
3452
+ real = realpathSync(resolve7(repositoryRoot, entry.path));
3333
3453
  } catch {
3334
3454
  return { ...base, reachable: false, currentLines: [] };
3335
3455
  }
3336
- if (!existsSync(join5(real, ".git"))) {
3456
+ if (!existsSync(join6(real, ".git"))) {
3337
3457
  return { ...base, reachable: false, currentLines: [] };
3338
3458
  }
3339
- return { ...base, reachable: true, currentLines: readGitignoreLines(join5(real, ".gitignore")) };
3459
+ return { ...base, reachable: true, currentLines: readGitignoreLines(join6(real, ".gitignore")) };
3340
3460
  }
3341
3461
  function hasErrorCode(error) {
3342
3462
  return error instanceof Error && typeof error.code === "string";
@@ -3350,7 +3470,7 @@ function readGitignoreLines(file) {
3350
3470
  }
3351
3471
  }
3352
3472
  function applyGitignorePlan(repositoryRoot, plan) {
3353
- const file = join5(realpathSync(resolve6(repositoryRoot, plan.path)), ".gitignore");
3473
+ const file = join6(realpathSync(resolve7(repositoryRoot, plan.path)), ".gitignore");
3354
3474
  let existing = "";
3355
3475
  try {
3356
3476
  existing = readFileSync(file, "utf8");
@@ -3462,23 +3582,23 @@ function gatherRepoSymlinks(repositoryRoot, anchorReal, entry) {
3462
3582
  const base = { path: entry.path };
3463
3583
  let real;
3464
3584
  try {
3465
- real = realpathSync(resolve6(repositoryRoot, entry.path));
3585
+ real = realpathSync(resolve7(repositoryRoot, entry.path));
3466
3586
  } catch {
3467
3587
  return { ...base, isAnchor: false, reachable: false, canonicalPresent: false, files: [] };
3468
3588
  }
3469
3589
  if (real === anchorReal) {
3470
3590
  return { ...base, isAnchor: true, reachable: true, canonicalPresent: false, files: [] };
3471
3591
  }
3472
- if (!existsSync(join5(real, ".git"))) {
3592
+ if (!existsSync(join6(real, ".git"))) {
3473
3593
  return { ...base, isAnchor: false, reachable: false, canonicalPresent: false, files: [] };
3474
3594
  }
3475
- const canonicalFile = join5(anchorReal, "agents", basename4(real), CANONICAL_FILE);
3595
+ const canonicalFile = join6(anchorReal, "agents", basename4(real), CANONICAL_FILE);
3476
3596
  if (!existsSync(canonicalFile)) {
3477
3597
  return { ...base, isAnchor: false, reachable: true, canonicalPresent: false, files: [] };
3478
3598
  }
3479
3599
  const files = expectedSymlinkTargets(real, canonicalFile).map(
3480
3600
  (spec) => {
3481
- const { state, actualTarget } = inspectSymlink(join5(real, spec.name), spec.target);
3601
+ const { state, actualTarget } = inspectSymlink(join6(real, spec.name), spec.target);
3482
3602
  return {
3483
3603
  name: spec.name,
3484
3604
  expectedTarget: spec.target,
@@ -3499,7 +3619,7 @@ function gatherRepoSymlinks(repositoryRoot, anchorReal, entry) {
3499
3619
  function applySymlinkPlan(repositoryRoot, plan) {
3500
3620
  let real;
3501
3621
  try {
3502
- real = realpathSync(resolve6(repositoryRoot, plan.path));
3622
+ real = realpathSync(resolve7(repositoryRoot, plan.path));
3503
3623
  } catch (error) {
3504
3624
  const message = failureReason(error);
3505
3625
  return { created: [], failed: plan.toCreate.map((c) => ({ file: c.name, message })) };
@@ -3507,9 +3627,9 @@ function applySymlinkPlan(repositoryRoot, plan) {
3507
3627
  const created = [];
3508
3628
  const failed = [];
3509
3629
  for (const { name, target } of plan.toCreate) {
3510
- const filePath = join5(real, name);
3630
+ const filePath = join6(real, name);
3511
3631
  try {
3512
- mkdirSync(dirname(filePath), { recursive: true });
3632
+ mkdirSync(dirname2(filePath), { recursive: true });
3513
3633
  symlinkSync(target, filePath);
3514
3634
  created.push(name);
3515
3635
  } catch (error) {
@@ -3644,12 +3764,12 @@ async function runProjectWorkspace(options, ctx = {}) {
3644
3764
  }
3645
3765
  }
3646
3766
  function resolveViewDir(repositoryRoot, viewPath) {
3647
- const abs = resolve6(repositoryRoot, viewPath);
3767
+ const abs = resolve7(repositoryRoot, viewPath);
3648
3768
  try {
3649
3769
  return realpathSync(abs);
3650
3770
  } catch {
3651
3771
  try {
3652
- return join5(realpathSync(dirname(abs)), basename4(abs));
3772
+ return join6(realpathSync(dirname2(abs)), basename4(abs));
3653
3773
  } catch {
3654
3774
  return abs;
3655
3775
  }
@@ -3658,7 +3778,7 @@ function resolveViewDir(repositoryRoot, viewPath) {
3658
3778
  function gatherViewRepo(repositoryRoot, viewDir, entry) {
3659
3779
  let repoReal;
3660
3780
  try {
3661
- repoReal = realpathSync(resolve6(repositoryRoot, entry.path));
3781
+ repoReal = realpathSync(resolve7(repositoryRoot, entry.path));
3662
3782
  } catch {
3663
3783
  return { path: entry.path, reachable: false };
3664
3784
  }
@@ -3667,7 +3787,7 @@ function gatherViewRepo(repositoryRoot, viewDir, entry) {
3667
3787
  return { path: entry.path, reachable: false };
3668
3788
  }
3669
3789
  const linkName = basename4(repoReal);
3670
- const { state, actualTarget } = inspectSymlink(join5(viewDir, linkName), expectedTarget);
3790
+ const { state, actualTarget } = inspectSymlink(join6(viewDir, linkName), expectedTarget);
3671
3791
  return {
3672
3792
  path: entry.path,
3673
3793
  reachable: true,
@@ -3681,9 +3801,9 @@ function applyViewPlan(viewDir, toCreate) {
3681
3801
  const created = [];
3682
3802
  const failed = [];
3683
3803
  for (const { name, target } of toCreate) {
3684
- const filePath = join5(viewDir, name);
3804
+ const filePath = join6(viewDir, name);
3685
3805
  try {
3686
- mkdirSync(dirname(filePath), { recursive: true });
3806
+ mkdirSync(dirname2(filePath), { recursive: true });
3687
3807
  symlinkSync(target, filePath);
3688
3808
  created.push(name);
3689
3809
  } catch (error) {
@@ -3696,7 +3816,7 @@ var TOP_LEVEL_INSTRUCTION_FILES_LOWER = new Set(
3696
3816
  INSTRUCTION_FILES.filter((f) => !f.includes("/")).map((f) => f.toLowerCase())
3697
3817
  );
3698
3818
  function classifyViewLink(viewDir, name, rosterRealpaths) {
3699
- const filePath = join5(viewDir, name);
3819
+ const filePath = join6(viewDir, name);
3700
3820
  let isLink;
3701
3821
  try {
3702
3822
  isLink = lstatSync(filePath).isSymbolicLink();
@@ -3710,12 +3830,12 @@ function classifyViewLink(viewDir, name, rosterRealpaths) {
3710
3830
  } catch {
3711
3831
  return null;
3712
3832
  }
3713
- const resolved = isAbsolute2(target) ? target : resolve6(viewDir, target);
3833
+ const resolved = isAbsolute3(target) ? target : resolve7(viewDir, target);
3714
3834
  try {
3715
3835
  if (rosterRealpaths.has(realpathSync(resolved))) return null;
3716
3836
  } catch {
3717
3837
  }
3718
- if (isAbsolute2(target)) return { target, kind: "absolute" };
3838
+ if (isAbsolute3(target)) return { target, kind: "absolute" };
3719
3839
  let isDir = false;
3720
3840
  try {
3721
3841
  isDir = statSync(resolved).isDirectory();
@@ -3725,7 +3845,7 @@ function classifyViewLink(viewDir, name, rosterRealpaths) {
3725
3845
  if (!isDir) {
3726
3846
  return { target, kind: existsSync(resolved) ? "non-repo" : "broken" };
3727
3847
  }
3728
- return { target, kind: existsSync(join5(resolved, ".git")) ? "repo" : "non-repo" };
3848
+ return { target, kind: existsSync(join6(resolved, ".git")) ? "repo" : "non-repo" };
3729
3849
  }
3730
3850
  function gatherExistingViewLinks(viewDir, rosterRealpaths) {
3731
3851
  let names;
@@ -3750,7 +3870,7 @@ function pruneViewLinks(viewDir, toPrune, rosterRealpaths) {
3750
3870
  const pruned = [];
3751
3871
  const failed = [];
3752
3872
  for (const { name } of toPrune) {
3753
- const filePath = join5(viewDir, name);
3873
+ const filePath = join6(viewDir, name);
3754
3874
  const c = classifyViewLink(viewDir, name, rosterRealpaths);
3755
3875
  if (c === null || c.kind !== "repo") {
3756
3876
  failed.push({
@@ -3796,11 +3916,11 @@ async function doRunProjectWorkspace(options, ctx) {
3796
3916
  } else {
3797
3917
  const viewDir = resolveViewDir(repositoryRoot, viewPath);
3798
3918
  const facts = roster.map((entry) => gatherViewRepo(repositoryRoot, viewDir, entry));
3799
- const rosterNames = roster.map((entry) => basename4(resolve6(repositoryRoot, entry.path)));
3919
+ const rosterNames = roster.map((entry) => basename4(resolve7(repositoryRoot, entry.path)));
3800
3920
  const rosterRealpaths = /* @__PURE__ */ new Set();
3801
3921
  for (const entry of roster) {
3802
3922
  try {
3803
- rosterRealpaths.add(realpathSync(resolve6(repositoryRoot, entry.path)));
3923
+ rosterRealpaths.add(realpathSync(resolve7(repositoryRoot, entry.path)));
3804
3924
  } catch {
3805
3925
  }
3806
3926
  }
@@ -3961,10 +4081,10 @@ async function runProjectPreset(options, ctx = {}) {
3961
4081
  }
3962
4082
  }
3963
4083
  function canonicalFileFor(anchorReal, canonicalName) {
3964
- return join5(anchorReal, "agents", canonicalName, CANONICAL_FILE);
4084
+ return join6(anchorReal, "agents", canonicalName, CANONICAL_FILE);
3965
4085
  }
3966
4086
  function canonicalLabelFor(canonicalName) {
3967
- return join5("agents", canonicalName, CANONICAL_FILE);
4087
+ return join6("agents", canonicalName, CANONICAL_FILE);
3968
4088
  }
3969
4089
  async function gatherRepoPreset(repositoryRoot, anchorReal, entry) {
3970
4090
  const declared = {
@@ -3975,14 +4095,14 @@ async function gatherRepoPreset(repositoryRoot, anchorReal, entry) {
3975
4095
  };
3976
4096
  let real;
3977
4097
  try {
3978
- real = realpathSync(resolve6(repositoryRoot, entry.path));
4098
+ real = realpathSync(resolve7(repositoryRoot, entry.path));
3979
4099
  } catch {
3980
4100
  return { ...declared, isAnchor: false, reachable: false, canonicalPresent: false };
3981
4101
  }
3982
4102
  if (real === anchorReal) {
3983
4103
  return { ...declared, isAnchor: true, reachable: true, canonicalPresent: false };
3984
4104
  }
3985
- if (!existsSync(join5(real, ".git"))) {
4105
+ if (!existsSync(join6(real, ".git"))) {
3986
4106
  return { ...declared, isAnchor: false, reachable: false, canonicalPresent: false };
3987
4107
  }
3988
4108
  const canonicalName = basename4(real);
@@ -4030,7 +4150,7 @@ async function applyPresetPlan(anchorReal, plan) {
4030
4150
  isLink = false;
4031
4151
  }
4032
4152
  if (isLink) throw new Error(`Canonical is a symlink in ${label}`);
4033
- if (plan.action === "create") mkdirSync(dirname(file), { recursive: true });
4153
+ if (plan.action === "create") mkdirSync(dirname2(file), { recursive: true });
4034
4154
  const existing = await readMarkdownFile4(file);
4035
4155
  await writeMarkdownFile5(file, renderWithMarkers4(existing, plan.desiredBlock, label));
4036
4156
  }
@@ -4204,7 +4324,7 @@ function gatherArchiveTeardown(repositoryRoot, manifest, target) {
4204
4324
  };
4205
4325
  let real;
4206
4326
  try {
4207
- real = realpathSync(resolve6(repositoryRoot, target));
4327
+ real = realpathSync(resolve7(repositoryRoot, target));
4208
4328
  } catch {
4209
4329
  return empty;
4210
4330
  }
@@ -4213,24 +4333,24 @@ function gatherArchiveTeardown(repositoryRoot, manifest, target) {
4213
4333
  const instructionFiles = [];
4214
4334
  for (const name of INSTRUCTION_FILES) {
4215
4335
  try {
4216
- lstatSync(join5(real, name));
4336
+ lstatSync(join6(real, name));
4217
4337
  instructionFiles.push(name);
4218
4338
  } catch {
4219
4339
  }
4220
4340
  }
4221
4341
  let ignored;
4222
4342
  try {
4223
- ignored = new Set(readGitignoreLines(join5(real, ".gitignore")).map((l) => l.trim()));
4343
+ ignored = new Set(readGitignoreLines(join6(real, ".gitignore")).map((l) => l.trim()));
4224
4344
  } catch {
4225
4345
  ignored = /* @__PURE__ */ new Set();
4226
4346
  }
4227
4347
  const gitignorePatterns = INSTRUCTION_FILES.filter((p) => ignored.has(p) || ignored.has(`/${p}`));
4228
- const canonical2 = existsSync(join5(anchorReal, "agents", canonicalName, CANONICAL_FILE));
4348
+ const canonical2 = existsSync(join6(anchorReal, "agents", canonicalName, CANONICAL_FILE));
4229
4349
  let viewLink = false;
4230
4350
  const viewPath = manifest.workspace.view;
4231
4351
  if (viewPath !== void 0) {
4232
4352
  try {
4233
- lstatSync(join5(resolveViewDir(repositoryRoot, viewPath), canonicalName));
4353
+ lstatSync(join6(resolveViewDir(repositoryRoot, viewPath), canonicalName));
4234
4354
  viewLink = true;
4235
4355
  } catch {
4236
4356
  }
@@ -4272,7 +4392,7 @@ async function doRunProjectArchive(target, options, ctx) {
4272
4392
  const roster = manifest.repos ?? [];
4273
4393
  let targetIsAnchor = false;
4274
4394
  try {
4275
- targetIsAnchor = realpathSync(resolve6(repositoryRoot, target)) === realpathSync(repositoryRoot);
4395
+ targetIsAnchor = realpathSync(resolve7(repositoryRoot, target)) === realpathSync(repositoryRoot);
4276
4396
  } catch {
4277
4397
  targetIsAnchor = false;
4278
4398
  }
@@ -4392,12 +4512,12 @@ function gatherRenameWiring(repositoryRoot, manifest, oldBasename) {
4392
4512
  } catch {
4393
4513
  return { canonicalDirOld: false, viewLinkOld: false };
4394
4514
  }
4395
- const canonicalDirOld = existsSync(join5(anchorReal, "agents", oldBasename));
4515
+ const canonicalDirOld = existsSync(join6(anchorReal, "agents", oldBasename));
4396
4516
  let viewLinkOld = false;
4397
4517
  const viewPath = manifest.workspace.view;
4398
4518
  if (viewPath !== void 0) {
4399
4519
  try {
4400
- lstatSync(join5(resolveViewDir(repositoryRoot, viewPath), oldBasename));
4520
+ lstatSync(join6(resolveViewDir(repositoryRoot, viewPath), oldBasename));
4401
4521
  viewLinkOld = true;
4402
4522
  } catch {
4403
4523
  }
@@ -4423,7 +4543,7 @@ async function doRunProjectRename(oldPath, newPath, options, ctx) {
4423
4543
  const roster = manifest.repos ?? [];
4424
4544
  let oldIsAnchor = false;
4425
4545
  try {
4426
- oldIsAnchor = realpathSync(resolve6(repositoryRoot, oldPath)) === realpathSync(repositoryRoot);
4546
+ oldIsAnchor = realpathSync(resolve7(repositoryRoot, oldPath)) === realpathSync(repositoryRoot);
4427
4547
  } catch {
4428
4548
  oldIsAnchor = false;
4429
4549
  }
@@ -4546,7 +4666,7 @@ import {
4546
4666
  // src/lib/durable-write.ts
4547
4667
  import { randomUUID } from "crypto";
4548
4668
  import { lstat, open, rename, stat as stat3, unlink as unlink2 } from "fs/promises";
4549
- import { basename as basename5, dirname as dirname2, join as join6 } from "path";
4669
+ import { basename as basename5, dirname as dirname3, join as join7 } from "path";
4550
4670
  async function assertNotSymlink(targetPath) {
4551
4671
  try {
4552
4672
  const st = await lstat(targetPath);
@@ -4561,8 +4681,8 @@ async function assertNotSymlink(targetPath) {
4561
4681
  }
4562
4682
  }
4563
4683
  async function writeFileDurable(targetPath, content) {
4564
- const dir = dirname2(targetPath);
4565
- const tmpPath = join6(dir, `.${basename5(targetPath)}.tmp.${randomUUID()}`);
4684
+ const dir = dirname3(targetPath);
4685
+ const tmpPath = join7(dir, `.${basename5(targetPath)}.tmp.${randomUUID()}`);
4566
4686
  let mode = 420;
4567
4687
  try {
4568
4688
  mode = (await stat3(targetPath)).mode & 511;
@@ -4597,25 +4717,25 @@ async function writeFileDurable(targetPath, content) {
4597
4717
  }
4598
4718
 
4599
4719
  // src/lib/protocols-config.ts
4600
- import { homedir as homedir5 } from "os";
4601
- import { isAbsolute as isAbsolute3, join as join7, resolve as resolve7 } from "path";
4602
- import { readYamlFile as readYamlFile4 } from "@basou/core";
4603
- var DEFAULT_PROTOCOLS_CONFIG_PATH = join7(homedir5(), ".basou", "protocols.yaml");
4604
- var DEFAULT_TARGET_PATH = join7(homedir5(), ".claude", "CLAUDE.md");
4720
+ import { homedir as homedir6 } from "os";
4721
+ import { isAbsolute as isAbsolute4, join as join8, resolve as resolve8 } from "path";
4722
+ import { readYamlFile as readYamlFile5 } from "@basou/core";
4723
+ var DEFAULT_PROTOCOLS_CONFIG_PATH = join8(homedir6(), ".basou", "protocols.yaml");
4724
+ var DEFAULT_TARGET_PATH = join8(homedir6(), ".claude", "CLAUDE.md");
4605
4725
  var ALLOWED_TOP_KEYS = /* @__PURE__ */ new Set(["version", "protocols"]);
4606
4726
  var ALLOWED_ENTRY_KEYS = /* @__PURE__ */ new Set(["source", "title"]);
4607
- function expandTilde2(p) {
4608
- if (p === "~") return homedir5();
4609
- if (p.startsWith("~/")) return join7(homedir5(), p.slice(2));
4727
+ function expandTilde3(p) {
4728
+ if (p === "~") return homedir6();
4729
+ if (p.startsWith("~/")) return join8(homedir6(), p.slice(2));
4610
4730
  return p;
4611
4731
  }
4612
- function isRecord2(value) {
4732
+ function isRecord3(value) {
4613
4733
  return typeof value === "object" && value !== null && !Array.isArray(value);
4614
4734
  }
4615
4735
  async function loadProtocolsConfig(configPath = DEFAULT_PROTOCOLS_CONFIG_PATH) {
4616
4736
  let raw;
4617
4737
  try {
4618
- raw = await readYamlFile4(configPath);
4738
+ raw = await readYamlFile5(configPath);
4619
4739
  } catch (error) {
4620
4740
  if (error instanceof Error && error.message === "YAML file not found") {
4621
4741
  throw new Error(
@@ -4627,7 +4747,7 @@ async function loadProtocolsConfig(configPath = DEFAULT_PROTOCOLS_CONFIG_PATH) {
4627
4747
  }
4628
4748
  throw error;
4629
4749
  }
4630
- if (!isRecord2(raw) || !Array.isArray(raw.protocols)) {
4750
+ if (!isRecord3(raw) || !Array.isArray(raw.protocols)) {
4631
4751
  throw new Error("~/.basou/protocols.yaml must contain a 'protocols:' list.");
4632
4752
  }
4633
4753
  for (const key of Object.keys(raw)) {
@@ -4640,7 +4760,7 @@ async function loadProtocolsConfig(configPath = DEFAULT_PROTOCOLS_CONFIG_PATH) {
4640
4760
  const seen = /* @__PURE__ */ new Set();
4641
4761
  const result = [];
4642
4762
  for (const entry of raw.protocols) {
4643
- if (!isRecord2(entry)) {
4763
+ if (!isRecord3(entry)) {
4644
4764
  throw new Error("Each protocol entry must be a mapping with a 'source' key.");
4645
4765
  }
4646
4766
  for (const key of Object.keys(entry)) {
@@ -4654,11 +4774,11 @@ async function loadProtocolsConfig(configPath = DEFAULT_PROTOCOLS_CONFIG_PATH) {
4654
4774
  if (entry.title !== void 0 && (typeof entry.title !== "string" || entry.title.trim().length === 0)) {
4655
4775
  throw new Error("A protocol entry 'title' must be a non-empty string when present.");
4656
4776
  }
4657
- const expanded = expandTilde2(entry.source.trim());
4658
- if (!isAbsolute3(expanded)) {
4777
+ const expanded = expandTilde3(entry.source.trim());
4778
+ if (!isAbsolute4(expanded)) {
4659
4779
  throw new Error("Protocol 'source' paths must be absolute (or start with '~').");
4660
4780
  }
4661
- const abs = resolve7(expanded);
4781
+ const abs = resolve8(expanded);
4662
4782
  if (seen.has(abs)) {
4663
4783
  throw new Error("Duplicate protocol source (each source path may appear only once).");
4664
4784
  }
@@ -4858,16 +4978,16 @@ import { InvalidArgumentError as InvalidArgumentError3 } from "commander";
4858
4978
 
4859
4979
  // src/commands/refresh-watch.ts
4860
4980
  import { readdir as readdir2, stat as stat4 } from "fs/promises";
4861
- import { homedir as homedir6 } from "os";
4862
- import { join as join8 } from "path";
4981
+ import { homedir as homedir7 } from "os";
4982
+ import { join as join9 } from "path";
4863
4983
  import { findErrorCode as findErrorCode8 } from "@basou/core";
4864
4984
  var DEFAULT_WATCH_INTERVAL_SEC = 30;
4865
4985
  var MIN_WATCH_INTERVAL_SEC = 5;
4866
4986
  var MAX_WATCH_INTERVAL_SEC = 86400;
4867
4987
  function watchedRoots(ctx) {
4868
4988
  return [
4869
- ctx.codexSessionsDir ?? join8(homedir6(), ".codex", "sessions"),
4870
- ctx.claudeProjectsDir ?? join8(homedir6(), ".claude", "projects")
4989
+ ctx.codexSessionsDir ?? join9(homedir7(), ".codex", "sessions"),
4990
+ ctx.claudeProjectsDir ?? join9(homedir7(), ".claude", "projects")
4871
4991
  ];
4872
4992
  }
4873
4993
  async function scanSourceLogs(roots) {
@@ -4881,7 +5001,7 @@ async function scanSourceLogs(roots) {
4881
5001
  throw new Error("Failed to read a source log directory", { cause: error });
4882
5002
  }
4883
5003
  for (const entry of entries) {
4884
- const full = join8(dir, entry.name);
5004
+ const full = join9(dir, entry.name);
4885
5005
  if (entry.isDirectory()) {
4886
5006
  await walk(full);
4887
5007
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
@@ -4988,19 +5108,19 @@ function parseInterval(value) {
4988
5108
  return seconds;
4989
5109
  }
4990
5110
  function abortableSleep(ms, signal) {
4991
- return new Promise((resolve11) => {
5111
+ return new Promise((resolve12) => {
4992
5112
  if (signal.aborted) {
4993
- resolve11();
5113
+ resolve12();
4994
5114
  return;
4995
5115
  }
4996
5116
  let timer;
4997
5117
  const onAbort = () => {
4998
5118
  clearTimeout(timer);
4999
- resolve11();
5119
+ resolve12();
5000
5120
  };
5001
5121
  timer = setTimeout(() => {
5002
5122
  signal.removeEventListener("abort", onAbort);
5003
- resolve11();
5123
+ resolve12();
5004
5124
  }, ms);
5005
5125
  signal.addEventListener("abort", onAbort, { once: true });
5006
5126
  });
@@ -5199,7 +5319,7 @@ async function assertWorkspaceInitialized8(basouRoot) {
5199
5319
  }
5200
5320
 
5201
5321
  // src/commands/report.ts
5202
- import { isAbsolute as isAbsolute4, resolve as resolve8 } from "path";
5322
+ import { isAbsolute as isAbsolute5, resolve as resolve9 } from "path";
5203
5323
  import {
5204
5324
  assertBasouRootSafe as assertBasouRootSafe10,
5205
5325
  basouPaths as basouPaths12,
@@ -5239,7 +5359,7 @@ async function doRunReportGenerate(options, ctx) {
5239
5359
  onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason)
5240
5360
  });
5241
5361
  if (options.out !== void 0) {
5242
- const outPath = isAbsolute4(options.out) ? options.out : resolve8(cwd, options.out);
5362
+ const outPath = isAbsolute5(options.out) ? options.out : resolve9(cwd, options.out);
5243
5363
  await writeMarkdownFile6(outPath, result.body);
5244
5364
  const { sessions, decisions, tasks } = result.data;
5245
5365
  console.error(
@@ -5402,8 +5522,8 @@ function renderReviewGaps(summary) {
5402
5522
 
5403
5523
  // src/commands/run.ts
5404
5524
  import { mkdir as mkdir2 } from "fs/promises";
5405
- import { homedir as homedir7 } from "os";
5406
- import { join as join9 } from "path";
5525
+ import { homedir as homedir8 } from "os";
5526
+ import { join as join10 } from "path";
5407
5527
  import {
5408
5528
  acquireLock as acquireLock5,
5409
5529
  assertBasouRootSafe as assertBasouRootSafe11,
@@ -5417,7 +5537,7 @@ import {
5417
5537
  overwriteYamlFile as overwriteYamlFile2,
5418
5538
  prefixedUlid as prefixedUlid4,
5419
5539
  readManifest as readManifest7,
5420
- readYamlFile as readYamlFile5,
5540
+ readYamlFile as readYamlFile6,
5421
5541
  resolveClaudeCodeCommand,
5422
5542
  resolveRepositoryRoot as resolveRepositoryRoot9,
5423
5543
  SessionSchema as SessionSchema2,
@@ -5456,13 +5576,13 @@ async function runClaudeCode(args, options, ctx = {}) {
5456
5576
  await assertBasouRootSafe11(paths.root);
5457
5577
  const manifest = await readManifest7(paths);
5458
5578
  const sessionId = prefixedUlid4("ses");
5459
- const sessionDir = join9(paths.sessions, sessionId);
5579
+ const sessionDir = join10(paths.sessions, sessionId);
5460
5580
  await mkdir2(sessionDir, { recursive: true });
5461
5581
  const appendEvent = ctx.appendEvent ?? (async (_sessionDir, event) => {
5462
5582
  await coreAppendChainedEvent2(paths, sessionId, event);
5463
5583
  });
5464
5584
  const startedAt = now().toISOString();
5465
- const sessionYamlPath = join9(sessionDir, "session.yaml");
5585
+ const sessionYamlPath = join10(sessionDir, "session.yaml");
5466
5586
  const session = buildInitialSession2({
5467
5587
  id: sessionId,
5468
5588
  command,
@@ -5588,7 +5708,7 @@ async function runClaudeCode(args, options, ctx = {}) {
5588
5708
  const rawRelated = computeRelatedFiles(preSnapshot, postSnapshot, diff);
5589
5709
  const relatedFiles = sanitizeRelatedFiles(rawRelated, {
5590
5710
  workingDirectory: repoRoot,
5591
- homedir: homedir7()
5711
+ homedir: homedir8()
5592
5712
  }).sanitized;
5593
5713
  const finalStatus = decideFinalStatus2(result, signalReceived);
5594
5714
  await appendEvent(sessionDir, {
@@ -5732,7 +5852,7 @@ function buildInitialSession2(input) {
5732
5852
  source: { ...claudeCodeAdapterMetadata },
5733
5853
  started_at: input.startedAt,
5734
5854
  status: "initialized",
5735
- working_directory: sanitizeWorkingDirectory2(input.cwd, { homedir: homedir7() }),
5855
+ working_directory: sanitizeWorkingDirectory2(input.cwd, { homedir: homedir8() }),
5736
5856
  invocation: {
5737
5857
  command: input.command,
5738
5858
  args: [...input.args],
@@ -5744,7 +5864,7 @@ function buildInitialSession2(input) {
5744
5864
  };
5745
5865
  }
5746
5866
  async function mutateSessionYaml2(filePath, mutator) {
5747
- const raw = await readYamlFile5(filePath);
5867
+ const raw = await readYamlFile6(filePath);
5748
5868
  const parsed = SessionSchema2.parse(raw);
5749
5869
  mutator(parsed);
5750
5870
  const validated = SessionSchema2.parse(parsed);
@@ -5805,7 +5925,7 @@ async function resolveRepositoryRootForRun(cwd) {
5805
5925
 
5806
5926
  // src/commands/session.ts
5807
5927
  import { readFile as readFile4 } from "fs/promises";
5808
- import { basename as basename6, isAbsolute as isAbsolute5, join as join10, relative as relative3 } from "path";
5928
+ import { basename as basename6, isAbsolute as isAbsolute6, join as join11, relative as relative3 } from "path";
5809
5929
  import {
5810
5930
  acquireLock as acquireLock6,
5811
5931
  appendEventToExistingSession as appendEventToExistingSession3,
@@ -5817,7 +5937,7 @@ import {
5817
5937
  loadSessionEntries,
5818
5938
  readAllEvents,
5819
5939
  readManifest as readManifest8,
5820
- readYamlFile as readYamlFile6,
5940
+ readYamlFile as readYamlFile7,
5821
5941
  rechainSessionInPlace,
5822
5942
  resolveSessionId as resolveSessionId3,
5823
5943
  resolveTaskId,
@@ -5930,11 +6050,11 @@ async function doRunSessionShow(idInput, options, ctx) {
5930
6050
  const paths = basouPaths15(repositoryRoot);
5931
6051
  await assertWorkspaceInitialized10(paths.root);
5932
6052
  const sessionId = await resolveSessionId3(paths, idInput);
5933
- const sessionDir = join10(paths.sessions, sessionId);
5934
- const sessionYamlPath = join10(sessionDir, "session.yaml");
6053
+ const sessionDir = join11(paths.sessions, sessionId);
6054
+ const sessionYamlPath = join11(sessionDir, "session.yaml");
5935
6055
  let session;
5936
6056
  try {
5937
- const raw = await readYamlFile6(sessionYamlPath);
6057
+ const raw = await readYamlFile7(sessionYamlPath);
5938
6058
  session = SessionSchema3.parse(raw);
5939
6059
  } catch (error) {
5940
6060
  if (findErrorCode11(error, "ENOENT")) {
@@ -6052,7 +6172,7 @@ function formatSessionWork(session, events, now) {
6052
6172
  }
6053
6173
  function formatWorkingDir(workingDir, repositoryRoot, options) {
6054
6174
  if (options.fullPath === true) return workingDir;
6055
- if (!isAbsolute5(workingDir)) {
6175
+ if (!isAbsolute6(workingDir)) {
6056
6176
  if (workingDir === ".") return "<repository_root>";
6057
6177
  return workingDir;
6058
6178
  }
@@ -6669,7 +6789,7 @@ async function resolveRepositoryRootForStatus(cwd) {
6669
6789
 
6670
6790
  // src/commands/task.ts
6671
6791
  import { readFile as readFile5 } from "fs/promises";
6672
- import { join as join11 } from "path";
6792
+ import { join as join12 } from "path";
6673
6793
  import {
6674
6794
  archiveTask,
6675
6795
  assertBasouRootSafe as assertBasouRootSafe15,
@@ -6996,7 +7116,7 @@ async function doRunTaskShow(idInput, options, ctx) {
6996
7116
  const events = [];
6997
7117
  const linkedSessionIds = new Set(doc.task.task.linked_sessions);
6998
7118
  for (const s of sessions) {
6999
- const sessionDir = join11(paths.sessions, s.sessionId);
7119
+ const sessionDir = join12(paths.sessions, s.sessionId);
7000
7120
  try {
7001
7121
  for await (const ev of replayEvents2(sessionDir, {
7002
7122
  onWarning: (w) => printReplayWarning(w, s.sessionId)
@@ -7899,7 +8019,7 @@ async function assertWorkspaceInitialized13(basouRoot) {
7899
8019
  // src/commands/view.ts
7900
8020
  import { spawn } from "child_process";
7901
8021
  import { createHash } from "crypto";
7902
- import { basename as basename7, resolve as resolve10 } from "path";
8022
+ import { basename as basename7, resolve as resolve11 } from "path";
7903
8023
  import {
7904
8024
  assertBasouRootSafe as assertBasouRootSafe17,
7905
8025
  basouPaths as basouPaths20,
@@ -7912,7 +8032,7 @@ import { InvalidArgumentError as InvalidArgumentError7 } from "commander";
7912
8032
  // src/lib/portfolio-safety.ts
7913
8033
  import { execFile } from "child_process";
7914
8034
  import { lstat as lstat2, realpath as realpath2 } from "fs/promises";
7915
- import { isAbsolute as isAbsolute6, join as join12, relative as relative4, resolve as resolve9 } from "path";
8035
+ import { isAbsolute as isAbsolute7, join as join13, relative as relative4, resolve as resolve10 } from "path";
7916
8036
  import { promisify } from "util";
7917
8037
  import { readManifest as readManifest11 } from "@basou/core";
7918
8038
  var execFileAsync = promisify(execFile);
@@ -7923,12 +8043,12 @@ async function canonical(p) {
7923
8043
  try {
7924
8044
  return await realpath2(p);
7925
8045
  } catch {
7926
- return resolve9(p);
8046
+ return resolve10(p);
7927
8047
  }
7928
8048
  }
7929
8049
  function isInside(child, parent) {
7930
8050
  const rel = relative4(parent, child);
7931
- return rel === "" || !rel.startsWith("..") && !isAbsolute6(rel);
8051
+ return rel === "" || !rel.startsWith("..") && !isAbsolute7(rel);
7932
8052
  }
7933
8053
  function isBasouPath(p) {
7934
8054
  return p === ".basou" || p.startsWith(".basou/") || p.includes("/.basou/") || p.endsWith("/.basou");
@@ -7936,7 +8056,7 @@ function isBasouPath(p) {
7936
8056
  async function inspectRepo(repoPath) {
7937
8057
  let hasEntry = false;
7938
8058
  try {
7939
- await lstat2(join12(repoPath, ".basou"));
8059
+ await lstat2(join13(repoPath, ".basou"));
7940
8060
  hasEntry = true;
7941
8061
  } catch (error) {
7942
8062
  if (errorCode(error) !== "ENOENT") {
@@ -7985,7 +8105,7 @@ async function checkPortfolioSafety(workspaces) {
7985
8105
  }
7986
8106
  const monitored = /* @__PURE__ */ new Map();
7987
8107
  for (const root of sourceRoots) {
7988
- const display = resolve9(ws.repoRoot, root);
8108
+ const display = resolve10(ws.repoRoot, root);
7989
8109
  const real = await canonical(display);
7990
8110
  if (real !== wsReal) monitored.set(real, display);
7991
8111
  }
@@ -8037,7 +8157,7 @@ function formatSafetyReport(result) {
8037
8157
 
8038
8158
  // src/lib/view-server.ts
8039
8159
  import { createServer } from "http";
8040
- import { join as join13 } from "path";
8160
+ import { join as join14 } from "path";
8041
8161
  import {
8042
8162
  computeWorkStats as computeWorkStats2,
8043
8163
  enumerateApprovals as enumerateApprovals2,
@@ -8694,7 +8814,7 @@ function startViewServer(opts) {
8694
8814
  };
8695
8815
  let boundPort = port;
8696
8816
  const getPort = () => boundPort;
8697
- return new Promise((resolve11, reject) => {
8817
+ return new Promise((resolve12, reject) => {
8698
8818
  const server = createServer((req, res) => {
8699
8819
  handleRequest(req, res, deps, getPort, runExclusive).catch((error) => {
8700
8820
  sendError(res, error instanceof HttpError ? error.status : 500, pathlessMessage(error));
@@ -8705,7 +8825,7 @@ function startViewServer(opts) {
8705
8825
  const address = server.address();
8706
8826
  boundPort = isAddressInfo(address) ? address.port : port;
8707
8827
  server.off("error", reject);
8708
- resolve11({
8828
+ resolve12({
8709
8829
  url: `http://${host}:${boundPort}`,
8710
8830
  port: boundPort,
8711
8831
  close: () => closeServer(server)
@@ -8717,8 +8837,8 @@ function isAddressInfo(value) {
8717
8837
  return value !== null && typeof value === "object";
8718
8838
  }
8719
8839
  function closeServer(server) {
8720
- return new Promise((resolve11) => {
8721
- server.close(() => resolve11());
8840
+ return new Promise((resolve12) => {
8841
+ server.close(() => resolve12());
8722
8842
  server.closeAllConnections();
8723
8843
  });
8724
8844
  }
@@ -8992,7 +9112,7 @@ async function sessionDetail(ws, sessionId) {
8992
9112
  throw error;
8993
9113
  }
8994
9114
  try {
8995
- const events = await readAllEvents2(join13(ws.paths.sessions, sessionId));
9115
+ const events = await readAllEvents2(join14(ws.paths.sessions, sessionId));
8996
9116
  return { session, events };
8997
9117
  } catch {
8998
9118
  return { session, events: [], degraded: true };
@@ -9212,12 +9332,12 @@ async function buildSingleDeps(ctx, cwd) {
9212
9332
  return { workspaces: [entry], mode: "single", nowProvider: nowProviderOf(ctx) };
9213
9333
  }
9214
9334
  async function buildPortfolioDeps(workspaceFlags, ctx, cwd) {
9215
- const specs = workspaceFlags.length > 0 ? workspaceFlags.map((p) => ({ path: resolve10(cwd, p) })) : await loadPortfolioConfig(ctx.portfolioConfigPath);
9335
+ const specs = workspaceFlags.length > 0 ? workspaceFlags.map((p) => ({ path: resolve11(cwd, p) })) : await loadPortfolioConfig(ctx.portfolioConfigPath);
9216
9336
  const entries = [];
9217
9337
  const seenPath = /* @__PURE__ */ new Set();
9218
9338
  const seenKey = /* @__PURE__ */ new Set();
9219
9339
  for (const spec of specs) {
9220
- const repoRoot = resolve10(spec.path);
9340
+ const repoRoot = resolve11(spec.path);
9221
9341
  if (seenPath.has(repoRoot)) continue;
9222
9342
  seenPath.add(repoRoot);
9223
9343
  const entry = await buildWorkspaceEntry(repoRoot, ctx, spec.label);
@@ -9289,7 +9409,7 @@ function openInBrowser(url, override) {
9289
9409
  }
9290
9410
  }
9291
9411
  function waitForShutdown(signal) {
9292
- return new Promise((resolve11) => {
9412
+ return new Promise((resolve12) => {
9293
9413
  const cleanup = () => {
9294
9414
  process.off("SIGINT", onSignal);
9295
9415
  process.off("SIGTERM", onSignal);
@@ -9297,18 +9417,18 @@ function waitForShutdown(signal) {
9297
9417
  };
9298
9418
  const onSignal = () => {
9299
9419
  cleanup();
9300
- resolve11();
9420
+ resolve12();
9301
9421
  };
9302
9422
  const onAbort = () => {
9303
9423
  cleanup();
9304
- resolve11();
9424
+ resolve12();
9305
9425
  };
9306
9426
  process.on("SIGINT", onSignal);
9307
9427
  process.on("SIGTERM", onSignal);
9308
9428
  if (signal !== void 0) {
9309
9429
  if (signal.aborted) {
9310
9430
  cleanup();
9311
- resolve11();
9431
+ resolve12();
9312
9432
  return;
9313
9433
  }
9314
9434
  signal.addEventListener("abort", onAbort);