@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 +272 -198
- package/package.json +1 -1
- package/src/commands/__tests__/admin-instance.test.ts +49 -2
- package/src/commands/__tests__/domain-install-owned.test.ts +122 -0
- package/src/commands/__tests__/help-contract.test.ts +15 -0
- package/src/commands/call.ts +1 -1
- package/src/commands/domain/install.ts +15 -4
- package/src/commands/instance/active.ts +4 -7
- package/src/commands/instance/list.ts +4 -8
- package/src/commands/instance/status.ts +14 -9
- package/src/commands/instance/use.ts +13 -11
- package/src/commands/view.ts +40 -13
- package/src/kernel/__tests__/client-owned-lookup.test.ts +51 -0
- package/src/kernel/client.ts +47 -20
- package/src/kernel/expand.ts +3 -22
- package/src/lib/__tests__/instance-candidates.test.ts +94 -19
- package/src/lib/__tests__/instance-target.test.ts +9 -1
- package/src/lib/__tests__/view-port-allocation.test.ts +82 -0
- package/src/lib/admin-instance.ts +27 -2
- package/src/lib/instance-candidates.ts +3 -3
- package/src/lib/instance-target.ts +1 -0
- package/src/lib/view/port-allocation.ts +19 -0
- package/src/setup/__tests__/instance-step.test.ts +239 -0
- package/src/setup/steps/instance.ts +141 -61
- package/studio/client/dist/assets/index-huaFafBC.css +1 -0
- package/studio/client/dist/index.html +2 -2
- package/studio/client/dist/assets/index-DKKMHBBC.css +0 -1
- /package/studio/client/dist/assets/{index-CyN5G8IA.js → index-DAC1a9vW.js} +0 -0
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.
|
|
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
|
|
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:
|
|
66393
|
-
managed: (slug) =>
|
|
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
|
|
66403
|
-
return await withAdminKernelClient(
|
|
66410
|
+
async function listOwnedInstances(opts) {
|
|
66411
|
+
return await withAdminKernelClient(opts, async (ctx) => callOwnedInstances(ctx.client));
|
|
66404
66412
|
}
|
|
66405
|
-
function
|
|
66406
|
-
|
|
66407
|
-
|
|
66408
|
-
|
|
66409
|
-
|
|
66410
|
-
|
|
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
|
|
66580
|
-
|
|
66581
|
-
|
|
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
|
-
|
|
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
|
|
67093
|
+
return await listOwnedInstances(opts);
|
|
67044
67094
|
} catch {
|
|
67045
67095
|
return [];
|
|
67046
67096
|
}
|
|
67047
67097
|
}
|
|
67048
67098
|
function assertManagedReady(info2) {
|
|
67049
|
-
if (
|
|
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 ??
|
|
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:
|
|
68006
|
-
managed: (instanceSlug) =>
|
|
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:
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
70067
|
+
return join12(dirname8(process.argv[1] ?? "."), "..", "viewer", "dist");
|
|
70017
70068
|
}
|
|
70018
70069
|
async function ensureViewerAssets() {
|
|
70019
70070
|
const dist = viewerDistDir();
|
|
70020
|
-
if (existsSync5(
|
|
70071
|
+
if (existsSync5(join12(dist, "main.js")) && existsSync5(join12(dist, "index.html")))
|
|
70021
70072
|
return dist;
|
|
70022
|
-
const srcDir =
|
|
70073
|
+
const srcDir = join12(dist, "..");
|
|
70023
70074
|
const bun = globalThis.Bun;
|
|
70024
|
-
if (bun && existsSync5(
|
|
70075
|
+
if (bun && existsSync5(join12(srcDir, "main.ts"))) {
|
|
70025
70076
|
const result = await bun.build({
|
|
70026
|
-
entrypoints: [
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
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 :
|
|
70312
|
-
identity: opts.creds ? "(pre-signed creds)" : opts.as ??
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
70954
|
+
candidates.push(join14(entryDir, "..", "studio"), join14(entryDir, "studio"));
|
|
70897
70955
|
} catch {}
|
|
70898
70956
|
for (const c of candidates) {
|
|
70899
|
-
if (existsSync8(
|
|
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(
|
|
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
|
-
|
|
70910
|
-
|
|
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 =
|
|
71123
|
-
if (!existsSync8(
|
|
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), () =>
|
|
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), () =>
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
73036
|
+
import { join as join15 } from "node:path";
|
|
72963
73037
|
function sessionsRoot() {
|
|
72964
|
-
return
|
|
73038
|
+
return join15(createPaths().home, "sessions");
|
|
72965
73039
|
}
|
|
72966
73040
|
function sessionDir(id) {
|
|
72967
|
-
return
|
|
73041
|
+
return join15(sessionsRoot(), id);
|
|
72968
73042
|
}
|
|
72969
73043
|
function eventsPath(id) {
|
|
72970
|
-
return
|
|
73044
|
+
return join15(sessionDir(id), "events.jsonl");
|
|
72971
73045
|
}
|
|
72972
73046
|
function metaPath(id) {
|
|
72973
|
-
return
|
|
73047
|
+
return join15(sessionDir(id), "meta.json");
|
|
72974
73048
|
}
|
|
72975
73049
|
function markerPath(id) {
|
|
72976
|
-
return
|
|
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
|
|
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 =
|
|
73059
|
-
const projectsDir =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
73170
|
-
const sessionsDir =
|
|
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(
|
|
73186
|
-
for (const dd of numericDirs(
|
|
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(
|
|
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 =
|
|
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
|
|
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(
|
|
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:
|
|
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(
|
|
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
|
|
73617
|
+
import { join as join19 } from "node:path";
|
|
73544
73618
|
function lockPath() {
|
|
73545
|
-
return
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
74503
|
+
return join21(sessionsRoot(), ".analyzer.lock");
|
|
74430
74504
|
}
|
|
74431
74505
|
function claimLock() {
|
|
74432
74506
|
const path4 = lockPath2();
|