@lunora/cli 1.0.0-alpha.67 → 1.0.0-alpha.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/packem_chunks/handler15.mjs +1 -1
- package/dist/packem_chunks/handler2.mjs +1 -1
- package/dist/packem_chunks/handler20.mjs +1 -1
- package/dist/packem_chunks/handler5.mjs +1 -1
- package/dist/packem_chunks/handler6.mjs +1 -1
- package/dist/packem_chunks/handler9.mjs +2 -2
- package/dist/packem_chunks/planDevCommand.mjs +101 -14
- package/dist/packem_chunks/runDeployCommand.mjs +2 -2
- package/dist/packem_chunks/runInitCommand.mjs +4 -4
- package/dist/packem_shared/{detect-package-manager-Cxo6Tpyx.mjs → detect-package-manager-DvEthdCw.mjs} +15 -28
- package/dist/packem_shared/{wrangler-secrets-P2_ZUR-k.mjs → wrangler-secrets-Dq_Fkbm-.mjs} +6 -4
- package/package.json +9 -8
package/dist/index.d.mts
CHANGED
|
@@ -483,8 +483,12 @@ interface DevCommandOptions {
|
|
|
483
483
|
ensureExample?: typeof ensureDevVarsExample;
|
|
484
484
|
/** Injection seam for tests — defaults to the real empty-secret/admin-token filler. */
|
|
485
485
|
fillSecrets?: typeof fillDevSecrets;
|
|
486
|
+
/** Injection seam for tests — defaults to the real free-port probe ({@link findAvailablePort}). */
|
|
487
|
+
findFreePort?: (preferred: number) => Promise<number>;
|
|
486
488
|
/** Dev flavor override (tests / callers that already detected it) — defaults to {@link detectDevFlavor}. */
|
|
487
489
|
flavor?: DevFlavor;
|
|
490
|
+
/** Injection seam for tests — defaults to the real IPv6-loopback probe ({@link hasIpv6Loopback}). */
|
|
491
|
+
hasIpv6Loopback?: () => boolean;
|
|
488
492
|
logger: Logger;
|
|
489
493
|
/** Injection seam for tests — defaults to the real remote-config materializer. */
|
|
490
494
|
materializeRemote?: typeof materializeRemoteWranglerConfig;
|
|
@@ -531,6 +535,12 @@ interface DevCommandPlan {
|
|
|
531
535
|
* regardless.
|
|
532
536
|
*/
|
|
533
537
|
frameworkHint?: string;
|
|
538
|
+
/**
|
|
539
|
+
* True when `wrangler dev` was given `--ip 127.0.0.1` because the host has no
|
|
540
|
+
* IPv6 loopback (`::1`) — surfaced so the dev loop can note the rebind.
|
|
541
|
+
* Always `false` for the vite flavor (the plugin owns its own bind).
|
|
542
|
+
*/
|
|
543
|
+
ipv4LoopbackForced: boolean;
|
|
534
544
|
/** The remote-binding decision: which D1/KV/R2 bindings hit the deployed worker. */
|
|
535
545
|
remote: DevRemotePlan;
|
|
536
546
|
studioEnabled: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -483,8 +483,12 @@ interface DevCommandOptions {
|
|
|
483
483
|
ensureExample?: typeof ensureDevVarsExample;
|
|
484
484
|
/** Injection seam for tests — defaults to the real empty-secret/admin-token filler. */
|
|
485
485
|
fillSecrets?: typeof fillDevSecrets;
|
|
486
|
+
/** Injection seam for tests — defaults to the real free-port probe ({@link findAvailablePort}). */
|
|
487
|
+
findFreePort?: (preferred: number) => Promise<number>;
|
|
486
488
|
/** Dev flavor override (tests / callers that already detected it) — defaults to {@link detectDevFlavor}. */
|
|
487
489
|
flavor?: DevFlavor;
|
|
490
|
+
/** Injection seam for tests — defaults to the real IPv6-loopback probe ({@link hasIpv6Loopback}). */
|
|
491
|
+
hasIpv6Loopback?: () => boolean;
|
|
488
492
|
logger: Logger;
|
|
489
493
|
/** Injection seam for tests — defaults to the real remote-config materializer. */
|
|
490
494
|
materializeRemote?: typeof materializeRemoteWranglerConfig;
|
|
@@ -531,6 +535,12 @@ interface DevCommandPlan {
|
|
|
531
535
|
* regardless.
|
|
532
536
|
*/
|
|
533
537
|
frameworkHint?: string;
|
|
538
|
+
/**
|
|
539
|
+
* True when `wrangler dev` was given `--ip 127.0.0.1` because the host has no
|
|
540
|
+
* IPv6 loopback (`::1`) — surfaced so the dev loop can note the rebind.
|
|
541
|
+
* Always `false` for the vite flavor (the plugin owns its own bind).
|
|
542
|
+
*/
|
|
543
|
+
ipv4LoopbackForced: boolean;
|
|
534
544
|
/** The remote-binding decision: which D1/KV/R2 bindings hit the deployed worker. */
|
|
535
545
|
remote: DevRemotePlan;
|
|
536
546
|
studioEnabled: boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readLinkedProject } from '@lunora/config';
|
|
2
2
|
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
3
|
-
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-
|
|
3
|
+
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-DvEthdCw.mjs';
|
|
4
4
|
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-Cw5Iu73G.mjs';
|
|
5
5
|
|
|
6
6
|
const LOG_FORMATS = /* @__PURE__ */ new Set(["json", "pretty"]);
|
|
@@ -2,7 +2,7 @@ import { mkdtempSync, rmSync, existsSync, readdirSync, statSync } from 'node:fs'
|
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import { join, relative } from 'node:path';
|
|
4
4
|
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
5
|
-
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-
|
|
5
|
+
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-DvEthdCw.mjs';
|
|
6
6
|
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-Cw5Iu73G.mjs';
|
|
7
7
|
|
|
8
8
|
const walk = (root) => {
|
|
@@ -4,7 +4,7 @@ import { runCodegen } from '@lunora/codegen';
|
|
|
4
4
|
import { p as parseApiSpec } from '../packem_shared/api-spec-Bx0iKbxA.mjs';
|
|
5
5
|
import { a as renderCodegenHint } from '../packem_shared/codegen-error-DJG-ghs_.mjs';
|
|
6
6
|
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
7
|
-
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-
|
|
7
|
+
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-DvEthdCw.mjs';
|
|
8
8
|
import { v as validateOutputFormat, i as isJsonFormat, p as printJson, l as loggerForFormat } from '../packem_shared/output-format-B4642rjE.mjs';
|
|
9
9
|
import { r as runSchemaDriftGate } from '../packem_shared/schema-drift-gate-BtBt0as0.mjs';
|
|
10
10
|
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-Cw5Iu73G.mjs';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
2
|
-
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-
|
|
2
|
+
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-DvEthdCw.mjs';
|
|
3
3
|
import { i as isDockerAvailable } from '../packem_shared/docker-hMQ97KSQ.mjs';
|
|
4
4
|
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-Cw5Iu73G.mjs';
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
2
|
-
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-
|
|
2
|
+
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-DvEthdCw.mjs';
|
|
3
3
|
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-Cw5Iu73G.mjs';
|
|
4
4
|
|
|
5
5
|
const withEnv = (args, env) => {
|
|
@@ -2,9 +2,9 @@ import { writeFileSync, existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { DEV_VARS_FILE, DEV_VARS_KEY_PATTERN, generateSecretValue, DEV_VARS_EXAMPLE_FILE, parseDevVariableEntries, isPlaceholderValue, packageNamesFromBindings, inferLunoraBindings, requiredSecrets, isMintableSecretKey } from '@lunora/config';
|
|
4
4
|
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
5
|
-
import { d as detectPackageManager, e as execArgsFor } from '../packem_shared/detect-package-manager-
|
|
5
|
+
import { d as detectPackageManager, e as execArgsFor } from '../packem_shared/detect-package-manager-DvEthdCw.mjs';
|
|
6
6
|
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-Cw5Iu73G.mjs';
|
|
7
|
-
import { l as listRemoteSecrets } from '../packem_shared/wrangler-secrets-
|
|
7
|
+
import { l as listRemoteSecrets } from '../packem_shared/wrangler-secrets-Dq_Fkbm-.mjs';
|
|
8
8
|
|
|
9
9
|
const NEWLINE_PRESENT = /[\r\n]/u;
|
|
10
10
|
const UNREPRESENTABLE_PRESENT = /["\\]/u;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { spawnSync, spawn } from 'node:child_process';
|
|
2
|
-
import { detectAgentRules, claimDevServerState, clearDevServerState, readDevServerState, readLiveDevServerState, readProjectDependencyNames, DEV_HANDOFF_ENV, isRecordedProcessCurrent, DEV_LOG_FILE, DEV_LOG_FILE_ENV, DEV_DAEMON_ENV, detectAiAgent, resolveRemoteEnabled, readProjectRemotePreference,
|
|
2
|
+
import { detectAgentRules, claimDevServerState, clearDevServerState, readDevServerState, readLiveDevServerState, readProjectDependencyNames, DEV_HANDOFF_ENV, isRecordedProcessCurrent, DEV_LOG_FILE, DEV_LOG_FILE_ENV, DEV_DAEMON_ENV, updateDevServerState, detectAiAgent, resolveRemoteEnabled, readProjectRemotePreference, inferLunoraBindings, packageNamesFromBindings, ensureDevVarsExample, ensureDevVariables, isInteractive, DEV_VARS_FILE, DEV_VARS_EXAMPLE_FILE, fillDevSecrets, claimAgentRulesHint, AGENT_RULES_HINT, findWranglerFile, readWranglerJsonc, detectFramework, discoverContainerInfo, streamContainerLogs, materializeRemoteWranglerConfig, formatLunoraEvent } from '@lunora/config';
|
|
3
3
|
import { p as parseApiSpec } from '../packem_shared/api-spec-Bx0iKbxA.mjs';
|
|
4
4
|
import { existsSync, watch, readFileSync, statSync, openSync, readSync, closeSync, mkdirSync } from 'node:fs';
|
|
5
5
|
import { join, dirname } from 'node:path';
|
|
6
6
|
import { runCodegen } from '@lunora/codegen';
|
|
7
7
|
import { r as renderCodegenFailure } from '../packem_shared/codegen-error-DJG-ghs_.mjs';
|
|
8
8
|
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
9
|
-
import { d as detectPackageManager, e as execArgsFor, r as runScriptCommand } from '../packem_shared/detect-package-manager-
|
|
9
|
+
import { d as detectPackageManager, e as execArgsFor, r as runScriptCommand } from '../packem_shared/detect-package-manager-DvEthdCw.mjs';
|
|
10
|
+
import { createServer, connect } from 'node:net';
|
|
10
11
|
import { forceJsonLogging } from '../packem_shared/createLogger-CIWSHrTL.mjs';
|
|
12
|
+
import { networkInterfaces } from 'node:os';
|
|
11
13
|
import { spawnShellCompat } from '../packem_shared/createRecordingSpawner-Cw5Iu73G.mjs';
|
|
12
|
-
import { createServer, request } from 'node:http';
|
|
13
|
-
import { connect } from 'node:net';
|
|
14
|
+
import { createServer as createServer$1, request } from 'node:http';
|
|
14
15
|
import { loadStudioAssets, studioAssetsStamp, renderStudioHtml, resolveAdminToken, SCHEMA_EDIT_ENDPOINT, POLICY_SCAFFOLD_ENDPOINT, SEED_ENDPOINT, serveJsonHandler, isStandaloneModulePath, readStandaloneAsset, assetContentType, handleSchemaEditRequest, handlePolicyScaffoldRequest, handleSeedRequest } from '@lunora/config/studio-host';
|
|
15
16
|
import { c as createTuiConfirm } from '../packem_shared/tui-prompts-BjEN8XgP.mjs';
|
|
16
17
|
import { p as printJson } from '../packem_shared/output-format-B4642rjE.mjs';
|
|
@@ -75,6 +76,32 @@ const startCodegenWatch = (options) => {
|
|
|
75
76
|
};
|
|
76
77
|
};
|
|
77
78
|
|
|
79
|
+
const DEFAULT_PROBE_ATTEMPTS = 64;
|
|
80
|
+
const LOOPBACK_HOST = "127.0.0.1";
|
|
81
|
+
const MAX_PORT = 65535;
|
|
82
|
+
const isPortFree = (port, host = LOOPBACK_HOST) => new Promise((resolve) => {
|
|
83
|
+
const server = createServer();
|
|
84
|
+
server.once("error", () => {
|
|
85
|
+
resolve(false);
|
|
86
|
+
});
|
|
87
|
+
server.once("listening", () => {
|
|
88
|
+
server.close(() => {
|
|
89
|
+
resolve(true);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
server.listen(port, host);
|
|
93
|
+
});
|
|
94
|
+
const findAvailablePort = async (preferred, host = LOOPBACK_HOST, attempts = DEFAULT_PROBE_ATTEMPTS) => {
|
|
95
|
+
for (let port = preferred; port < preferred + attempts && port <= MAX_PORT; port += 1) {
|
|
96
|
+
if (await isPortFree(port, host)) {
|
|
97
|
+
return port;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return preferred;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const hasIpv6Loopback = (readInterfaces = networkInterfaces) => Object.values(readInterfaces()).some((addresses) => addresses?.some((address) => address.internal && address.address === "::1"));
|
|
104
|
+
|
|
78
105
|
const PROXY_PREFIX = "/_lunora";
|
|
79
106
|
const pathnameOf = (url) => {
|
|
80
107
|
const queryIndex = url.indexOf("?");
|
|
@@ -201,7 +228,7 @@ const startStudioServer = async (options) => {
|
|
|
201
228
|
return true;
|
|
202
229
|
};
|
|
203
230
|
const document = Buffer.from(html);
|
|
204
|
-
const server = createServer((request, response) => {
|
|
231
|
+
const server = createServer$1((request, response) => {
|
|
205
232
|
const pathname = pathnameOf(request.url ?? "/");
|
|
206
233
|
if (isLoopback && !isLoopbackHost(request.headers.host)) {
|
|
207
234
|
response.statusCode = 403;
|
|
@@ -437,11 +464,18 @@ const runDevBackground = async (options) => {
|
|
|
437
464
|
for (const line of readLogTail(logPath, FAILURE_LOG_TAIL_LINES)) {
|
|
438
465
|
logger.error(` ${line}`);
|
|
439
466
|
}
|
|
440
|
-
clearDevServerState(cwd, child.pid);
|
|
467
|
+
clearDevServerState(cwd, child.pid ?? process.pid);
|
|
441
468
|
return { code: outcome.exitCode === 0 ? 1 : outcome.exitCode };
|
|
442
469
|
}
|
|
470
|
+
if (child.pid !== void 0) {
|
|
471
|
+
const current = readDevServerState(cwd);
|
|
472
|
+
if (current?.pid === process.pid) {
|
|
473
|
+
updateDevServerState(cwd, { logFile: logPath, pid: child.pid });
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
const pidHint = child.pid === void 0 ? "" : ` (pid ${String(child.pid)})`;
|
|
443
477
|
logger.warn(
|
|
444
|
-
`dev server did not confirm ready within ${String(Math.round(timeout / 1e3))}s — it may still be compiling. Check \`lunora dev status\` and \`lunora dev logs\`; \`lunora dev stop\` shuts it down.`
|
|
478
|
+
`dev server did not confirm ready within ${String(Math.round(timeout / 1e3))}s — it may still be compiling${pidHint}. Check \`lunora dev status\` and \`lunora dev logs\`; \`lunora dev stop\` shuts it down.`
|
|
445
479
|
);
|
|
446
480
|
return { code: 1 };
|
|
447
481
|
};
|
|
@@ -516,10 +550,10 @@ const processGroupId = (pid) => {
|
|
|
516
550
|
return void 0;
|
|
517
551
|
}
|
|
518
552
|
};
|
|
519
|
-
const forceKillRecordedServer = (state, signal) => {
|
|
520
|
-
if (
|
|
553
|
+
const forceKillRecordedServer = (state, signal, platform = process.platform, spawnSyncImpl = spawnSync) => {
|
|
554
|
+
if (platform === "win32") {
|
|
521
555
|
try {
|
|
522
|
-
|
|
556
|
+
spawnSyncImpl("taskkill", ["/pid", String(state.pid), "/T", "/F"], { stdio: "ignore" });
|
|
523
557
|
} catch {
|
|
524
558
|
}
|
|
525
559
|
return;
|
|
@@ -536,6 +570,16 @@ const forceKillRecordedServer = (state, signal) => {
|
|
|
536
570
|
} catch {
|
|
537
571
|
}
|
|
538
572
|
};
|
|
573
|
+
const reportSurvivedForceKill = (state, options) => {
|
|
574
|
+
if (options.json) {
|
|
575
|
+
printJson({ pid: state.pid, stopped: false });
|
|
576
|
+
} else {
|
|
577
|
+
options.logger.error(
|
|
578
|
+
`dev server (pid ${String(state.pid)}) survived the force-kill — record kept; retry \`lunora dev stop\` or kill the process manually.`
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
return { code: 1 };
|
|
582
|
+
};
|
|
539
583
|
const runDevStop = async (options) => {
|
|
540
584
|
const { cwd, logger } = options;
|
|
541
585
|
const state = readDevServerState(cwd);
|
|
@@ -545,6 +589,8 @@ const runDevStop = async (options) => {
|
|
|
545
589
|
});
|
|
546
590
|
const pollInterval = options.pollIntervalMs ?? POLL_INTERVAL_MS;
|
|
547
591
|
const grace = options.stopGraceMs ?? STOP_GRACE_MS;
|
|
592
|
+
const platform = options.platform ?? process.platform;
|
|
593
|
+
const spawnSyncImpl = options.spawnSyncImpl ?? spawnSync;
|
|
548
594
|
if (state === void 0 || !alive(state.pid)) {
|
|
549
595
|
if (state !== void 0) {
|
|
550
596
|
clearDevServerState(cwd, state.pid);
|
|
@@ -565,7 +611,11 @@ const runDevStop = async (options) => {
|
|
|
565
611
|
await sleep(pollInterval);
|
|
566
612
|
}
|
|
567
613
|
if (alive(state.pid)) {
|
|
568
|
-
forceKillRecordedServer(state, signal);
|
|
614
|
+
forceKillRecordedServer(state, signal, platform, spawnSyncImpl);
|
|
615
|
+
await sleep(pollInterval);
|
|
616
|
+
if (alive(state.pid)) {
|
|
617
|
+
return reportSurvivedForceKill(state, options);
|
|
618
|
+
}
|
|
569
619
|
}
|
|
570
620
|
clearDevServerState(cwd, state.pid);
|
|
571
621
|
if (options.json) {
|
|
@@ -669,6 +719,29 @@ const resolveRemotePlan = (options, cwd) => {
|
|
|
669
719
|
}
|
|
670
720
|
return { args: ["--config", result.configPath], plan: { bindings, cleanup, enabled: true } };
|
|
671
721
|
};
|
|
722
|
+
const resolveLoopbackArgs = (cwd, hasLoopback) => {
|
|
723
|
+
const wranglerPath = findWranglerFile(cwd);
|
|
724
|
+
if (wranglerPath !== void 0) {
|
|
725
|
+
const { parsed } = readWranglerJsonc(wranglerPath);
|
|
726
|
+
if (parsed?.dev?.ip !== void 0) {
|
|
727
|
+
return [];
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return hasLoopback() ? [] : ["--ip", "127.0.0.1"];
|
|
731
|
+
};
|
|
732
|
+
const resolveWorkerPort = async (options, cwd) => {
|
|
733
|
+
if (options.workerPort !== void 0) {
|
|
734
|
+
return options.workerPort;
|
|
735
|
+
}
|
|
736
|
+
const wranglerPath = findWranglerFile(cwd);
|
|
737
|
+
if (wranglerPath !== void 0) {
|
|
738
|
+
const { parsed } = readWranglerJsonc(wranglerPath);
|
|
739
|
+
if (typeof parsed?.dev?.port === "number") {
|
|
740
|
+
return parsed.dev.port;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
return (options.findFreePort ?? findAvailablePort)(DEFAULT_WORKER_PORT);
|
|
744
|
+
};
|
|
672
745
|
const planDevCommand = (options) => {
|
|
673
746
|
const cwd = options.cwd ?? process.cwd();
|
|
674
747
|
const manager = detectPackageManager(cwd);
|
|
@@ -678,6 +751,7 @@ const planDevCommand = (options) => {
|
|
|
678
751
|
return {
|
|
679
752
|
codegenEnabled: false,
|
|
680
753
|
flavor,
|
|
754
|
+
ipv4LoopbackForced: false,
|
|
681
755
|
remote: { bindings: [], cleanup: () => {
|
|
682
756
|
}, enabled: options.remote === true },
|
|
683
757
|
studioEnabled: false,
|
|
@@ -697,11 +771,13 @@ const planDevCommand = (options) => {
|
|
|
697
771
|
const frameworkHint = detection.framework === "none" ? void 0 : `this project uses ${detection.framework} — the worker runs inside Vite there. run \`${runScriptCommand(manager, "dev")}\` for the full app (frontend + HMR); \`lunora dev\` starts only the worker.`;
|
|
698
772
|
const workerPort = options.workerPort ?? DEFAULT_WORKER_PORT;
|
|
699
773
|
const remote = resolveRemotePlan(options, cwd);
|
|
700
|
-
const
|
|
774
|
+
const loopbackArgs = resolveLoopbackArgs(cwd, options.hasIpv6Loopback ?? hasIpv6Loopback);
|
|
775
|
+
const exec = execArgsFor(manager, "wrangler", ["dev", "--port", String(workerPort), ...loopbackArgs, "--var", "WORKER_ENV:development", ...remote.args]);
|
|
701
776
|
return {
|
|
702
777
|
codegenEnabled: options.codegen !== false,
|
|
703
778
|
flavor,
|
|
704
779
|
frameworkHint,
|
|
780
|
+
ipv4LoopbackForced: loopbackArgs.length > 0,
|
|
705
781
|
remote: remote.plan,
|
|
706
782
|
studioEnabled: options.studio !== false,
|
|
707
783
|
studioPort: options.port ?? DEFAULT_STUDIO_PORT,
|
|
@@ -899,8 +975,14 @@ const claimStartRecord = (plan, cwd) => {
|
|
|
899
975
|
);
|
|
900
976
|
return claim.ok ? void 0 : claim.existing;
|
|
901
977
|
};
|
|
978
|
+
const buildDevPlan = async (options) => {
|
|
979
|
+
const cwd = options.cwd ?? process.cwd();
|
|
980
|
+
const flavor = options.flavor ?? detectDevFlavor(cwd);
|
|
981
|
+
const workerPort = flavor === "wrangler" ? await resolveWorkerPort(options, cwd) : options.workerPort;
|
|
982
|
+
return planDevCommand({ ...options, cwd, flavor, workerPort });
|
|
983
|
+
};
|
|
902
984
|
const runDevCommand = async (options) => {
|
|
903
|
-
const plan =
|
|
985
|
+
const plan = await buildDevPlan(options);
|
|
904
986
|
const { logger } = options;
|
|
905
987
|
const cwd = plan.wrangler.cwd ?? process.cwd();
|
|
906
988
|
const handles = { remoteCleanup: plan.remote.cleanup };
|
|
@@ -922,6 +1004,11 @@ const runDevCommand = async (options) => {
|
|
|
922
1004
|
logger.info(
|
|
923
1005
|
plan.flavor === "vite" ? "starting vite dev (worker + studio + codegen run inside Vite via @lunora/vite)" : "starting wrangler dev + studio"
|
|
924
1006
|
);
|
|
1007
|
+
if (plan.ipv4LoopbackForced) {
|
|
1008
|
+
logger.info(
|
|
1009
|
+
"no IPv6 loopback (::1) on this host — binding the worker to 127.0.0.1 (--ip) so wrangler dev doesn't crash. Pin `dev.ip` in wrangler.jsonc to override."
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
925
1012
|
if (plan.codegenEnabled) {
|
|
926
1013
|
handles.codegen = (options.startCodegen ?? startCodegenWatch)({ apiSpec: options.apiSpec, logger, projectRoot: cwd });
|
|
927
1014
|
}
|
|
@@ -1026,4 +1113,4 @@ const execute = defineHandler(async ({ argument, cwd, logger, options }) => {
|
|
|
1026
1113
|
});
|
|
1027
1114
|
});
|
|
1028
1115
|
|
|
1029
|
-
export { detectDevFlavor, execute, planDevCommand, resolveRemotePlan, runDevCommand };
|
|
1116
|
+
export { detectDevFlavor, execute, planDevCommand, resolveRemotePlan, resolveWorkerPort, runDevCommand };
|
|
@@ -7,7 +7,7 @@ import { Project } from 'ts-morph';
|
|
|
7
7
|
import { p as parseApiSpec } from '../packem_shared/api-spec-Bx0iKbxA.mjs';
|
|
8
8
|
import { r as readWranglerName } from '../packem_shared/wrangler-name-cy4yhm9j.mjs';
|
|
9
9
|
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
10
|
-
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-
|
|
10
|
+
import { e as execArgsFor, d as detectPackageManager } from '../packem_shared/detect-package-manager-DvEthdCw.mjs';
|
|
11
11
|
import { a as isRailpackAvailable, i as isDockerAvailable } from '../packem_shared/docker-hMQ97KSQ.mjs';
|
|
12
12
|
import { v as validateOutputFormat, i as isJsonFormat, p as printJson, l as loggerForFormat } from '../packem_shared/output-format-B4642rjE.mjs';
|
|
13
13
|
import { containerBuildTag } from '@lunora/container';
|
|
@@ -15,7 +15,7 @@ import { defaultSpawner } from '../packem_shared/createRecordingSpawner-Cw5Iu73G
|
|
|
15
15
|
import { r as resolveWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
|
|
16
16
|
import { r as runSchemaDriftGate } from '../packem_shared/schema-drift-gate-BtBt0as0.mjs';
|
|
17
17
|
import { c as createTuiConfirm } from '../packem_shared/tui-prompts-BjEN8XgP.mjs';
|
|
18
|
-
import { l as listRemoteSecrets } from '../packem_shared/wrangler-secrets-
|
|
18
|
+
import { l as listRemoteSecrets } from '../packem_shared/wrangler-secrets-Dq_Fkbm-.mjs';
|
|
19
19
|
import { runMigrateDataCommand } from './runMigrateGenerateCommand.mjs';
|
|
20
20
|
|
|
21
21
|
const WORKERS_DEV_URL = /https?:\/\/[^\s"'<>]+\.workers\.dev[^\s"'<>]*/u;
|
|
@@ -7,7 +7,7 @@ import { downloadTemplate } from 'giget';
|
|
|
7
7
|
import { modify, applyEdits } from 'jsonc-parser';
|
|
8
8
|
import { join, dirname } from 'node:path';
|
|
9
9
|
import { d as defineHandler } from '../packem_shared/command-lYnl4QyF.mjs';
|
|
10
|
-
import { d as detectPackageManager, a as detectInstalledManagers, i as installArgsFor, r as runScriptCommand } from '../packem_shared/detect-package-manager-
|
|
10
|
+
import { d as detectPackageManager, a as detectInstalledManagers, i as installArgsFor, r as runScriptCommand } from '../packem_shared/detect-package-manager-DvEthdCw.mjs';
|
|
11
11
|
import MagicString from 'magic-string';
|
|
12
12
|
import { Project, SyntaxKind } from 'ts-morph';
|
|
13
13
|
import { P as PromptCancelledError } from '../packem_shared/prompt-cancelled-APzX1Im-.mjs';
|
|
@@ -1940,8 +1940,7 @@ const maybeOfferGit = async (options, target) => {
|
|
|
1940
1940
|
options.logger.warn("`git init` failed — initialize it yourself later with `git init`.");
|
|
1941
1941
|
}
|
|
1942
1942
|
};
|
|
1943
|
-
const printNextSteps = async (name, installed, insideMonorepo) => {
|
|
1944
|
-
const manager = installed ?? "pnpm";
|
|
1943
|
+
const printNextSteps = async (name, installed, manager, insideMonorepo) => {
|
|
1945
1944
|
const steps = [{ code: `cd ./${name}`, lead: "Enter your project directory using" }];
|
|
1946
1945
|
if (installed === void 0) {
|
|
1947
1946
|
steps.push({ code: `${manager} install`, lead: "Install dependencies with", tail: insideMonorepo ? " from the workspace root" : void 0 });
|
|
@@ -2462,7 +2461,8 @@ const runPostScaffold = async (options, result, cwd) => {
|
|
|
2462
2461
|
const installedManager = options.inPlace === true ? void 0 : await maybeOfferInstall(options, result.target);
|
|
2463
2462
|
if (options.inPlace !== true) {
|
|
2464
2463
|
await maybeOfferGit(options, result.target);
|
|
2465
|
-
|
|
2464
|
+
const manager = installedManager ?? detectPackageManager(result.target);
|
|
2465
|
+
await printNextSteps(basename(result.target), installedManager, manager, isInsideMonorepo(cwd));
|
|
2466
2466
|
await emitMascot(options.logger);
|
|
2467
2467
|
}
|
|
2468
2468
|
};
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { LunoraError } from '@lunora/errors';
|
|
3
|
+
import { findPackageManagerSync, identifyInitiatingPackageManager } from '@visulima/package/package-manager';
|
|
4
4
|
|
|
5
|
-
const FALLBACK = "pnpm";
|
|
6
|
-
const KNOWN_MANAGERS = ["pnpm", "yarn", "npm", "bun"];
|
|
7
5
|
const INSTALL_PREFERENCE = ["pnpm", "bun", "yarn", "npm"];
|
|
8
6
|
const isManagerInstalled = (manager) => {
|
|
9
7
|
try {
|
|
@@ -16,34 +14,23 @@ const detectInstalledManagers = (probe = isManagerInstalled) => INSTALL_PREFEREN
|
|
|
16
14
|
const installArgsFor = (manager) => {
|
|
17
15
|
return { args: ["install"], command: manager };
|
|
18
16
|
};
|
|
19
|
-
const
|
|
20
|
-
if (typeof declared !== "string") {
|
|
21
|
-
return void 0;
|
|
22
|
-
}
|
|
23
|
-
return KNOWN_MANAGERS.find((manager) => declared.startsWith(`${manager}@`));
|
|
24
|
-
};
|
|
25
|
-
const readDeclaredManager = (directory) => {
|
|
26
|
-
const candidate = join(directory, "package.json");
|
|
27
|
-
if (!existsSync(candidate)) {
|
|
28
|
-
return void 0;
|
|
29
|
-
}
|
|
17
|
+
const detectPackageManager = (startDirectory) => {
|
|
30
18
|
try {
|
|
31
|
-
|
|
32
|
-
return parseDeclaredManager(parsed.packageManager);
|
|
19
|
+
return findPackageManagerSync(startDirectory).packageManager;
|
|
33
20
|
} catch {
|
|
34
|
-
return void 0;
|
|
35
21
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
directory = dirname(directory);
|
|
22
|
+
const initiating = identifyInitiatingPackageManager();
|
|
23
|
+
if (initiating !== void 0) {
|
|
24
|
+
return initiating.name === "cnpm" ? "npm" : initiating.name;
|
|
25
|
+
}
|
|
26
|
+
const [installed] = detectInstalledManagers();
|
|
27
|
+
if (installed !== void 0) {
|
|
28
|
+
return installed;
|
|
45
29
|
}
|
|
46
|
-
|
|
30
|
+
throw new LunoraError(
|
|
31
|
+
"INTERNAL",
|
|
32
|
+
"Could not detect a package manager: no lock file or `packageManager` field was found, and none (pnpm, bun, yarn, npm) is installed on PATH."
|
|
33
|
+
);
|
|
47
34
|
};
|
|
48
35
|
const execArgsFor = (manager, command, args) => {
|
|
49
36
|
if (manager === "yarn") {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
|
+
import { e as execArgsFor, d as detectPackageManager } from './detect-package-manager-DvEthdCw.mjs';
|
|
2
3
|
|
|
3
4
|
const execCode = (error) => {
|
|
4
5
|
if (!error) {
|
|
@@ -25,15 +26,16 @@ const parseSecretNames = (stdout) => {
|
|
|
25
26
|
return [...names].toSorted((a, b) => a.localeCompare(b));
|
|
26
27
|
};
|
|
27
28
|
const listRemoteSecrets = async (inputs) => {
|
|
28
|
-
const
|
|
29
|
+
const wranglerArgs = ["secret", "list", "--format", "json"];
|
|
29
30
|
if (inputs.env !== void 0) {
|
|
30
|
-
|
|
31
|
+
wranglerArgs.push("--env", inputs.env);
|
|
31
32
|
}
|
|
32
33
|
if (inputs.temporary) {
|
|
33
|
-
|
|
34
|
+
wranglerArgs.push("--temporary");
|
|
34
35
|
}
|
|
36
|
+
const { args, command } = execArgsFor(detectPackageManager(inputs.cwd), "wrangler", wranglerArgs);
|
|
35
37
|
const runner = inputs.runner ?? defaultRunner;
|
|
36
|
-
const result = await runner(
|
|
38
|
+
const result = await runner(command, args, inputs.cwd);
|
|
37
39
|
if (result.code !== 0) {
|
|
38
40
|
return { error: result.stderr.trim() || `wrangler secret list exited ${String(result.code)}`, names: [], ok: false };
|
|
39
41
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/cli",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.69",
|
|
4
4
|
"description": "The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
|
@@ -51,16 +51,17 @@
|
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@bomb.sh/tab": "0.0.
|
|
55
|
-
"@lunora/codegen": "1.0.0-alpha.
|
|
56
|
-
"@lunora/config": "1.0.0-alpha.
|
|
57
|
-
"@lunora/container": "1.0.0-alpha.
|
|
58
|
-
"@lunora/d1": "1.0.0-alpha.
|
|
59
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
60
|
-
"@lunora/seed": "1.0.0-alpha.
|
|
54
|
+
"@bomb.sh/tab": "0.0.16",
|
|
55
|
+
"@lunora/codegen": "1.0.0-alpha.34",
|
|
56
|
+
"@lunora/config": "1.0.0-alpha.56",
|
|
57
|
+
"@lunora/container": "1.0.0-alpha.7",
|
|
58
|
+
"@lunora/d1": "1.0.0-alpha.24",
|
|
59
|
+
"@lunora/errors": "1.0.0-alpha.2",
|
|
60
|
+
"@lunora/seed": "1.0.0-alpha.17",
|
|
61
61
|
"@visulima/cerebro": "3.0.0-alpha.32",
|
|
62
62
|
"@visulima/error": "6.0.0-alpha.34",
|
|
63
63
|
"@visulima/fs": "5.0.0-alpha.32",
|
|
64
|
+
"@visulima/package": "5.0.0-alpha.23",
|
|
64
65
|
"@visulima/pail": "4.0.0-alpha.22",
|
|
65
66
|
"@visulima/path": "3.0.0-alpha.13",
|
|
66
67
|
"@visulima/spinner": "1.0.0-alpha.4",
|