@astrale-os/cli 0.6.2-alpha.0 → 0.7.0-alpha.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/astrale.js CHANGED
@@ -2576,7 +2576,7 @@ var package_default;
2576
2576
  var init_package = __esm(() => {
2577
2577
  package_default = {
2578
2578
  name: "@astrale-os/cli",
2579
- version: "0.6.2-alpha.0",
2579
+ version: "0.7.0-alpha.0",
2580
2580
  description: "Astrale CLI — connect to existing Astrale kernels",
2581
2581
  keywords: [
2582
2582
  "astrale",
@@ -65902,6 +65902,12 @@ var init_session = __esm(() => {
65902
65902
  function adminInstanceMethod(method) {
65903
65903
  return `${ADMIN_INSTANCE}:${method}`;
65904
65904
  }
65905
+ async function callOwnedInstances(client) {
65906
+ return await client.call(adminInstanceMethod("listMine"), {});
65907
+ }
65908
+ function findOwnedInstance(instances, identifier) {
65909
+ return instances.find((instance) => instance.id === identifier || instance.slug === identifier);
65910
+ }
65905
65911
  function formatInstanceLocation(info2) {
65906
65912
  return [info2.state && info2.state !== "ready" ? info2.state : undefined, info2.region, info2.hostId].filter(Boolean).join(" · ");
65907
65913
  }
@@ -66019,6 +66025,8 @@ function adminTargetToInstance(target) {
66019
66025
  };
66020
66026
  }
66021
66027
  function isManagedInstanceNotFound(error52) {
66028
+ if (error52 instanceof AstraleError && error52.code === "INSTANCE_NOT_FOUND")
66029
+ return true;
66022
66030
  if (!(error52 instanceof Error))
66023
66031
  return false;
66024
66032
  if (error52.name === "NotFoundError")
@@ -66384,13 +66392,13 @@ var init_ca_fetch = () => {};
66384
66392
  // src/kernel/client.ts
66385
66393
  async function resolveKernelTarget(opts, config2) {
66386
66394
  if (opts.url && !opts.instance) {
66387
- const resolved2 = await resolveInstanceTarget({ source: "url", url: opts.url }, { config: config2, admin: adminLookupOpts(opts) });
66395
+ const resolved2 = await resolveInstanceTarget({ source: "url", url: opts.url }, { config: config2 });
66388
66396
  return resolvedToKernelTarget(resolved2);
66389
66397
  }
66390
66398
  const resolved = await resolveInstanceTarget(opts.instance ? { source: "name", name: opts.instance } : { source: "active" }, {
66391
66399
  config: config2,
66392
- admin: adminLookupOpts(opts),
66393
- managed: (slug) => lookupManagedInstance(slug, opts)
66400
+ admin: {},
66401
+ managed: (slug) => lookupImplicitOwnedInstance(slug, opts)
66394
66402
  });
66395
66403
  return resolvedToKernelTarget(resolved, opts.url);
66396
66404
  }
@@ -66399,16 +66407,22 @@ async function withKernelClient(opts, fn2) {
66399
66407
  const target = await resolveKernelTarget(opts, config2);
66400
66408
  return withResolvedKernelClient(opts, config2, target, fn2);
66401
66409
  }
66402
- async function lookupManagedInstance(slug, opts) {
66403
- return await withAdminKernelClient(adminLookupOpts(opts), async (ctx) => await ctx.client.call(adminInstanceMethod("info"), { id: slug }));
66410
+ async function listOwnedInstances(opts) {
66411
+ return await withAdminKernelClient(opts, async (ctx) => callOwnedInstances(ctx.client));
66404
66412
  }
66405
- function adminLookupOpts(opts) {
66406
- return {
66407
- as: opts.as,
66408
- creds: opts.creds,
66409
- timeout: opts.timeout,
66410
- debug: opts.debug
66411
- };
66413
+ async function lookupOwnedInstance(slug, opts) {
66414
+ const instance = findOwnedInstance(await listOwnedInstances(opts), slug);
66415
+ if (instance)
66416
+ return instance;
66417
+ throw new AstraleError("INSTANCE_NOT_FOUND", `No owned instance matches "${slug}".`);
66418
+ }
66419
+ async function lookupImplicitOwnedInstance(slug, targetOpts, deps = {
66420
+ lookupOwned: lookupOwnedInstance
66421
+ }) {
66422
+ return await deps.lookupOwned(slug, {
66423
+ timeout: targetOpts.timeout,
66424
+ debug: targetOpts.debug
66425
+ });
66412
66426
  }
66413
66427
  function resolvedToKernelTarget(target, urlOverride) {
66414
66428
  return {
@@ -66564,30 +66578,97 @@ var init_provision_instance = __esm(() => {
66564
66578
  });
66565
66579
 
66566
66580
  // src/setup/steps/instance.ts
66567
- async function fetchManaged(ctx) {
66568
- try {
66569
- return await withSpinner("Checking for existing instances", !ctx.machine, () => withAdminKernelClient(ctx.opts, async (client) => await client.client.call(adminInstanceMethod("list"), {})));
66570
- } catch {
66571
- return [];
66572
- }
66573
- }
66574
66581
  function hero(slug, kernelUrl) {
66575
66582
  console.log("");
66576
66583
  console.log(renderInstanceHero(slug, guiOrigin(kernelUrl)));
66577
66584
  console.log("");
66578
66585
  }
66579
- async function adopt(info2) {
66580
- const { repointedFrom } = await upsertManagedBookmark(info2.slug, info2.slug, info2.url);
66581
- await setActive(info2.slug);
66586
+ async function adoptOwnedInstance(info2, deps = {
66587
+ upsert: upsertManagedBookmark,
66588
+ activate: setActive
66589
+ }) {
66590
+ const { repointedFrom } = await deps.upsert(info2.slug, info2.slug, info2.url, info2.organizationId);
66591
+ await deps.activate(info2.slug);
66582
66592
  if (repointedFrom) {
66583
66593
  log.warn(`Bookmark "${info2.slug}" repointed: ${repointedFrom} → ${normalizeInstanceKernelUrl(info2.url)}`);
66584
66594
  }
66585
66595
  log.success(`Active instance: ${info2.slug}`);
66586
66596
  hero(info2.slug, info2.url);
66587
66597
  }
66598
+ function defaultDependencies(ctx) {
66599
+ return {
66600
+ fetchOwned: (setupCtx) => withSpinner("Checking for existing instances", !setupCtx.machine, () => listOwnedInstances(setupCtx.opts)),
66601
+ adopt: adoptOwnedInstance,
66602
+ selectReady: (instances) => selectFrom("No active instance. Pick one:", instances.map((info2) => ({
66603
+ label: `${info2.slug} ${source_default.dim(guiOrigin(info2.url))}`,
66604
+ value: info2
66605
+ }))),
66606
+ confirmCreate: () => confirmDefaultYes("No instances yet. Provision your first one now?"),
66607
+ promptSlug: () => ctx.slug ? Promise.resolve(ctx.slug) : promptText("Pick a slug for your instance", { validate: slugError }),
66608
+ provision: (slug) => provisionInstance(slug, ctx.opts)
66609
+ };
66610
+ }
66611
+ async function ensureOwnedInstance(ctx, deps = defaultDependencies(ctx)) {
66612
+ let owned;
66613
+ try {
66614
+ owned = await deps.fetchOwned(ctx);
66615
+ } catch (cause) {
66616
+ const detail = cause instanceof Error ? cause.message : String(cause);
66617
+ throw new AstraleError("INSTANCE_DISCOVERY_FAILED", `Could not check your Astrale instances: ${detail}`, "No instance was created. Check `astrale admin status`, then rerun `astrale setup`.");
66618
+ }
66619
+ const ready = owned.filter((info2) => info2.state === "ready");
66620
+ if (ready.length === 1) {
66621
+ await deps.adopt(ready[0]);
66622
+ return "fixed";
66623
+ }
66624
+ if (ready.length > 1) {
66625
+ const choice = await deps.selectReady(ready);
66626
+ if (choice === null) {
66627
+ log.dim(" Skipped — no active instance set.");
66628
+ return "skipped";
66629
+ }
66630
+ await deps.adopt(choice);
66631
+ return "fixed";
66632
+ }
66633
+ if (owned.length > 0) {
66634
+ reportNotReady(owned);
66635
+ return "skipped";
66636
+ }
66637
+ if (!await deps.confirmCreate()) {
66638
+ log.dim(" Skipped — create one later: astrale instance create <slug>");
66639
+ return "skipped";
66640
+ }
66641
+ const slug = await deps.promptSlug();
66642
+ if (!slug) {
66643
+ log.dim(" Skipped — no slug given.");
66644
+ return "skipped";
66645
+ }
66646
+ const { created, selectionError } = await deps.provision(slug);
66647
+ if (selectionError) {
66648
+ const detail = selectionError instanceof Error ? selectionError.message : String(selectionError);
66649
+ throw new AstraleError("INSTANCE_SELECTION_FAILED", `Instance "${slug}" was provisioned, but the CLI could not select it: ${detail}`, `Fix local CLI storage, then run \`astrale instance use ${slug}\`.`);
66650
+ }
66651
+ hero(slug, created.url);
66652
+ return "fixed";
66653
+ }
66654
+ function reportNotReady(instances) {
66655
+ log.warn(`${instances.length === 1 ? "Your instance is" : "Your instances are"} not ready; setup will not create another.`);
66656
+ for (const info2 of instances) {
66657
+ const phase = info2.phase && info2.phase !== info2.state ? ` (${info2.phase})` : "";
66658
+ log.dim(` ${info2.slug}: ${info2.state}${phase} · astrale instance status ${info2.slug}`);
66659
+ if (info2.error)
66660
+ log.dim(` ${info2.error}`);
66661
+ }
66662
+ if (instances.some((info2) => info2.state === "failed")) {
66663
+ log.dim(" Inspect the failure, then deliberately delete/recreate it with `astrale instance` commands.");
66664
+ } else {
66665
+ log.dim(" Wait for provisioning to finish, then rerun `astrale setup`.");
66666
+ }
66667
+ }
66588
66668
  var instanceStep;
66589
66669
  var init_instance2 = __esm(() => {
66590
66670
  init_source();
66671
+ init_errors3();
66591
66672
  init_client2();
66592
66673
  init_instance();
66593
66674
  init_local_status();
@@ -66617,38 +66698,7 @@ var init_instance2 = __esm(() => {
66617
66698
  log.success(`Active instance: ${instance.active} (${guiOrigin(instance.url)})`);
66618
66699
  return "unchanged";
66619
66700
  }
66620
- const managed = await fetchManaged(ctx);
66621
- if (managed.length > 0) {
66622
- const choice = await selectFrom("No active instance. Pick one or create a new instance:", [
66623
- ...managed.map((info2) => ({
66624
- label: `${info2.slug} ${source_default.dim(guiOrigin(info2.url))}`,
66625
- value: info2
66626
- })),
66627
- { label: source_default.cyan("➕ Create a new instance"), value: "create" }
66628
- ]);
66629
- if (choice === null) {
66630
- log.dim(" Skipped — no active instance set.");
66631
- return "skipped";
66632
- }
66633
- if (choice !== "create") {
66634
- await adopt(choice);
66635
- return "fixed";
66636
- }
66637
- } else {
66638
- const yes = await confirmDefaultYes("No instances yet. Provision your first one now?");
66639
- if (!yes) {
66640
- log.dim(" Skipped — create one later: astrale instance create <slug>");
66641
- return "skipped";
66642
- }
66643
- }
66644
- const slug = ctx.slug ?? await promptText("Pick a slug for your instance", { validate: slugError });
66645
- if (!slug) {
66646
- log.dim(" Skipped — no slug given.");
66647
- return "skipped";
66648
- }
66649
- const { created } = await provisionInstance(slug, ctx.opts);
66650
- hero(slug, created.url);
66651
- return "fixed";
66701
+ return ensureOwnedInstance(ctx);
66652
66702
  }
66653
66703
  };
66654
66704
  });
@@ -67027,7 +67077,7 @@ async function resolveUseTarget2(name, opts) {
67027
67077
  return await resolveInstance(chosen.key);
67028
67078
  }
67029
67079
  assertManagedReady(chosen.info);
67030
- const { repointedFrom } = await upsertManagedBookmark(chosen.key, chosen.info.slug, chosen.url);
67080
+ const { repointedFrom } = await upsertManagedBookmark(chosen.key, chosen.info.slug, chosen.url, chosen.info.organizationId);
67031
67081
  if (repointedFrom) {
67032
67082
  log.warn(`Bookmark "${chosen.key}" repointed: ${repointedFrom} → ${chosen.url}`);
67033
67083
  }
@@ -67040,16 +67090,16 @@ async function fetchManagedInstances(name, opts) {
67040
67090
  return [];
67041
67091
  }
67042
67092
  try {
67043
- return await withAdminKernelClient(opts, async (ctx) => await ctx.client.call(adminInstanceMethod("list"), {}));
67093
+ return await listOwnedInstances(opts);
67044
67094
  } catch {
67045
67095
  return [];
67046
67096
  }
67047
67097
  }
67048
67098
  function assertManagedReady(info2) {
67049
- if (!info2.state || info2.state === "ready")
67099
+ if (info2.state === "ready")
67050
67100
  return;
67051
67101
  const detail = info2.phase && info2.phase !== info2.state ? ` (${info2.phase})` : "";
67052
- throw new AstraleError("INSTANCE_NOT_READY", `Instance "${info2.slug}" is ${info2.state}${detail}; it cannot be selected yet.`, info2.error ?? undefined);
67102
+ throw new AstraleError("INSTANCE_NOT_READY", `Instance "${info2.slug}" is ${info2.state}${detail}; it cannot be selected yet.`, info2.error ?? `Run: astrale instance status ${info2.slug}`);
67053
67103
  }
67054
67104
  async function pickCandidate(name, candidates) {
67055
67105
  return selectFrom(`Multiple instances match "${name}":`, candidates.map((candidate) => ({
@@ -68002,8 +68052,8 @@ async function buildSelfContext(opts) {
68002
68052
  } else {
68003
68053
  const resolved = await resolveInstanceTarget(opts.instance ? { source: "name", name: opts.instance } : { source: "active" }, {
68004
68054
  config: config2,
68005
- admin: adminLookupOpts2(opts),
68006
- managed: (instanceSlug) => lookupManagedInstance2(instanceSlug, opts)
68055
+ admin: {},
68056
+ managed: (instanceSlug) => lookupImplicitOwnedInstance(instanceSlug, opts)
68007
68057
  });
68008
68058
  slug = resolved.name;
68009
68059
  defaultIdentity = resolved.defaultIdentity;
@@ -68034,17 +68084,6 @@ async function buildSelfContext(opts) {
68034
68084
  }
68035
68085
  return { identity: identity4, instanceSlug: slug, credsJwt: opts.creds, instanceSigned, idpSubject };
68036
68086
  }
68037
- function adminLookupOpts2(opts) {
68038
- return {
68039
- as: opts.as,
68040
- creds: opts.creds,
68041
- timeout: opts.timeout,
68042
- debug: opts.debug
68043
- };
68044
- }
68045
- async function lookupManagedInstance2(slug, opts) {
68046
- return await withAdminKernelClient(adminLookupOpts2(opts), async (ctx) => await ctx.client.call(adminInstanceMethod("info"), { id: slug }));
68047
- }
68048
68087
  async function withSelfHint(fn2, meta3) {
68049
68088
  if (!meta3)
68050
68089
  return fn2();
@@ -68528,7 +68567,7 @@ Examples:
68528
68567
  $ astrale call /:host.astrale.ai:class.KernelInstance:list
68529
68568
  $ astrale call /:blog.acme.com:class.Author:list limit=10
68530
68569
  $ astrale call '@self::deactivate'
68531
- $ astrale call /:shell.astrale.ai:class.Application:available --json
68570
+ $ astrale call /:shell.astrale.ai:function.search-domains --json
68532
68571
  `,
68533
68572
  arguments: [
68534
68573
  {
@@ -69727,67 +69766,6 @@ async function findFreePort(start, span2 = 20, host = LOOPBACK) {
69727
69766
  var LOOPBACK = "127.0.0.1";
69728
69767
  var init_port = () => {};
69729
69768
 
69730
- // src/lib/view/resolve.ts
69731
- function parseViewSpec(spec) {
69732
- if (VIEW_PATH_RE.test(spec))
69733
- return { kind: "view", path: spec };
69734
- if (spec.startsWith("/") || spec.startsWith("@"))
69735
- return { kind: "target", path: spec };
69736
- throw new AstraleError("INVALID_ARGUMENT", `"${spec}" is neither a ViewPath (/:origin:view.slug) nor a node path (/… or @id)`);
69737
- }
69738
- async function resolveViewCandidates(ctx, nodePath) {
69739
- const result = await ctx.client.call(VIEW_RESOLVE_PATH, { node: nodePath });
69740
- if (!Array.isArray(result)) {
69741
- throw new AstraleError("UNEXPECTED_RESULT", `View:resolve returned a non-array for ${nodePath}`);
69742
- }
69743
- return result;
69744
- }
69745
- function candidateSlug(candidate) {
69746
- const fromPath = candidate.path?.split("/").pop() ?? "";
69747
- return candidate.name ?? fromPath;
69748
- }
69749
- function pickCandidate2(candidates, nodePath, slug) {
69750
- if (slug) {
69751
- const match = candidates.find((c) => candidateSlug(c) === slug || c.path.endsWith(`/${slug}`));
69752
- if (!match) {
69753
- throw new AstraleError("VIEW_NOT_FOUND", `No view "${slug}" on ${nodePath} — available: ${candidates.map(candidateSlug).join(", ") || "(none)"}`);
69754
- }
69755
- return match;
69756
- }
69757
- if (candidates.length === 0) {
69758
- throw new AstraleError("VIEW_NOT_FOUND", `No views resolve on ${nodePath}`);
69759
- }
69760
- if (candidates.length === 1)
69761
- return candidates[0];
69762
- return "ambiguous";
69763
- }
69764
- function applyViewUrlOverride(resolvedUrl, override) {
69765
- const parsed = parseUrl(override);
69766
- if (parsed.pathname !== "/")
69767
- return parsed.toString();
69768
- const original = parseUrl(resolvedUrl);
69769
- return new URL(original.pathname + original.search + original.hash, parsed.origin).toString();
69770
- }
69771
- function rewriteLocalViewUrl(url2) {
69772
- const parsed = parseUrl(url2);
69773
- if (parsed.hostname !== "host.docker.internal")
69774
- return url2;
69775
- parsed.hostname = "127.0.0.1";
69776
- return parsed.toString();
69777
- }
69778
- function parseUrl(raw) {
69779
- try {
69780
- return new URL(raw);
69781
- } catch {
69782
- throw new AstraleError("INVALID_URL", `Not a valid URL: ${raw}`);
69783
- }
69784
- }
69785
- var VIEW_RESOLVE_PATH = "/:kernel.astrale.ai:class.View:resolve", VIEW_PATH_RE;
69786
- var init_resolve7 = __esm(() => {
69787
- init_errors3();
69788
- VIEW_PATH_RE = /^\/:[^\s/:@]+:view\.[a-z][a-z0-9-]*$/;
69789
- });
69790
-
69791
69769
  // src/lib/view/session.ts
69792
69770
  import { mkdir as mkdir9, readdir as readdir2, readFile as readFile10, rm as rm2, writeFile as writeFile8 } from "node:fs/promises";
69793
69771
  import { join as join10 } from "node:path";
@@ -69858,11 +69836,84 @@ var init_session2 = __esm(() => {
69858
69836
  VIEW_DIR = join10(paths.home, "view");
69859
69837
  });
69860
69838
 
69839
+ // src/lib/view/port-allocation.ts
69840
+ import { join as join11 } from "node:path";
69841
+ function withViewPortAllocationLock(fn2, lockPath = VIEW_PORT_LOCK) {
69842
+ return withFileLock(lockPath, fn2);
69843
+ }
69844
+ var VIEW_PORT_LOCK;
69845
+ var init_port_allocation = __esm(() => {
69846
+ init_fs_atomic();
69847
+ init_session2();
69848
+ VIEW_PORT_LOCK = join11(VIEW_DIR, "ports.lock");
69849
+ });
69850
+
69851
+ // src/lib/view/resolve.ts
69852
+ function parseViewSpec(spec) {
69853
+ if (VIEW_PATH_RE.test(spec))
69854
+ return { kind: "view", path: spec };
69855
+ if (spec.startsWith("/") || spec.startsWith("@"))
69856
+ return { kind: "target", path: spec };
69857
+ throw new AstraleError("INVALID_ARGUMENT", `"${spec}" is neither a ViewPath (/:origin:view.slug) nor a node path (/… or @id)`);
69858
+ }
69859
+ async function resolveViewCandidates(ctx, nodePath) {
69860
+ const result = await ctx.client.call(VIEW_RESOLVE_PATH, { node: nodePath });
69861
+ if (!Array.isArray(result)) {
69862
+ throw new AstraleError("UNEXPECTED_RESULT", `View:resolve returned a non-array for ${nodePath}`);
69863
+ }
69864
+ return result;
69865
+ }
69866
+ function candidateSlug(candidate) {
69867
+ const fromPath = candidate.path?.split("/").pop() ?? "";
69868
+ return candidate.name ?? fromPath;
69869
+ }
69870
+ function pickCandidate2(candidates, nodePath, slug) {
69871
+ if (slug) {
69872
+ const match = candidates.find((c) => candidateSlug(c) === slug || c.path.endsWith(`/${slug}`));
69873
+ if (!match) {
69874
+ throw new AstraleError("VIEW_NOT_FOUND", `No view "${slug}" on ${nodePath} — available: ${candidates.map(candidateSlug).join(", ") || "(none)"}`);
69875
+ }
69876
+ return match;
69877
+ }
69878
+ if (candidates.length === 0) {
69879
+ throw new AstraleError("VIEW_NOT_FOUND", `No views resolve on ${nodePath}`);
69880
+ }
69881
+ if (candidates.length === 1)
69882
+ return candidates[0];
69883
+ return "ambiguous";
69884
+ }
69885
+ function applyViewUrlOverride(resolvedUrl, override) {
69886
+ const parsed = parseUrl(override);
69887
+ if (parsed.pathname !== "/")
69888
+ return parsed.toString();
69889
+ const original = parseUrl(resolvedUrl);
69890
+ return new URL(original.pathname + original.search + original.hash, parsed.origin).toString();
69891
+ }
69892
+ function rewriteLocalViewUrl(url2) {
69893
+ const parsed = parseUrl(url2);
69894
+ if (parsed.hostname !== "host.docker.internal")
69895
+ return url2;
69896
+ parsed.hostname = "127.0.0.1";
69897
+ return parsed.toString();
69898
+ }
69899
+ function parseUrl(raw) {
69900
+ try {
69901
+ return new URL(raw);
69902
+ } catch {
69903
+ throw new AstraleError("INVALID_URL", `Not a valid URL: ${raw}`);
69904
+ }
69905
+ }
69906
+ var VIEW_RESOLVE_PATH = "/:kernel.astrale.ai:class.View:resolve", VIEW_PATH_RE;
69907
+ var init_resolve7 = __esm(() => {
69908
+ init_errors3();
69909
+ VIEW_PATH_RE = /^\/:[^\s/:@]+:view\.[a-z][a-z0-9-]*$/;
69910
+ });
69911
+
69861
69912
  // src/lib/view/server.ts
69862
69913
  import { existsSync as existsSync5 } from "node:fs";
69863
69914
  import { readFile as readFile11 } from "node:fs/promises";
69864
69915
  import { createServer } from "node:http";
69865
- import { dirname as dirname8, join as join11 } from "node:path";
69916
+ import { dirname as dirname8, join as join12 } from "node:path";
69866
69917
  import { Readable } from "node:stream";
69867
69918
  function startViewServer(config2) {
69868
69919
  const { session, proxy } = config2;
@@ -69920,11 +69971,11 @@ function startViewServer(config2) {
69920
69971
  return;
69921
69972
  }
69922
69973
  if (sub === "/" || sub === "/index.html") {
69923
- await serveAsset(res, join11(hostDir, "index.html"), "text/html; charset=utf-8");
69974
+ await serveAsset(res, join12(hostDir, "index.html"), "text/html; charset=utf-8");
69924
69975
  return;
69925
69976
  }
69926
69977
  if (sub === "/main.js") {
69927
- await serveAsset(res, join11(hostDir, "main.js"), "text/javascript; charset=utf-8");
69978
+ await serveAsset(res, join12(hostDir, "main.js"), "text/javascript; charset=utf-8");
69928
69979
  return;
69929
69980
  }
69930
69981
  if (sub === "/config.json" && req.method === "GET") {
@@ -70013,17 +70064,17 @@ function viewerDistDir() {
70013
70064
  const override = process.env.ASTRALE_VIEWER_DIR;
70014
70065
  if (override)
70015
70066
  return override;
70016
- return join11(dirname8(process.argv[1] ?? "."), "..", "viewer", "dist");
70067
+ return join12(dirname8(process.argv[1] ?? "."), "..", "viewer", "dist");
70017
70068
  }
70018
70069
  async function ensureViewerAssets() {
70019
70070
  const dist = viewerDistDir();
70020
- if (existsSync5(join11(dist, "main.js")) && existsSync5(join11(dist, "index.html")))
70071
+ if (existsSync5(join12(dist, "main.js")) && existsSync5(join12(dist, "index.html")))
70021
70072
  return dist;
70022
- const srcDir = join11(dist, "..");
70073
+ const srcDir = join12(dist, "..");
70023
70074
  const bun = globalThis.Bun;
70024
- if (bun && existsSync5(join11(srcDir, "main.ts"))) {
70075
+ if (bun && existsSync5(join12(srcDir, "main.ts"))) {
70025
70076
  const result = await bun.build({
70026
- entrypoints: [join11(srcDir, "main.ts")],
70077
+ entrypoints: [join12(srcDir, "main.ts")],
70027
70078
  outdir: dist,
70028
70079
  target: "browser",
70029
70080
  minify: false
@@ -70032,7 +70083,7 @@ async function ensureViewerAssets() {
70032
70083
  throw new Error(`viewer build failed: ${result.logs.join(`
70033
70084
  `)}`);
70034
70085
  const { copyFile: copyFile2 } = await import("node:fs/promises");
70035
- await copyFile2(join11(srcDir, "index.html"), join11(dist, "index.html"));
70086
+ await copyFile2(join12(srcDir, "index.html"), join12(dist, "index.html"));
70036
70087
  return dist;
70037
70088
  }
70038
70089
  throw new Error(`viewer bundle missing at ${dist} — reinstall the CLI (or run \`bun scripts/build.ts\` in a dev checkout)`);
@@ -70174,7 +70225,7 @@ __export(exports_view, {
70174
70225
  import { randomBytes } from "node:crypto";
70175
70226
  import { closeSync, existsSync as existsSync6, openSync, statSync } from "node:fs";
70176
70227
  import { mkdir as mkdir10, readdir as readdir3, readFile as readFile12, writeFile as writeFile9 } from "node:fs/promises";
70177
- import { dirname as dirname9, join as join12 } from "node:path";
70228
+ import { dirname as dirname9, join as join13 } from "node:path";
70178
70229
  async function resolveSession(spec, opts) {
70179
70230
  const parsed = spec ? parseViewSpec(spec) : undefined;
70180
70231
  if (parsed?.kind === "target" && opts.target) {
@@ -70250,7 +70301,7 @@ async function resolveServeRuntime() {
70250
70301
  if (node2 && entry?.endsWith(".js") && existsSync6(entry))
70251
70302
  return { file: node2, args: [entry] };
70252
70303
  if (node2 && entry?.endsWith(".ts")) {
70253
- const dist = join12(dirname9(entry), "..", "dist", "astrale.js");
70304
+ const dist = join13(dirname9(entry), "..", "dist", "astrale.js");
70254
70305
  await ensureDevDist(entry, dist);
70255
70306
  if (existsSync6(dist))
70256
70307
  return { file: node2, args: [dist] };
@@ -70268,7 +70319,7 @@ async function ensureDevDist(entry, dist) {
70268
70319
  const bun = globalThis.Bun;
70269
70320
  if (!bun)
70270
70321
  return;
70271
- const srcDir = join12(dirname9(entry), "..", "src");
70322
+ const srcDir = join13(dirname9(entry), "..", "src");
70272
70323
  if (existsSync6(dist) && !await newerThan(srcDir, statSync(dist).mtimeMs))
70273
70324
  return;
70274
70325
  console.error("(dev) building dist/astrale.js for the session server…");
@@ -70284,7 +70335,7 @@ async function newerThan(dir, mtimeMs) {
70284
70335
  for (const item of entries) {
70285
70336
  if (!item.isFile())
70286
70337
  continue;
70287
- if (statSync(join12(item.parentPath, item.name)).mtimeMs > mtimeMs)
70338
+ if (statSync(join13(item.parentPath, item.name)).mtimeMs > mtimeMs)
70288
70339
  return true;
70289
70340
  }
70290
70341
  return false;
@@ -70293,11 +70344,18 @@ async function startSession(view, target, opts) {
70293
70344
  await ensureViewerAssets();
70294
70345
  const config2 = await readConfig();
70295
70346
  const kernelTarget = await resolveKernelTarget(opts, config2);
70347
+ const [instances, identities, runtime] = await Promise.all([
70348
+ readInstances(),
70349
+ readIdentities(),
70350
+ resolveServeRuntime()
70351
+ ]);
70352
+ return withViewPortAllocationLock(() => startSessionLocked(view, target, opts, kernelTarget, instances.active, identities.default, runtime));
70353
+ }
70354
+ async function startSessionLocked(view, target, opts, kernelTarget, activeInstance, defaultIdentity, runtime) {
70296
70355
  const port = await findFreePort(VIEW_PORT_BASE, VIEW_PORT_SPAN);
70297
70356
  if (port === null) {
70298
- fatal(new Error(`No free port in ${VIEW_PORT_BASE}-${VIEW_PORT_BASE + VIEW_PORT_SPAN - 1} — close sessions with \`astrale view --close --all\``));
70357
+ throw new Error(`No free port in ${VIEW_PORT_BASE}-${VIEW_PORT_BASE + VIEW_PORT_SPAN - 1} — close sessions with \`astrale view --close --all\``);
70299
70358
  }
70300
- const [instances, identities] = await Promise.all([readInstances(), readIdentities()]);
70301
70359
  const id = `v-${randomBytes(3).toString("hex")}`;
70302
70360
  const nonce = randomBytes(12).toString("hex");
70303
70361
  const record2 = {
@@ -70308,8 +70366,8 @@ async function startSession(view, target, opts) {
70308
70366
  pageUrl: `http://127.0.0.1:${port}/s/${nonce}/`,
70309
70367
  view,
70310
70368
  target,
70311
- instance: opts.instance ?? (opts.url ? opts.url : instances.active),
70312
- identity: opts.creds ? "(pre-signed creds)" : opts.as ?? identities.default,
70369
+ instance: opts.instance ?? (opts.url ? opts.url : activeInstance),
70370
+ identity: opts.creds ? "(pre-signed creds)" : opts.as ?? defaultIdentity,
70313
70371
  createdAt: new Date().toISOString()
70314
70372
  };
70315
70373
  const serveConfig = {
@@ -70331,7 +70389,6 @@ async function startSession(view, target, opts) {
70331
70389
  await mkdir10(VIEW_DIR, { recursive: true });
70332
70390
  await writeFile9(configPath(id), JSON.stringify(serveConfig, null, 2));
70333
70391
  const logFd = openSync(logPath(id), "a");
70334
- const runtime = await resolveServeRuntime();
70335
70392
  const child = spawnHandle(runtime.file, [...runtime.args, "__view-serve", "--config", configPath(id)], {
70336
70393
  detached: true,
70337
70394
  stdio: ["ignore", logFd, logFd]
@@ -70339,7 +70396,7 @@ async function startSession(view, target, opts) {
70339
70396
  child.unref();
70340
70397
  closeSync(logFd);
70341
70398
  if (!child.pid)
70342
- fatal(new Error("Failed to spawn the view session server"));
70399
+ throw new Error("Failed to spawn the view session server");
70343
70400
  const live = { ...record2, pid: child.pid };
70344
70401
  await saveRecord(live);
70345
70402
  const deadline = Date.now() + READY_TIMEOUT_MS;
@@ -70355,9 +70412,9 @@ async function startSession(view, target, opts) {
70355
70412
  }
70356
70413
  const tail = await readFile12(logPath(id), "utf8").catch(() => "");
70357
70414
  await closeSession(live);
70358
- return fatal(new Error(`View session server did not come up.${tail ? `
70415
+ throw new Error(`View session server did not come up.${tail ? `
70359
70416
  --- server log ---
70360
- ${tail.slice(-2000)}` : ""}`));
70417
+ ${tail.slice(-2000)}` : ""}`);
70361
70418
  }
70362
70419
  async function waitForPageState(record2) {
70363
70420
  const deadline = Date.now() + STATE_TIMEOUT_MS;
@@ -70502,6 +70559,7 @@ var init_view4 = __esm(() => {
70502
70559
  init_output();
70503
70560
  init_port();
70504
70561
  init_proc();
70562
+ init_port_allocation();
70505
70563
  init_resolve7();
70506
70564
  init_server();
70507
70565
  init_session2();
@@ -70886,28 +70944,28 @@ __export(exports_studio, {
70886
70944
  default: () => studio_default
70887
70945
  });
70888
70946
  import { existsSync as existsSync8, realpathSync } from "node:fs";
70889
- import { dirname as dirname10, join as join13, resolve } from "node:path";
70947
+ import { dirname as dirname10, join as join14, resolve } from "node:path";
70890
70948
  function resolveStudioDir() {
70891
70949
  const candidates = [];
70892
70950
  if (process.env.ASTRALE_STUDIO_DIR)
70893
70951
  candidates.push(process.env.ASTRALE_STUDIO_DIR);
70894
70952
  try {
70895
70953
  const entryDir = dirname10(realpathSync(process.argv[1] ?? ""));
70896
- candidates.push(join13(entryDir, "..", "studio"), join13(entryDir, "studio"));
70954
+ candidates.push(join14(entryDir, "..", "studio"), join14(entryDir, "studio"));
70897
70955
  } catch {}
70898
70956
  for (const c of candidates) {
70899
- if (existsSync8(join13(c, "server", "index.ts")))
70957
+ if (existsSync8(join14(c, "server", "index.ts")))
70900
70958
  return resolve(c);
70901
70959
  }
70902
70960
  throw new Error(`Domain Studio assets not found (looked in: ${candidates.join(", ") || "<none>"}). ` + `Reinstall the astrale CLI, or set ASTRALE_STUDIO_DIR to a studio checkout.`);
70903
70961
  }
70904
70962
  function isDevSource(studioDir) {
70905
- return existsSync8(join13(studioDir, "vite.config.ts")) && existsSync8(join13(studioDir, "client", "src"));
70963
+ return existsSync8(join14(studioDir, "vite.config.ts")) && existsSync8(join14(studioDir, "client", "src"));
70906
70964
  }
70907
70965
  function resolveViteBin(studioDir) {
70908
70966
  for (const c of [
70909
- join13(studioDir, "node_modules", ".bin", "vite"),
70910
- join13(studioDir, "..", "..", "node_modules", ".bin", "vite")
70967
+ join14(studioDir, "node_modules", ".bin", "vite"),
70968
+ join14(studioDir, "..", "..", "node_modules", ".bin", "vite")
70911
70969
  ]) {
70912
70970
  if (existsSync8(c))
70913
70971
  return c;
@@ -71119,8 +71177,8 @@ Examples:
71119
71177
  }
71120
71178
  }), "server");
71121
71179
  } else {
71122
- const dist = join13(studioDir, "client", "dist");
71123
- if (!existsSync8(join13(dist, "index.html"))) {
71180
+ const dist = join14(studioDir, "client", "dist");
71181
+ if (!existsSync8(join14(dist, "index.html"))) {
71124
71182
  throw new Error(`studio client not built at ${dist} — run: pnpm --filter @astrale-os/studio build`);
71125
71183
  }
71126
71184
  serverChild = supervise(spawnHandle("bun", ["server/index.ts", workspace, "--port", String(studioPort), "--no-open"], {
@@ -71242,7 +71300,7 @@ var init_list = __esm(() => {
71242
71300
  }));
71243
71301
  let managed = [];
71244
71302
  if (!opts.bookmarked) {
71245
- managed = await withSpinner("Fetching instances", !isMachine(opts), () => withAdminKernelClient(opts, async (ctx) => await ctx.client.call(adminInstanceMethod("list"), {})));
71303
+ managed = await withSpinner("Fetching instances", !isMachine(opts), () => listOwnedInstances(opts));
71246
71304
  }
71247
71305
  if (isMachine(opts)) {
71248
71306
  output({
@@ -71499,6 +71557,7 @@ __export(exports_status2, {
71499
71557
  var status_default2;
71500
71558
  var init_status2 = __esm(() => {
71501
71559
  init_source();
71560
+ init_errors3();
71502
71561
  init_client2();
71503
71562
  init_admin_target();
71504
71563
  init_log();
@@ -71510,20 +71569,26 @@ var init_status2 = __esm(() => {
71510
71569
  options: [...ADMIN_TARGET_OPTIONS],
71511
71570
  action: async (id, opts) => {
71512
71571
  try {
71513
- const result = await withSpinner(`Fetching instance ${id}`, !isMachine(opts), () => withAdminKernelClient(opts, async (ctx) => await ctx.client.call(adminInstanceMethod("info"), { id })));
71572
+ const result = await withSpinner(`Fetching instance ${id}`, !isMachine(opts), () => listOwnedInstances(opts).then((instances) => {
71573
+ const match = findOwnedInstance(instances, id);
71574
+ if (match)
71575
+ return match;
71576
+ throw new AstraleError("INSTANCE_NOT_FOUND", `No owned instance matches "${id}".`, "Run `astrale instance list` to see your instances.");
71577
+ }));
71514
71578
  if (isMachine(opts)) {
71515
71579
  output(result, opts);
71516
71580
  return;
71517
71581
  }
71518
71582
  console.log(`${source_default.bold(result.slug)} ${source_default.dim(result.url)}`);
71519
- if (result.state)
71520
- log.dim(` state: ${result.state}${result.phase ? ` (${result.phase})` : ""}`);
71583
+ log.dim(` state: ${result.state}${result.phase ? ` (${result.phase})` : ""}`);
71521
71584
  if (result.error)
71522
71585
  log.dim(` error: ${result.error}`);
71523
71586
  if (result.region)
71524
71587
  log.dim(` region: ${result.region}`);
71525
71588
  if (result.hostId)
71526
71589
  log.dim(` host: ${result.hostId}`);
71590
+ if (result.organizationId)
71591
+ log.dim(` organization: ${result.organizationId}`);
71527
71592
  if (result.createdAt)
71528
71593
  log.dim(` created: ${result.createdAt}`);
71529
71594
  } catch (e) {
@@ -71548,7 +71613,9 @@ async function resolveActiveForDisplay() {
71548
71613
  };
71549
71614
  }
71550
71615
  try {
71551
- const managed = await withAdminKernelClient({}, async (ctx) => await ctx.client.call(adminInstanceMethod("info"), { id: active.name }));
71616
+ const managed = findOwnedInstance(await listOwnedInstances({}), active.name);
71617
+ if (!managed)
71618
+ return { name: active.name };
71552
71619
  return {
71553
71620
  name: managed.slug,
71554
71621
  url: normalizeInstanceKernelUrl(managed.url),
@@ -71834,7 +71901,7 @@ async function installViaAdmin(target, opts) {
71834
71901
  const adminOpts = { ...opts, instance: undefined };
71835
71902
  try {
71836
71903
  await withAdminKernelClient(adminOpts, async (ctx) => {
71837
- const instances = await ctx.client.call(adminInstanceMethod("list"), {});
71904
+ const instances = await callOwnedInstances(ctx.client);
71838
71905
  const ref2 = await resolveDomainRef(ctx, target, interactive);
71839
71906
  const slug = await resolveTargetSlug(opts, target, interactive, instances);
71840
71907
  const match = instances.find((i) => i.slug === slug);
@@ -71842,6 +71909,7 @@ async function installViaAdmin(target, opts) {
71842
71909
  const known = instances.map((i) => i.slug).join(", ") || "(none)";
71843
71910
  throw new AstraleError("INSTANCE_NOT_MANAGED", `Instance "${slug}" is not admin-managed (managed: ${known}).`, `Install the url directly onto it instead: astrale domain install <url> --direct -i ${slug}`);
71844
71911
  }
71912
+ assertInstallTargetReady(match);
71845
71913
  const label = ref2.origin ?? ref2.url ?? "domain";
71846
71914
  const result = await withSpinner(`Installing ${label} on ${match.slug}`, !isMachine(opts), () => ctx.client.call(adminDomainMethod("install"), {
71847
71915
  instanceId: match.slug,
@@ -71858,9 +71926,15 @@ async function installViaAdmin(target, opts) {
71858
71926
  log.dim(` url: ${result.url}`);
71859
71927
  });
71860
71928
  } catch (e) {
71861
- fatal(e);
71929
+ fatal(e, opts);
71862
71930
  }
71863
71931
  }
71932
+ function assertInstallTargetReady(instance) {
71933
+ if (instance.state === "ready")
71934
+ return;
71935
+ const detail = instance.phase && instance.phase !== instance.state ? ` (${instance.phase})` : "";
71936
+ throw new AstraleError("INSTANCE_NOT_READY", `Instance "${instance.slug}" is ${instance.state}${detail}; domains cannot be installed yet.`, instance.error ?? `Run: astrale instance status ${instance.slug}`);
71937
+ }
71864
71938
  function domainRefFromTarget(target) {
71865
71939
  return isHttpUrl(target) ? { url: target } : { origin: target };
71866
71940
  }
@@ -72959,21 +73033,21 @@ var init_status4 = __esm(() => {
72959
73033
 
72960
73034
  // src/telemetry/store.ts
72961
73035
  import { existsSync as existsSync9, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync2 } from "node:fs";
72962
- import { join as join14 } from "node:path";
73036
+ import { join as join15 } from "node:path";
72963
73037
  function sessionsRoot() {
72964
- return join14(createPaths().home, "sessions");
73038
+ return join15(createPaths().home, "sessions");
72965
73039
  }
72966
73040
  function sessionDir(id) {
72967
- return join14(sessionsRoot(), id);
73041
+ return join15(sessionsRoot(), id);
72968
73042
  }
72969
73043
  function eventsPath(id) {
72970
- return join14(sessionDir(id), "events.jsonl");
73044
+ return join15(sessionDir(id), "events.jsonl");
72971
73045
  }
72972
73046
  function metaPath(id) {
72973
- return join14(sessionDir(id), "meta.json");
73047
+ return join15(sessionDir(id), "meta.json");
72974
73048
  }
72975
73049
  function markerPath(id) {
72976
- return join14(sessionDir(id), ".analyzed");
73050
+ return join15(sessionDir(id), ".analyzed");
72977
73051
  }
72978
73052
  function readJsonSafe(path4) {
72979
73053
  try {
@@ -73051,12 +73125,12 @@ var init_list4 = __esm(() => {
73051
73125
  // src/telemetry/adapters/claude-code.ts
73052
73126
  import { existsSync as existsSync10, readdirSync as readdirSync3, statSync as statSync3 } from "node:fs";
73053
73127
  import { homedir as homedir3 } from "node:os";
73054
- import { join as join15 } from "node:path";
73128
+ import { join as join16 } from "node:path";
73055
73129
  function mungeCwd(cwd) {
73056
73130
  return cwd.replace(/[^a-zA-Z0-9]/g, "-");
73057
73131
  }
73058
- function claudeCodeAdapter(base2 = join15(homedir3(), ".claude")) {
73059
- const projectsDir = join15(base2, "projects");
73132
+ function claudeCodeAdapter(base2 = join16(homedir3(), ".claude")) {
73133
+ const projectsDir = join16(base2, "projects");
73060
73134
  function detect2() {
73061
73135
  try {
73062
73136
  return existsSync10(projectsDir);
@@ -73080,7 +73154,7 @@ function claudeCodeAdapter(base2 = join15(homedir3(), ".claude")) {
73080
73154
  for (const dir of dirs) {
73081
73155
  if (dir !== munged && !dir.startsWith(prefix))
73082
73156
  continue;
73083
- const projectPath = join15(projectsDir, dir);
73157
+ const projectPath = join16(projectsDir, dir);
73084
73158
  let files;
73085
73159
  try {
73086
73160
  files = readdirSync3(projectPath);
@@ -73090,7 +73164,7 @@ function claudeCodeAdapter(base2 = join15(homedir3(), ".claude")) {
73090
73164
  for (const file2 of files) {
73091
73165
  if (!file2.endsWith(".jsonl"))
73092
73166
  continue;
73093
- const transcriptPath = join15(projectPath, file2);
73167
+ const transcriptPath = join16(projectPath, file2);
73094
73168
  try {
73095
73169
  const st = statSync3(transcriptPath);
73096
73170
  const mtimeMs = st.mtime.getTime();
@@ -73126,7 +73200,7 @@ var init_claude_code = __esm(() => {
73126
73200
  import { existsSync as existsSync11, openSync as openSync2, readdirSync as readdirSync4, readSync, statSync as statSync4 } from "node:fs";
73127
73201
  import { closeSync as closeSync2 } from "node:fs";
73128
73202
  import { homedir as homedir4 } from "node:os";
73129
- import { join as join16 } from "node:path";
73203
+ import { join as join17 } from "node:path";
73130
73204
  function readFirstLine(path4) {
73131
73205
  let fd = null;
73132
73206
  try {
@@ -73166,8 +73240,8 @@ function numericDirs(path4) {
73166
73240
  return [];
73167
73241
  }
73168
73242
  }
73169
- function codexAdapter(base2 = join16(homedir4(), ".codex")) {
73170
- const sessionsDir = join16(base2, "sessions");
73243
+ function codexAdapter(base2 = join17(homedir4(), ".codex")) {
73244
+ const sessionsDir = join17(base2, "sessions");
73171
73245
  function detect2() {
73172
73246
  try {
73173
73247
  return existsSync11(sessionsDir);
@@ -73182,12 +73256,12 @@ function codexAdapter(base2 = join16(homedir4(), ".codex")) {
73182
73256
  const endMs = window2.end.getTime();
73183
73257
  const lowerMs = startMs - DAY_MS;
73184
73258
  for (const yyyy of numericDirs(sessionsDir)) {
73185
- for (const mm of numericDirs(join16(sessionsDir, yyyy))) {
73186
- for (const dd of numericDirs(join16(sessionsDir, yyyy, mm))) {
73259
+ for (const mm of numericDirs(join17(sessionsDir, yyyy))) {
73260
+ for (const dd of numericDirs(join17(sessionsDir, yyyy, mm))) {
73187
73261
  const dayStart = Date.UTC(Number(yyyy), Number(mm) - 1, Number(dd));
73188
73262
  if (dayStart > endMs + DAY_MS || dayStart + DAY_MS <= lowerMs)
73189
73263
  continue;
73190
- scanDay(join16(sessionsDir, yyyy, mm, dd), root, startMs, endMs, sessions);
73264
+ scanDay(join17(sessionsDir, yyyy, mm, dd), root, startMs, endMs, sessions);
73191
73265
  }
73192
73266
  }
73193
73267
  }
@@ -73209,7 +73283,7 @@ function scanDay(dayPath, root, startMs, endMs, out) {
73209
73283
  for (const file2 of files) {
73210
73284
  if (!file2.startsWith("rollout-") || !file2.endsWith(".jsonl"))
73211
73285
  continue;
73212
- const transcriptPath = join16(dayPath, file2);
73286
+ const transcriptPath = join17(dayPath, file2);
73213
73287
  try {
73214
73288
  const st = statSync4(transcriptPath);
73215
73289
  const mtimeMs = st.mtime.getTime();
@@ -73356,7 +73430,7 @@ var init_gate = () => {};
73356
73430
  // src/telemetry/analyze.ts
73357
73431
  import { spawn as spawn3 } from "node:child_process";
73358
73432
  import { appendFileSync, writeFileSync as writeFileSync2 } from "node:fs";
73359
- import { join as join17 } from "node:path";
73433
+ import { join as join18 } from "node:path";
73360
73434
  function writeMarker(id, marker) {
73361
73435
  writeFileSync2(markerPath(id), JSON.stringify(marker, null, 2) + `
73362
73436
  `);
@@ -73452,7 +73526,7 @@ async function analyzeSession(id, opts = {}) {
73452
73526
  const guides = new Map(adapters.map((a) => [a.name, a.readingGuide]));
73453
73527
  const prompt = buildPrompt({ id, root, signals: signals2, guides, file: opts.file ?? false });
73454
73528
  const dir = sessionDir(id);
73455
- writeFileSync2(join17(dir, "analyzer-prompt.md"), prompt);
73529
+ writeFileSync2(join18(dir, "analyzer-prompt.md"), prompt);
73456
73530
  const outcome = await runClaude(prompt, dir, opts);
73457
73531
  const marker = {
73458
73532
  analyzedAt: new Date().toISOString(),
@@ -73460,7 +73534,7 @@ async function analyzeSession(id, opts = {}) {
73460
73534
  note: outcome.note
73461
73535
  };
73462
73536
  writeMarker(id, marker);
73463
- return { ...marker, reportPath: join17(dir, "report.md") };
73537
+ return { ...marker, reportPath: join18(dir, "report.md") };
73464
73538
  }
73465
73539
  function runClaude(prompt, cwd, opts) {
73466
73540
  return new Promise((resolve2) => {
@@ -73490,7 +73564,7 @@ function runClaude(prompt, cwd, opts) {
73490
73564
  child.on("close", (code) => {
73491
73565
  clearTimeout(timer);
73492
73566
  try {
73493
- appendFileSync(join17(cwd, "analyzer.log"), out + (err ? `
73567
+ appendFileSync(join18(cwd, "analyzer.log"), out + (err ? `
73494
73568
  --- stderr ---
73495
73569
  ${err}` : ""));
73496
73570
  } catch {}
@@ -73540,9 +73614,9 @@ var init_settings = __esm(() => {
73540
73614
 
73541
73615
  // src/telemetry/trigger.ts
73542
73616
  import { existsSync as existsSync12, mkdirSync as mkdirSync2, readFileSync as readFileSync6, rmSync as rmSync2, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
73543
- import { join as join18 } from "node:path";
73617
+ import { join as join19 } from "node:path";
73544
73618
  function lockPath() {
73545
- return join18(sessionsRoot(), ".analyzer.lock");
73619
+ return join19(sessionsRoot(), ".analyzer.lock");
73546
73620
  }
73547
73621
  function releaseLock() {
73548
73622
  try {
@@ -74301,12 +74375,12 @@ function redactArgv(argv) {
74301
74375
  init_store2();
74302
74376
  import { createHash as createHash2 } from "node:crypto";
74303
74377
  import { existsSync as existsSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "node:fs";
74304
- import { dirname as dirname12, join as join19 } from "node:path";
74378
+ import { dirname as dirname12, join as join20 } from "node:path";
74305
74379
  var MAX_ID_LEN = 64;
74306
74380
  function findGitRoot(start) {
74307
74381
  let dir = start;
74308
74382
  for (;; ) {
74309
- if (existsSync13(join19(dir, ".git")))
74383
+ if (existsSync13(join20(dir, ".git")))
74310
74384
  return dir;
74311
74385
  const parent = dirname12(dir);
74312
74386
  if (parent === dir)
@@ -74407,7 +74481,7 @@ init_settings();
74407
74481
  init_store2();
74408
74482
  import { spawn as spawn4 } from "node:child_process";
74409
74483
  import { existsSync as existsSync14, mkdirSync as mkdirSync4, readFileSync as readFileSync7, rmSync as rmSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "node:fs";
74410
- import { join as join20 } from "node:path";
74484
+ import { join as join21 } from "node:path";
74411
74485
  var LOCK_STALE_MS2 = 30 * 60 * 1000;
74412
74486
  var GC_AGE_MS2 = 30 * 24 * 60 * 60 * 1000;
74413
74487
  var GC_MAX_PER_RUN = 20;
@@ -74426,7 +74500,7 @@ function gcOldSessions(sessions) {
74426
74500
  } catch {}
74427
74501
  }
74428
74502
  function lockPath2() {
74429
- return join20(sessionsRoot(), ".analyzer.lock");
74503
+ return join21(sessionsRoot(), ".analyzer.lock");
74430
74504
  }
74431
74505
  function claimLock() {
74432
74506
  const path4 = lockPath2();