@nylorun/cli 0.3.0-beta → 0.4.0-beta

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +50 -1
  2. package/README.md +55 -78
  3. package/dist/{runtime/baseline.js → baseline.js} +0 -1
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.js +34 -115
  6. package/dist/doctor.d.ts +1 -12
  7. package/dist/doctor.js +6 -96
  8. package/dist/home.d.ts +6 -0
  9. package/dist/home.js +15 -0
  10. package/dist/model/host-model.js +1 -1
  11. package/dist/project/create-tenant.d.ts +3 -1
  12. package/dist/project/create-tenant.js +3 -2
  13. package/dist/project/credentials.js +1 -1
  14. package/dist/project/env.d.ts +3 -0
  15. package/dist/project/env.js +21 -0
  16. package/dist/project/link.js +1 -1
  17. package/dist/project/root.js +2 -1
  18. package/dist/project/seed.d.ts +6 -0
  19. package/dist/project/seed.js +9 -7
  20. package/dist/tenant/commands.js +73 -14
  21. package/package.json +6 -9
  22. package/dist/dev-entry.d.ts +0 -5
  23. package/dist/dev-entry.js +0 -7
  24. package/dist/dev.d.ts +0 -47
  25. package/dist/dev.js +0 -278
  26. package/dist/launcher.d.ts +0 -5
  27. package/dist/launcher.js +0 -7
  28. package/dist/project/attach.d.ts +0 -32
  29. package/dist/project/attach.js +0 -241
  30. package/dist/runtime/commands.d.ts +0 -16
  31. package/dist/runtime/commands.js +0 -292
  32. package/dist/runtime/ephemeral.d.ts +0 -37
  33. package/dist/runtime/ephemeral.js +0 -84
  34. package/dist/runtime/exit-codes.d.ts +0 -9
  35. package/dist/runtime/exit-codes.js +0 -43
  36. package/dist/runtime/index.d.ts +0 -8
  37. package/dist/runtime/index.js +0 -6
  38. package/dist/runtime/launcher.d.ts +0 -81
  39. package/dist/runtime/launcher.js +0 -243
  40. package/dist/runtime/progress.d.ts +0 -10
  41. package/dist/runtime/progress.js +0 -8
  42. package/dist/runtime/version.d.ts +0 -6
  43. package/dist/runtime/version.js +0 -27
  44. /package/dist/{runtime/baseline.d.ts → baseline.d.ts} +0 -0
@@ -18,9 +18,11 @@ export interface CreateTenantResult {
18
18
  name: string;
19
19
  };
20
20
  }
21
+ /** The Project's `package.json` name, else its directory name. */
22
+ export declare function defaultTenantName(projectRoot: string): Promise<string>;
21
23
  /**
22
24
  * Create a Tenant via `@nylorun/admin` and write format-1 link + credentials.
23
25
  */
24
26
  export declare function createProjectTenant(options: CreateTenantOptions): Promise<CreateTenantResult>;
25
- /** Resolve Admin from the local Host root (after launcher `up`). */
27
+ /** Resolve Admin from the local Host root (host.json and the admin key). */
26
28
  export declare function localAdmin(home?: string): Admin;
@@ -5,7 +5,8 @@ import { newPrincipalId } from "@nylorun/agents";
5
5
  import { CliError } from "../errors.js";
6
6
  import { writeCredentials, } from "./credentials.js";
7
7
  import { writeLink } from "./link.js";
8
- async function defaultTenantName(projectRoot) {
8
+ /** The Project's `package.json` name, else its directory name. */
9
+ export async function defaultTenantName(projectRoot) {
9
10
  try {
10
11
  const pkg = JSON.parse(await readFile(join(projectRoot, "package.json"), "utf8"));
11
12
  if (typeof pkg.name === "string" && pkg.name.trim())
@@ -59,7 +60,7 @@ export async function createProjectTenant(options) {
59
60
  envelope: { id: created.tenant.id, name: created.tenant.name },
60
61
  };
61
62
  }
62
- /** Resolve Admin from the local Host root (after launcher `up`). */
63
+ /** Resolve Admin from the local Host root (host.json and the admin key). */
63
64
  export function localAdmin(home) {
64
65
  return createAdmin(home ? { home } : undefined);
65
66
  }
@@ -10,7 +10,7 @@ export async function readCredentials(projectRoot) {
10
10
  !/^[0-9a-f]{64}$/.test(value.applicationKey) ||
11
11
  typeof value?.principalId !== "string" ||
12
12
  value.principalId.length === 0) {
13
- throw new CliError(`Invalid Project credentials at ${path}. Remove .nylorun/credentials.json and run nylorun dev.`, 1);
13
+ throw new CliError(`Invalid Project credentials at ${path}. Remove .nylorun/credentials.json and run nylo tenant create.`, 1);
14
14
  }
15
15
  const format = value.format === undefined || value.format === 0
16
16
  ? 0
@@ -0,0 +1,3 @@
1
+ /** Three `export` lines for `nylo env` (was `nylorun status --env`, F2-7). */
2
+ export declare function printLinkedEnvExports(projectRoot?: string): Promise<void>;
3
+ export declare function shellQuote(value: string): string;
@@ -0,0 +1,21 @@
1
+ import { readCredentials } from "./credentials.js";
2
+ import { readLink } from "./link.js";
3
+ import { findProjectRoot } from "./root.js";
4
+ /** Three `export` lines for `nylo env` (was `nylorun status --env`, F2-7). */
5
+ export async function printLinkedEnvExports(projectRoot = process.cwd()) {
6
+ const root = findProjectRoot(projectRoot) ?? projectRoot;
7
+ const link = await readLink(root);
8
+ const credentials = await readCredentials(root);
9
+ if (!link || !credentials) {
10
+ console.log("# No Project link in this directory. Run nylo tenant create to create one.");
11
+ return;
12
+ }
13
+ console.log(`export NYLORUN_RUNTIME_URL=${shellQuote(link.hostUrl)}`);
14
+ console.log(`export NYLORUN_SERVER_KEY=${shellQuote(credentials.applicationKey)}`);
15
+ console.log(`export NYLORUN_TENANT=${shellQuote(link.tenantId)}`);
16
+ }
17
+ export function shellQuote(value) {
18
+ if (/^[A-Za-z0-9_./:-]+$/.test(value))
19
+ return value;
20
+ return `'${value.replace(/'/g, `'\\''`)}'`;
21
+ }
@@ -31,7 +31,7 @@ export async function readLink(projectRoot) {
31
31
  typeof value?.hostId !== "string" ||
32
32
  typeof value?.tenantId !== "string" ||
33
33
  !isTenantId(value.tenantId)) {
34
- throw new CliError(`Invalid Project link at ${linkPath(projectRoot)}. Remove .nylorun/link.json and run nylorun dev.`, 1);
34
+ throw new CliError(`Invalid Project link at ${linkPath(projectRoot)}. Remove .nylorun/link.json and run nylo tenant create.`, 1);
35
35
  }
36
36
  const format = value.format === undefined || value.format === 0
37
37
  ? 0
@@ -26,8 +26,9 @@ export function findProjectRoot(cwd = process.cwd()) {
26
26
  const root = parse(directory).root;
27
27
  let fallback;
28
28
  for (;;) {
29
+ // The home directory is never a Project, but a package.json below it is.
29
30
  if (directory === stop)
30
- return undefined;
31
+ return fallback;
31
32
  if (existsSync(join(directory, ".nylorun")))
32
33
  return directory;
33
34
  if (!fallback && existsSync(join(directory, "package.json")))
@@ -7,6 +7,11 @@ export interface SeedOptions {
7
7
  env?: Readonly<Record<string, string>>;
8
8
  fetchImpl?: typeof fetch;
9
9
  signal?: AbortSignal;
10
+ /**
11
+ * Seed the Tenant-level fixture model (`fixtureModel: true`, Host feature
12
+ * `tenant-fixture-model`) and skip the Project's model credential.
13
+ */
14
+ fixtureModel?: boolean;
10
15
  }
11
16
  /**
12
17
  * Seed non-secret Tenant config via `PUT /v1/tenant/config/seed`.
@@ -16,4 +21,5 @@ export interface SeedOptions {
16
21
  export declare function seedTenantFromProject(options: SeedOptions): Promise<{
17
22
  applied: string[];
18
23
  kept: string[];
24
+ model?: string;
19
25
  }>;
@@ -21,14 +21,12 @@ export async function seedTenantFromProject(options) {
21
21
  const env = options.env ?? loadProjectEnvironment(options.projectRoot);
22
22
  const fetchImpl = options.fetchImpl ?? fetch;
23
23
  const sandboxRaw = env.NYLORUN_SANDBOX?.trim();
24
- const sandbox = sandboxRaw === "auto" ||
25
- sandboxRaw === "microsandbox" ||
26
- sandboxRaw === "virtual"
24
+ const sandbox = sandboxRaw === "auto" || sandboxRaw === "virtual"
27
25
  ? { backend: sandboxRaw }
28
26
  : undefined;
29
27
  let applied = [];
30
28
  let kept = [];
31
- if (sandbox) {
29
+ if (sandbox || options.fixtureModel) {
32
30
  const response = await fetchImpl(`${options.hostUrl.replace(/\/$/, "")}/v1/tenant/config/seed`, {
33
31
  method: "PUT",
34
32
  headers: {
@@ -37,7 +35,8 @@ export async function seedTenantFromProject(options) {
37
35
  },
38
36
  body: JSON.stringify({
39
37
  requestId: randomUUID(),
40
- sandbox,
38
+ ...(sandbox ? { sandbox } : {}),
39
+ ...(options.fixtureModel ? { fixtureModel: true } : {}),
41
40
  }),
42
41
  signal: options.signal ?? AbortSignal.timeout(15_000),
43
42
  });
@@ -50,13 +49,16 @@ export async function seedTenantFromProject(options) {
50
49
  applied = body.applied ?? [];
51
50
  kept = body.kept ?? [];
52
51
  }
53
- if (env.NYLORUN_DEV_MODEL?.trim() !== "fixture") {
52
+ // A fixture-model Tenant never calls a real model: its credential stays out of it.
53
+ let model;
54
+ if (!options.fixtureModel && env.NYLORUN_DEV_MODEL?.trim() !== "fixture") {
54
55
  const seeded = modelFromEnv(env, options.projectRoot);
55
56
  if (seeded) {
56
57
  await putHostModel(options.hostUrl, options.applicationKey, seeded, options.tenantId);
58
+ model = `${seeded.provider}/${seeded.model}`;
57
59
  }
58
60
  }
59
- return { applied, kept };
61
+ return { applied, kept, ...(model ? { model } : {}) };
60
62
  }
61
63
  function modelFromEnv(env, projectRoot) {
62
64
  const provider = env.MODEL_PROVIDER?.trim();
@@ -3,10 +3,14 @@ import { randomUUID } from "node:crypto";
3
3
  import { createAdmin } from "@nylorun/admin";
4
4
  import { createClient, isTenantId } from "@nylorun/agents";
5
5
  import { CliError } from "../errors.js";
6
- import { resolveHome } from "../runtime/launcher.js";
6
+ import { resolveHome } from "../home.js";
7
7
  import { readCredentials, removeCredentials, } from "../project/credentials.js";
8
8
  import { readLink, removeLink, writeLink, } from "../project/link.js";
9
- import { requireProjectRoot } from "../project/root.js";
9
+ import { findProjectRoot, requireProjectRoot } from "../project/root.js";
10
+ import { createProjectTenant, defaultTenantName, } from "../project/create-tenant.js";
11
+ import { seedTenantFromProject } from "../project/seed.js";
12
+ import { loadProjectEnvironment } from "../environment.js";
13
+ import { shellQuote } from "../project/env.js";
10
14
  /** Exact-and-unique name or id match. */
11
15
  export function matchTenant(tenants, nameOrId) {
12
16
  if (isTenantId(nameOrId)) {
@@ -27,18 +31,73 @@ export function matchTenant(tenants, nameOrId) {
27
31
  function localAdmin(home) {
28
32
  return createAdmin(home ? { home } : undefined);
29
33
  }
34
+ /**
35
+ * `nylo tenant create [name]`. Inside a Project: create the Tenant, write the
36
+ * Project link and credentials, and seed it from the Project's `.env` (sandbox
37
+ * and model provider). Outside one: create the Tenant and print its
38
+ * connection variables once, since the Host keeps only a hash of the key.
39
+ */
40
+ async function createTenant(options) {
41
+ const admin = localAdmin(options.home);
42
+ let hostId;
43
+ try {
44
+ hostId = (await admin.status()).host?.hostId;
45
+ }
46
+ catch (error) {
47
+ throw new CliError(`No Runtime answers at ${admin.url} (${error instanceof Error ? error.message : String(error)}). Start the local stack with "npx nylorun up".`, 6);
48
+ }
49
+ if (!hostId)
50
+ throw new CliError(`Host at ${admin.url} did not report hostId in admin status.`, 1);
51
+ const projectRoot = findProjectRoot();
52
+ if (!projectRoot) {
53
+ const created = await admin.createTenant({ name: options.name ?? "tenant" });
54
+ console.log(`Tenant ${created.tenant.name} ${created.tenant.id} (created)`);
55
+ console.log("# Not in a Project: nothing was linked. The key is shown only once.");
56
+ console.log(`export NYLORUN_RUNTIME_URL=${shellQuote(admin.url.replace(/\/$/, ""))}`);
57
+ console.log(`export NYLORUN_SERVER_KEY=${shellQuote(created.applicationKey)}`);
58
+ console.log(`export NYLORUN_TENANT=${shellQuote(created.tenant.id)}`);
59
+ return;
60
+ }
61
+ const link = await readLink(projectRoot);
62
+ if (link)
63
+ throw new CliError(`This Project is already linked to Tenant ${link.tenantId}. Use "nylo tenant use <name-or-id>" to switch, or "nylo tenant delete" first.`, 1);
64
+ const created = await createProjectTenant({
65
+ admin,
66
+ hostId,
67
+ projectRoot,
68
+ name: options.name ?? (await defaultTenantName(projectRoot)),
69
+ });
70
+ console.log(`Tenant ${created.envelope.name} ${created.envelope.id} (created)`);
71
+ console.log(`Linked ${projectRoot}/.nylorun/`);
72
+ const seeded = await seedTenantFromProject({
73
+ hostUrl: created.link.hostUrl,
74
+ tenantId: created.link.tenantId,
75
+ applicationKey: created.credentials.applicationKey,
76
+ projectRoot,
77
+ env: loadProjectEnvironment(projectRoot),
78
+ });
79
+ console.log(seeded.model
80
+ ? `Model ${seeded.model} (from .env)`
81
+ : "Model not configured: set it in Studio, or run nylo configure");
82
+ }
30
83
  export async function tenantCommand(args) {
31
84
  const [verb, ...rest] = args;
32
85
  if (!verb || verb === "--help" || verb === "-h") {
33
- console.log(`nylorun tenant current|list [--json]|use <name-or-id>|status [--json]|reset [--sessions|--sandboxes|--all] [--yes]|delete <name-or-id> [--yes]`);
86
+ console.log(`nylo tenant create [name]|current|list [--json]|use <name-or-id>|status [--json]|reset [--sessions|--sandboxes|--all] [--yes]|delete <name-or-id> [--yes]`);
34
87
  return;
35
88
  }
36
89
  const home = resolveHome();
90
+ if (verb === "create") {
91
+ if (rest.length > 1 || rest.some((arg) => arg.startsWith("-")))
92
+ throw new CliError("Usage: nylo tenant create [name]", 2);
93
+ await createTenant({ home, ...(rest[0] ? { name: rest[0] } : {}) });
94
+ return;
95
+ }
37
96
  if (verb === "current") {
38
97
  const root = requireProjectRoot();
39
98
  const link = await readLink(root);
40
99
  if (!link) {
41
- console.log("No Project link. Run nylorun dev to create one.");
100
+ console.log("No Project link. Run nylo tenant create to create one.");
42
101
  return;
43
102
  }
44
103
  const admin = localAdmin(home);
@@ -52,7 +111,7 @@ export async function tenantCommand(args) {
52
111
  if (verb === "list") {
53
112
  const json = rest.includes("--json");
54
113
  if (rest.some((a) => a !== "--json")) {
55
- throw new CliError("Usage: nylorun tenant list [--json]", 2);
114
+ throw new CliError("Usage: nylo tenant list [--json]", 2);
56
115
  }
57
116
  const admin = localAdmin(home);
58
117
  const tenants = await admin.listTenants();
@@ -73,7 +132,7 @@ export async function tenantCommand(args) {
73
132
  if (verb === "use") {
74
133
  const nameOrId = rest[0];
75
134
  if (!nameOrId || rest.length > 1) {
76
- throw new CliError("Usage: nylorun tenant use <name-or-id>", 2);
135
+ throw new CliError("Usage: nylo tenant use <name-or-id>", 2);
77
136
  }
78
137
  const root = requireProjectRoot();
79
138
  const admin = localAdmin(home);
@@ -87,7 +146,7 @@ export async function tenantCommand(args) {
87
146
  console.warn("Sharing a Tenant shares executor registrations across Projects that link to it.");
88
147
  const credentials = await readCredentials(root);
89
148
  if (!credentials) {
90
- throw new CliError("No Project credentials. Run nylorun dev to create a Tenant first, or copy credentials for the target Tenant.", 1);
149
+ throw new CliError("No Project credentials. Run nylo tenant create to create a Tenant first, or copy credentials for the target Tenant.", 1);
91
150
  }
92
151
  const client = createClient({
93
152
  url: admin.url,
@@ -98,7 +157,7 @@ export async function tenantCommand(args) {
98
157
  await client.transport.json("/v1/tenant", "GET");
99
158
  }
100
159
  catch {
101
- throw new CliError(`Credentials do not authorize Tenant ${selected.id}. Create a new Tenant with nylorun dev instead of reusing another Project's Tenant without its key.`, 1);
160
+ throw new CliError(`Credentials do not authorize Tenant ${selected.id}. Create a new Tenant with nylo tenant create instead of reusing another Project's Tenant without its key.`, 1);
102
161
  }
103
162
  await writeLink(root, {
104
163
  format: 1,
@@ -112,13 +171,13 @@ export async function tenantCommand(args) {
112
171
  if (verb === "status") {
113
172
  const json = rest.includes("--json");
114
173
  if (rest.some((a) => a !== "--json")) {
115
- throw new CliError("Usage: nylorun tenant status [--json]", 2);
174
+ throw new CliError("Usage: nylo tenant status [--json]", 2);
116
175
  }
117
176
  const root = requireProjectRoot();
118
177
  const link = await readLink(root);
119
178
  const credentials = await readCredentials(root);
120
179
  if (!link || !credentials) {
121
- throw new CliError("No Project link. Run nylorun dev to create one.", 1);
180
+ throw new CliError("No Project link. Run nylo tenant create to create one.", 1);
122
181
  }
123
182
  const client = createClient({
124
183
  url: link.hostUrl,
@@ -174,7 +233,7 @@ export async function tenantCommand(args) {
174
233
  else if (flags.includes("--sessions") || flags.length === 0)
175
234
  scope = "sessions";
176
235
  else
177
- throw new CliError("Usage: nylorun tenant reset [--sessions|--sandboxes|--all] [--yes]", 2);
236
+ throw new CliError("Usage: nylo tenant reset [--sessions|--sandboxes|--all] [--yes]", 2);
178
237
  if (flags.filter((f) => ["--sessions", "--sandboxes", "--all"].includes(f)).length > 1) {
179
238
  throw new CliError("Pass only one of --sessions, --sandboxes, --all.", 2);
180
239
  }
@@ -182,7 +241,7 @@ export async function tenantCommand(args) {
182
241
  const link = await readLink(root);
183
242
  const credentials = await readCredentials(root);
184
243
  if (!link || !credentials) {
185
- throw new CliError("No Project link. Run nylorun dev first.", 1);
244
+ throw new CliError("No Project link. Run nylo tenant create first.", 1);
186
245
  }
187
246
  const admin = localAdmin(home);
188
247
  const tenants = await admin.listTenants();
@@ -215,7 +274,7 @@ export async function tenantCommand(args) {
215
274
  const yes = rest.includes("--yes");
216
275
  const nameOrId = rest.find((a) => a !== "--yes");
217
276
  if (!nameOrId || rest.filter((a) => a !== "--yes").length !== 1) {
218
- throw new CliError("Usage: nylorun tenant delete <name-or-id> [--yes]", 2);
277
+ throw new CliError("Usage: nylo tenant delete <name-or-id> [--yes]", 2);
219
278
  }
220
279
  const root = requireProjectRoot();
221
280
  const admin = localAdmin(home);
@@ -243,7 +302,7 @@ export async function tenantCommand(args) {
243
302
  console.log(`Deleted Tenant ${selected.name ?? selected.id}.`);
244
303
  return;
245
304
  }
246
- throw new CliError(`Unknown tenant command ${verb}.\nUsage: nylorun tenant current|list|use|status|reset|delete`, 2);
305
+ throw new CliError(`Unknown tenant command ${verb}.\nUsage: nylo tenant current|list|use|status|reset|delete`, 2);
247
306
  }
248
307
  async function confirmOrThrow(prompt) {
249
308
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@nylorun/cli",
3
- "version": "0.3.0-beta",
3
+ "version": "0.4.0-beta",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
- "description": "Nylorun local development CLI",
6
+ "description": "Nylorun Runtime client: Tenants, Project links and model providers",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/nylorun/harness.git",
@@ -30,9 +30,9 @@
30
30
  "prepack": "npm run build"
31
31
  },
32
32
  "dependencies": {
33
- "@nylorun/agents": "0.6.0-beta",
34
- "@nylorun/admin": "0.2.0-beta",
35
- "@earendil-works/pi-ai": "0.85.1"
33
+ "@nylorun/agents": "0.7.0-beta",
34
+ "@nylorun/admin": "0.3.0-beta",
35
+ "@earendil-works/pi-ai": "0.87.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "typescript": "npm:@typescript/typescript6@^6.0.2",
@@ -40,9 +40,6 @@
40
40
  "vitest": "^5.0.1"
41
41
  },
42
42
  "bin": {
43
- "nylorun": "dist/cli.js"
44
- },
45
- "nylorun": {
46
- "runtime": "0.10.0-beta"
43
+ "nylo": "dist/cli.js"
47
44
  }
48
45
  }
@@ -1,5 +0,0 @@
1
- /**
2
- * Legacy watcher entry. `nylorun dev` now runs the Project entry with
3
- * `tsx watch` directly (D§12).
4
- */
5
- export declare function legacyDevEntryRemoved(): never;
package/dist/dev-entry.js DELETED
@@ -1,7 +0,0 @@
1
- /**
2
- * Legacy watcher entry. `nylorun dev` now runs the Project entry with
3
- * `tsx watch` directly (D§12).
4
- */
5
- export function legacyDevEntryRemoved() {
6
- throw new Error("cli/src/dev-entry.ts is no longer used. Point nylorun dev at your Project entry (default src/main.ts).");
7
- }
package/dist/dev.d.ts DELETED
@@ -1,47 +0,0 @@
1
- export interface DevelopOptions {
2
- entry?: string;
3
- flags?: readonly string[];
4
- projectRoot?: string;
5
- home?: string;
6
- }
7
- export type DevelopmentPreflight = {
8
- tsx: string;
9
- entry: string;
10
- ephemeral: boolean;
11
- localUi: boolean;
12
- studio: boolean;
13
- open: boolean;
14
- };
15
- /**
16
- * Everything that can be checked without contacting the Host, so a Project that
17
- * cannot run never causes a Runtime Host to be started on its behalf.
18
- */
19
- export declare function developmentPreflight(args?: readonly string[]): DevelopmentPreflight;
20
- /**
21
- * Resolve `@nylorun/studio` from the Project and call `startStudio`.
22
- * Used by `nylorun studio` and `nylorun dev --local-ui`.
23
- */
24
- export declare function startStudio(options: {
25
- runtimeUrl: string;
26
- serverKey: string;
27
- tenant: {
28
- id: string;
29
- name: string;
30
- };
31
- open: boolean;
32
- port?: number;
33
- /** When true, force local UI. When false/omit, use startStudio default (hosted). */
34
- localUi?: boolean;
35
- cacheDir?: string;
36
- projectRoot?: string;
37
- }): Promise<{
38
- address: string;
39
- launchUrl: string;
40
- close(): Promise<void>;
41
- }>;
42
- /**
43
- * `nylorun dev [entry]` — D§12 steps 1–4.
44
- * Spawns `tsx watch <entry>` with the three Project environment variables.
45
- * `--local-ui` also starts the Studio proxy with a local dashboard.
46
- */
47
- export declare function develop(options?: DevelopOptions): Promise<number>;