@codemation/cli 0.0.21 → 0.0.24
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/CHANGELOG.md +34 -0
- package/dist/{CliBin-BYHuUedo.js → CliBin-CWXW_92Y.js} +116 -32
- package/dist/bin.js +1 -1
- package/dist/index.d.ts +8661 -1741
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/src/CliProgramFactory.ts +3 -0
- package/src/bootstrap/CodemationCliApplicationSession.ts +3 -3
- package/src/commands/DevCommand.ts +20 -20
- package/src/database/ConsumerDatabaseConnectionResolver.ts +10 -10
- package/src/database/DatabaseMigrationsApplyService.ts +1 -1
- package/src/database/HostPackageRootResolver.ts +2 -2
- package/src/database/PrismaMigrateDeployInvoker.ts +3 -2
- package/src/dev/CliDevProxyServer.ts +3 -6
- package/src/dev/DevCliBannerRenderer.ts +39 -0
- package/src/dev/DevNextChildProcessOutputFilter.ts +30 -0
- package/src/dev/DevNextHostEnvironmentBuilder.ts +1 -0
- package/src/dev/DevNextStartupBannerLineFilter.ts +25 -0
- package/src/user/CliDatabaseUrlDescriptor.ts +1 -1
- package/src/user/UserAdminCliBootstrap.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CliProgram, i as CliPathResolver, n as CliProgramFactory, o as ConsumerOutputBuilder, r as CodemationCliApplicationSession, s as ConsumerBuildOptionsParser, t as CliBin } from "./CliBin-
|
|
1
|
+
import { a as CliProgram, i as CliPathResolver, n as CliProgramFactory, o as ConsumerOutputBuilder, r as CodemationCliApplicationSession, s as ConsumerBuildOptionsParser, t as CliBin } from "./CliBin-CWXW_92Y.js";
|
|
2
2
|
import { CodemationPluginDiscovery } from "@codemation/host/server";
|
|
3
3
|
|
|
4
4
|
export { CliBin, CliPathResolver, CliProgram, CliProgramFactory, CodemationCliApplicationSession, CodemationPluginDiscovery, ConsumerBuildOptionsParser, ConsumerOutputBuilder };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemation/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"reflect-metadata": "^0.2.2",
|
|
39
39
|
"typescript": "^5.9.3",
|
|
40
40
|
"ws": "^8.19.0",
|
|
41
|
-
"@codemation/host": "0.
|
|
42
|
-
"@codemation/
|
|
41
|
+
"@codemation/next-host": "0.1.2",
|
|
42
|
+
"@codemation/host": "0.1.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/http-proxy": "^1.17.15",
|
package/src/CliProgramFactory.ts
CHANGED
|
@@ -21,6 +21,8 @@ import { HostPackageRootResolver } from "./database/HostPackageRootResolver";
|
|
|
21
21
|
import { PrismaMigrationDeployer } from "@codemation/host/persistence";
|
|
22
22
|
import { DevBootstrapSummaryFetcher } from "./dev/DevBootstrapSummaryFetcher";
|
|
23
23
|
import { DevCliBannerRenderer } from "./dev/DevCliBannerRenderer";
|
|
24
|
+
import { DevNextChildProcessOutputFilter } from "./dev/DevNextChildProcessOutputFilter";
|
|
25
|
+
import { DevNextStartupBannerLineFilter } from "./dev/DevNextStartupBannerLineFilter";
|
|
24
26
|
import { CliDevProxyServerFactory } from "./dev/CliDevProxyServerFactory";
|
|
25
27
|
import { DevApiRuntimeFactory } from "./dev/DevApiRuntimeFactory";
|
|
26
28
|
import { DevRebuildQueueFactory } from "./dev/DevRebuildQueueFactory";
|
|
@@ -100,6 +102,7 @@ export class CliProgramFactory {
|
|
|
100
102
|
new DevApiRuntimeFactory(devSessionServices.loopbackPortAllocator, appConfigLoader, pluginDiscovery),
|
|
101
103
|
new CliDevProxyServerFactory(),
|
|
102
104
|
new DevRebuildQueueFactory(),
|
|
105
|
+
new DevNextChildProcessOutputFilter(new DevNextStartupBannerLineFilter()),
|
|
103
106
|
);
|
|
104
107
|
return new CliProgram(
|
|
105
108
|
buildOptionsParser,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
AppContainerLifecycle,
|
|
6
6
|
type AppConfig,
|
|
7
7
|
DatabaseMigrations,
|
|
8
|
-
PrismaClient,
|
|
8
|
+
type PrismaClient,
|
|
9
9
|
type CommandBus,
|
|
10
10
|
type QueryBus,
|
|
11
11
|
} from "@codemation/host";
|
|
@@ -34,10 +34,10 @@ export class CodemationCliApplicationSession {
|
|
|
34
34
|
|
|
35
35
|
getPrismaClient(): PrismaClient | undefined {
|
|
36
36
|
const container = this.getContainer();
|
|
37
|
-
if (!container.isRegistered(PrismaClient, true)) {
|
|
37
|
+
if (!container.isRegistered(ApplicationTokens.PrismaClient, true)) {
|
|
38
38
|
return undefined;
|
|
39
39
|
}
|
|
40
|
-
return container.resolve(PrismaClient);
|
|
40
|
+
return container.resolve(ApplicationTokens.PrismaClient);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
getCommandBus(): CommandBus {
|
|
@@ -13,6 +13,7 @@ import type { DevBootstrapSummaryFetcher } from "../dev/DevBootstrapSummaryFetch
|
|
|
13
13
|
import type { CliDevProxyServer } from "../dev/CliDevProxyServer";
|
|
14
14
|
import type { CliDevProxyServerFactory } from "../dev/CliDevProxyServerFactory";
|
|
15
15
|
import type { DevCliBannerRenderer } from "../dev/DevCliBannerRenderer";
|
|
16
|
+
import type { DevNextChildProcessOutputFilter } from "../dev/DevNextChildProcessOutputFilter";
|
|
16
17
|
import { ConsumerEnvDotenvFilePredicate } from "../dev/ConsumerEnvDotenvFilePredicate";
|
|
17
18
|
import type { DevRebuildQueueFactory } from "../dev/DevRebuildQueueFactory";
|
|
18
19
|
import type { DevSourceWatcher } from "../dev/DevSourceWatcher";
|
|
@@ -49,6 +50,7 @@ export class DevCommand {
|
|
|
49
50
|
private readonly devApiRuntimeFactory: DevApiRuntimeFactory,
|
|
50
51
|
private readonly cliDevProxyServerFactory: CliDevProxyServerFactory,
|
|
51
52
|
private readonly devRebuildQueueFactory: DevRebuildQueueFactory,
|
|
53
|
+
private readonly devNextChildProcessOutputFilter: DevNextChildProcessOutputFilter,
|
|
52
54
|
) {}
|
|
53
55
|
|
|
54
56
|
async execute(
|
|
@@ -112,11 +114,16 @@ export class DevCommand {
|
|
|
112
114
|
await this.startPackagedUiWhenNeeded(prepared, processState, uiProxyBase);
|
|
113
115
|
this.bindShutdownSignalsToChildProcesses(processState, proxyServer);
|
|
114
116
|
await this.spawnDevUiWhenNeeded(prepared, processState, gatewayBaseUrl);
|
|
117
|
+
this.devCliBannerRenderer.renderGatewayListeningHint(
|
|
118
|
+
prepared.devMode === "watch-framework" ? prepared.nextPort : prepared.gatewayPort,
|
|
119
|
+
commandName,
|
|
120
|
+
prepared.devMode,
|
|
121
|
+
prepared.devMode === "watch-framework" ? prepared.gatewayPort : undefined,
|
|
122
|
+
);
|
|
115
123
|
await this.startWatcherForSourceRestart(prepared, processState, watcher, devMode, gatewayBaseUrl, proxyServer, {
|
|
116
124
|
commandName,
|
|
117
125
|
configPathOverride: args.configPathOverride,
|
|
118
126
|
});
|
|
119
|
-
this.logPackagedUiDevHintWhenNeeded(devMode, gatewayPort, commandName);
|
|
120
127
|
await stopPromise;
|
|
121
128
|
} finally {
|
|
122
129
|
if (previousDevelopmentServerToken === undefined) {
|
|
@@ -234,9 +241,10 @@ export class DevCommand {
|
|
|
234
241
|
});
|
|
235
242
|
state.currentPackagedUi = spawn(nextHostCommand.command, nextHostCommand.args, {
|
|
236
243
|
cwd: nextHostCommand.cwd,
|
|
237
|
-
...this.
|
|
244
|
+
...this.devDetachedChildSpawnPipeOptions(),
|
|
238
245
|
env: nextHostEnvironment,
|
|
239
246
|
});
|
|
247
|
+
this.devNextChildProcessOutputFilter.attach(state.currentPackagedUi);
|
|
240
248
|
state.currentPackagedUi.on("error", (error) => {
|
|
241
249
|
if (state.stopRequested || state.isRestartingUi) {
|
|
242
250
|
return;
|
|
@@ -276,14 +284,18 @@ export class DevCommand {
|
|
|
276
284
|
proxyServer.setBuildStatus("idle");
|
|
277
285
|
}
|
|
278
286
|
|
|
279
|
-
|
|
280
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Next startup lines are filtered (see {@link DevNextChildProcessOutputFilter}) so the CLI can
|
|
289
|
+
* own the primary “open this URL” message without the internal loopback port dominating stdout.
|
|
290
|
+
*/
|
|
291
|
+
private devDetachedChildSpawnPipeOptions(): Readonly<{
|
|
292
|
+
stdio: ["ignore", "pipe", "pipe"];
|
|
281
293
|
detached: boolean;
|
|
282
294
|
windowsHide?: boolean;
|
|
283
295
|
}> {
|
|
284
296
|
return process.platform === "win32"
|
|
285
|
-
? { stdio: "
|
|
286
|
-
: { stdio: "
|
|
297
|
+
? { stdio: ["ignore", "pipe", "pipe"], detached: true, windowsHide: true }
|
|
298
|
+
: { stdio: ["ignore", "pipe", "pipe"], detached: true };
|
|
287
299
|
}
|
|
288
300
|
|
|
289
301
|
private bindShutdownSignalsToChildProcesses(
|
|
@@ -341,9 +353,10 @@ export class DevCommand {
|
|
|
341
353
|
});
|
|
342
354
|
state.currentDevUi = spawn("pnpm", ["exec", "next", "dev"], {
|
|
343
355
|
cwd: nextHostRoot,
|
|
344
|
-
...this.
|
|
356
|
+
...this.devDetachedChildSpawnPipeOptions(),
|
|
345
357
|
env: nextHostEnvironment,
|
|
346
358
|
});
|
|
359
|
+
this.devNextChildProcessOutputFilter.attach(state.currentDevUi);
|
|
347
360
|
state.currentDevUi.on("exit", (code) => {
|
|
348
361
|
const normalizedCode = code ?? 0;
|
|
349
362
|
if (state.stopRequested || state.isRestartingUi) {
|
|
@@ -591,17 +604,4 @@ export class DevCommand {
|
|
|
591
604
|
await this.consumerBuildArtifactsPublisher.publish(snapshot, discoveredPlugins);
|
|
592
605
|
this.cliLogger.debug(`Dev: consumer output published (${snapshot.buildVersion}).`);
|
|
593
606
|
}
|
|
594
|
-
|
|
595
|
-
private logPackagedUiDevHintWhenNeeded(
|
|
596
|
-
devMode: DevMode,
|
|
597
|
-
gatewayPort: number,
|
|
598
|
-
commandName: "dev" | "dev:plugin",
|
|
599
|
-
): void {
|
|
600
|
-
if (devMode !== "packaged-ui") {
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
this.cliLogger.info(
|
|
604
|
-
`codemation ${commandName}: open http://127.0.0.1:${gatewayPort} — this uses the packaged @codemation/next-host UI. Use \`codemation ${commandName} --watch-framework\` only when working on the framework UI itself.`,
|
|
605
|
-
);
|
|
606
|
-
}
|
|
607
607
|
}
|
|
@@ -3,7 +3,7 @@ import type { AppPersistenceConfig } from "@codemation/host/persistence";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Resolves TCP PostgreSQL vs
|
|
6
|
+
* Resolves TCP PostgreSQL vs SQLite vs none from env + {@link CodemationConfig} (same rules as the host runtime).
|
|
7
7
|
*/
|
|
8
8
|
export class ConsumerDatabaseConnectionResolver {
|
|
9
9
|
resolve(processEnv: NodeJS.ProcessEnv, config: CodemationConfig, consumerRoot: string): AppPersistenceConfig {
|
|
@@ -20,18 +20,18 @@ export class ConsumerDatabaseConnectionResolver {
|
|
|
20
20
|
return { kind: "postgresql", databaseUrl };
|
|
21
21
|
}
|
|
22
22
|
return {
|
|
23
|
-
kind: "
|
|
24
|
-
|
|
23
|
+
kind: "sqlite",
|
|
24
|
+
databaseFilePath: this.resolveSqliteFilePath(database.sqliteFilePath, processEnv, consumerRoot),
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
private resolveDatabaseKind(
|
|
29
|
-
configuredKind: "postgresql" | "
|
|
29
|
+
configuredKind: "postgresql" | "sqlite" | undefined,
|
|
30
30
|
databaseUrl: string | undefined,
|
|
31
31
|
env: NodeJS.ProcessEnv,
|
|
32
|
-
): "postgresql" | "
|
|
32
|
+
): "postgresql" | "sqlite" {
|
|
33
33
|
const kindFromEnv = env.CODEMATION_DATABASE_KIND?.trim();
|
|
34
|
-
if (kindFromEnv === "postgresql" || kindFromEnv === "
|
|
34
|
+
if (kindFromEnv === "postgresql" || kindFromEnv === "sqlite") {
|
|
35
35
|
return kindFromEnv;
|
|
36
36
|
}
|
|
37
37
|
if (configuredKind) {
|
|
@@ -41,15 +41,15 @@ export class ConsumerDatabaseConnectionResolver {
|
|
|
41
41
|
if (trimmedUrl && (trimmedUrl.startsWith("postgresql://") || trimmedUrl.startsWith("postgres://"))) {
|
|
42
42
|
return "postgresql";
|
|
43
43
|
}
|
|
44
|
-
return "
|
|
44
|
+
return "sqlite";
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
private
|
|
47
|
+
private resolveSqliteFilePath(
|
|
48
48
|
configuredPath: string | undefined,
|
|
49
49
|
env: NodeJS.ProcessEnv,
|
|
50
50
|
consumerRoot: string,
|
|
51
51
|
): string {
|
|
52
|
-
const envPath = env.
|
|
52
|
+
const envPath = env.CODEMATION_SQLITE_FILE_PATH?.trim();
|
|
53
53
|
if (envPath && envPath.length > 0) {
|
|
54
54
|
return path.isAbsolute(envPath) ? envPath : path.resolve(consumerRoot, envPath);
|
|
55
55
|
}
|
|
@@ -59,6 +59,6 @@ export class ConsumerDatabaseConnectionResolver {
|
|
|
59
59
|
? trimmedConfiguredPath
|
|
60
60
|
: path.resolve(consumerRoot, trimmedConfiguredPath);
|
|
61
61
|
}
|
|
62
|
-
return path.resolve(consumerRoot, ".codemation", "
|
|
62
|
+
return path.resolve(consumerRoot, ".codemation", "codemation.sqlite");
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -60,7 +60,7 @@ export class DatabaseMigrationsApplyService {
|
|
|
60
60
|
if (persistence.kind === "none") {
|
|
61
61
|
if (requirePersistence) {
|
|
62
62
|
throw new Error(
|
|
63
|
-
"Database persistence is not configured. Set CodemationConfig.runtime.database (postgresql URL or
|
|
63
|
+
"Database persistence is not configured. Set CodemationConfig.runtime.database (postgresql URL or SQLite file path).",
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
66
|
return;
|
|
@@ -12,7 +12,7 @@ export class HostPackageRootResolver {
|
|
|
12
12
|
const entry = fileURLToPath(entryUrl);
|
|
13
13
|
let dir = path.dirname(entry);
|
|
14
14
|
for (let depth = 0; depth < 8; depth += 1) {
|
|
15
|
-
if (existsSync(path.join(dir, "prisma", "schema.prisma"))) {
|
|
15
|
+
if (existsSync(path.join(dir, "prisma", "schema.postgresql.prisma"))) {
|
|
16
16
|
return dir;
|
|
17
17
|
}
|
|
18
18
|
const parent = path.dirname(dir);
|
|
@@ -21,6 +21,6 @@ export class HostPackageRootResolver {
|
|
|
21
21
|
}
|
|
22
22
|
dir = parent;
|
|
23
23
|
}
|
|
24
|
-
throw new Error(`Could not locate prisma/schema.prisma near @codemation/host entry: ${entry}`);
|
|
24
|
+
throw new Error(`Could not locate prisma/schema.postgresql.prisma near @codemation/host entry: ${entry}`);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -9,11 +9,12 @@ export interface PrismaMigrateDeployRunner {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Runs `pnpm exec prisma migrate deploy` in the host package
|
|
12
|
+
* Runs `pnpm exec prisma migrate deploy --config prisma.config.ts` in the host package
|
|
13
|
+
* so the selected PostgreSQL or SQLite Prisma track is respected.
|
|
13
14
|
*/
|
|
14
15
|
export class PrismaMigrateDeployInvoker implements PrismaMigrateDeployRunner {
|
|
15
16
|
run(args: Readonly<{ hostPackageRoot: string; env: NodeJS.ProcessEnv }>): PrismaMigrateDeployResult {
|
|
16
|
-
const result = spawnSync("pnpm", ["exec", "prisma", "migrate", "deploy"], {
|
|
17
|
+
const result = spawnSync("pnpm", ["exec", "prisma", "migrate", "deploy", "--config", "prisma.config.ts"], {
|
|
17
18
|
cwd: args.hostPackageRoot,
|
|
18
19
|
env: args.env,
|
|
19
20
|
stdio: "inherit",
|
|
@@ -165,12 +165,9 @@ export class CliDevProxyServer {
|
|
|
165
165
|
);
|
|
166
166
|
return;
|
|
167
167
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
});
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
168
|
+
// Host-owned `/api/auth/*` is served by the disposable Hono runtime (same DB as other APIs).
|
|
169
|
+
// Do not route it to the Next UI — that used to cause gateway → Next → gateway loops when Next
|
|
170
|
+
// proxied auth back through CODEMATION_RUNTIME_DEV_URL.
|
|
174
171
|
if (pathname.startsWith("/api/")) {
|
|
175
172
|
const runtimeTarget = this.activeRuntime;
|
|
176
173
|
if (pathname === "/api/dev/bootstrap-summary" && runtimeTarget) {
|
|
@@ -49,6 +49,45 @@ export class DevCliBannerRenderer {
|
|
|
49
49
|
this.renderRuntimeSummary(summary);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* URL to open in the browser: packaged UI uses the CLI gateway port; watch-framework uses the
|
|
54
|
+
* Next.js dev port (PORT). When they differ, {@link devGatewayPort} is shown in the footer.
|
|
55
|
+
*/
|
|
56
|
+
renderGatewayListeningHint(
|
|
57
|
+
browserPort: number,
|
|
58
|
+
commandName: "dev" | "dev:plugin",
|
|
59
|
+
devMode: "packaged-ui" | "watch-framework",
|
|
60
|
+
devGatewayPort?: number,
|
|
61
|
+
): void {
|
|
62
|
+
const url = `http://127.0.0.1:${browserPort}`;
|
|
63
|
+
const footer =
|
|
64
|
+
devMode === "watch-framework"
|
|
65
|
+
? chalk.dim(
|
|
66
|
+
devGatewayPort !== undefined && devGatewayPort !== browserPort
|
|
67
|
+
? `The dev gateway (API + runtime) is at http://127.0.0.1:${devGatewayPort}. Open the URL above for the Next.js UI (HMR).`
|
|
68
|
+
: "Open the URL above for the Next.js UI.",
|
|
69
|
+
)
|
|
70
|
+
: chalk.dim(
|
|
71
|
+
`The UI is served through this URL (not the internal Next port). Framework UI work in the monorepo: \`codemation ${commandName} --watch-framework\`.`,
|
|
72
|
+
);
|
|
73
|
+
const bodyLines = [
|
|
74
|
+
chalk.whiteBright.bold("Codemation is running"),
|
|
75
|
+
"",
|
|
76
|
+
`${chalk.hex("#9ca3af")("Open in your browser:")} ${chalk.greenBright.underline(url)}`,
|
|
77
|
+
"",
|
|
78
|
+
footer,
|
|
79
|
+
];
|
|
80
|
+
const box = boxen(bodyLines.join("\n"), {
|
|
81
|
+
padding: { top: 0, bottom: 0, left: 1, right: 1 },
|
|
82
|
+
margin: { top: 1, bottom: 0 },
|
|
83
|
+
borderStyle: "double",
|
|
84
|
+
borderColor: "green",
|
|
85
|
+
title: chalk.bold("Codemation dev"),
|
|
86
|
+
titleAlignment: "center",
|
|
87
|
+
});
|
|
88
|
+
process.stdout.write(`${box}\n`);
|
|
89
|
+
}
|
|
90
|
+
|
|
52
91
|
/**
|
|
53
92
|
* Shown after hot reload / watcher restarts (no figlet).
|
|
54
93
|
*/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ChildProcess } from "node:child_process";
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
|
|
4
|
+
import type { DevNextStartupBannerLineFilter } from "./DevNextStartupBannerLineFilter";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Attaches to a spawned Next child process and forwards streams while dropping
|
|
8
|
+
* {@link DevNextStartupBannerLineFilter} matches (startup banner only).
|
|
9
|
+
*/
|
|
10
|
+
export class DevNextChildProcessOutputFilter {
|
|
11
|
+
constructor(private readonly lineFilter: DevNextStartupBannerLineFilter) {}
|
|
12
|
+
|
|
13
|
+
attach(child: ChildProcess): void {
|
|
14
|
+
this.pipeFilteredStream(child.stdout, process.stdout);
|
|
15
|
+
this.pipeFilteredStream(child.stderr, process.stderr);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private pipeFilteredStream(source: NodeJS.ReadableStream | null, sink: NodeJS.WritableStream): void {
|
|
19
|
+
if (!source) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const rl = createInterface({ input: source, crlfDelay: Infinity });
|
|
23
|
+
rl.on("line", (line) => {
|
|
24
|
+
if (this.lineFilter.shouldSuppress(line)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
sink.write(`${line}\n`);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -42,6 +42,7 @@ export class DevNextHostEnvironmentBuilder {
|
|
|
42
42
|
HOSTNAME: "127.0.0.1",
|
|
43
43
|
AUTH_SECRET: args.authSecret,
|
|
44
44
|
AUTH_URL: args.publicBaseUrl,
|
|
45
|
+
CODEMATION_PUBLIC_BASE_URL: args.publicBaseUrl,
|
|
45
46
|
CODEMATION_PUBLIC_WS_PORT: String(publicWebsocketPort),
|
|
46
47
|
NEXT_PUBLIC_CODEMATION_WS_PORT: String(publicWebsocketPort),
|
|
47
48
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filters noisy Next.js `next start` / `next dev` startup lines so the CLI can
|
|
3
|
+
* surface the Codemation gateway URL as the primary “where to browse” signal.
|
|
4
|
+
*/
|
|
5
|
+
export class DevNextStartupBannerLineFilter {
|
|
6
|
+
shouldSuppress(line: string): boolean {
|
|
7
|
+
const t = line.replace(/\r$/, "").trimEnd();
|
|
8
|
+
if (t.length === 0) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (/^\s*▲\s+Next\.js/.test(t)) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (/^\s*-\s+Local:\s+/.test(t)) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (/^\s*-\s+Network:\s+/.test(t)) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (/^\s*✓\s+Ready\b/.test(t)) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -11,7 +11,7 @@ export class CliDatabaseUrlDescriptor {
|
|
|
11
11
|
if (persistence.kind === "postgresql") {
|
|
12
12
|
return this.describeForDisplay(persistence.databaseUrl);
|
|
13
13
|
}
|
|
14
|
-
return `
|
|
14
|
+
return `SQLite (${persistence.databaseFilePath})`;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
describeForDisplay(databaseUrl: string | undefined): string {
|
|
@@ -40,7 +40,7 @@ export class UserAdminCliBootstrap {
|
|
|
40
40
|
}
|
|
41
41
|
if (loadResult.appConfig.persistence.kind === "none") {
|
|
42
42
|
throw new Error(
|
|
43
|
-
"Database persistence is not configured. Set CodemationConfig.runtime.database (postgresql URL or
|
|
43
|
+
"Database persistence is not configured. Set CodemationConfig.runtime.database (postgresql URL or SQLite file path).",
|
|
44
44
|
);
|
|
45
45
|
}
|
|
46
46
|
const session = await CodemationCliApplicationSession.open({
|