Skip to content

fix: inspector #828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions examples/chat-room/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@
"private": true,
"type": "module",
"scripts": {
"dev": "npx @actor-core/cli@latest dev",
"check-types": "tsc --noEmit",
"test": "vitest run"
},
"devDependencies": {
"@types/node": "^22.13.9",
"@types/prompts": "^2",
"actor-core": "workspace:*",
"@actor-core/cli": "workspace:*",
"prompts": "^2.4.2",
"tsx": "^3.12.7",
"typescript": "^5.5.2",
"vitest": "^3.0.9"
},
"example": {
"platforms": [
"*"
],
"platforms": ["*"],
"actors": {
"chat-room": "src/chat-room.ts"
}
Expand Down
6 changes: 3 additions & 3 deletions examples/counter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
"private": true,
"type": "module",
"scripts": {
"dev": "npx @actor-core/cli@latest dev",
"check-types": "tsc --noEmit",
"test": "vitest run"
},
"devDependencies": {
"@types/node": "^22.13.9",
"actor-core": "workspace:*",
"@actor-core/cli": "workspace:*",
"tsx": "^3.12.7",
"typescript": "^5.7.3",
"vitest": "^3.0.9"
},
"example": {
"platforms": [
"*"
]
"platforms": ["*"]
}
}
3 changes: 3 additions & 0 deletions packages/actor-core-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@
"check-types": "tsc --noEmit"
},
"dependencies": {
"@actor-core/nodejs": "workspace:^",
"@sentry/profiling-node": "^9.3.0",
"bundle-require": "^5.1.0",
"chokidar": "^4.0.3",
"esbuild": "^0.25.1",
"open": "^10.1.0",
"yoga-wasm-web": "0.3.3"
},
"devDependencies": {
Expand Down
3 changes: 2 additions & 1 deletion packages/actor-core-cli/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { PACKAGE_JSON } from "./macros" with { type: "macro" };
import { create, deploy, program } from "./mod";
import { create, deploy, dev, program } from "./mod";

export default program
.name(PACKAGE_JSON.name)
.version(PACKAGE_JSON.version)
.description(PACKAGE_JSON.description)
.addCommand(deploy)
.addCommand(create)
.addCommand(dev)
.parse();
37 changes: 4 additions & 33 deletions packages/actor-core-cli/src/commands/deploy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import semver from "semver";
import which from "which";
import { MIN_RIVET_CLI_VERSION } from "../constants";
import { VERSION } from "../macros" with { type: "macro" };
import { isBundleError, isNotFoundError, validateConfig } from "../utils/mod";
import { workflow } from "../workflow";
import { z } from "zod";
import { RivetClient } from "@rivet-gg/api";
Expand All @@ -17,6 +16,7 @@ import {
createRivetApi,
getServiceToken,
} from "../utils/rivet-api";
import { validateConfigTask } from "../workflows/validate-config";

export const deploy = new Command()
.name("deploy")
Expand Down Expand Up @@ -46,36 +46,7 @@ export const deploy = new Command()
const { config, cli } = yield* ctx.task(
"Prepare",
async function* (ctx) {
const config = yield* ctx.task("Validate config", async () => {
try {
return await validateConfig(cwd);
} catch (error) {
const indexFile = path.relative(
process.cwd(),
path.join(cwd, "src", "index.ts"),
);
if (isBundleError(error)) {
throw ctx.error(
`Could not parse Actors index file (${indexFile})\n${error.details}`,
{
hint: "Please make sure that the file exists and does not have any syntax errors.",
},
);
} else if (isNotFoundError(error)) {
throw ctx.error(
`Could not find Actors index file (${indexFile})`,
{
hint: "Please make sure that the file exists and not empty.",
},
);
} else {
console.error(error);
throw ctx.error("Failed to validate config.", {
hint: "Please check the logs above for more information.",
});
}
}
});
const config = yield* validateConfigTask(ctx, cwd);

const cli = yield* ctx.task(
"Locale rivet-cli",
Expand All @@ -92,7 +63,7 @@ export const deploy = new Command()

if (cliLocation) {
// check version
const { stdout } = yield* ctx.$`${cliLocation} --version`;
const { stdout } = yield* exec`${cliLocation} --version`;
const semVersion = semver.coerce(
stdout.split("\n")[2].split(" ")[1].trim(),
);
Expand Down Expand Up @@ -152,7 +123,7 @@ export const deploy = new Command()

const envName =
opts.env ??
(yield* ctx.task("Select environment", async function* () {
(yield* ctx.task("Select environment", async function* (ctx) {
const { stdout } = await exec`${cli} env ls --json`;
const envs = JSON.parse(stdout);
return yield* ctx.prompt("Select environment", {
Expand Down
103 changes: 103 additions & 0 deletions packages/actor-core-cli/src/commands/dev.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import * as path from "node:path";
import { Argument, Command, Option } from "commander";
import { workflow } from "../workflow";

import { validateConfigTask } from "../workflows/validate-config";
import chokidar from "chokidar";
import { Text } from "ink";
import open from "open";
import { withResolvers } from "../utils/mod";
import { spawn } from "node:child_process";

export const dev = new Command()
.name("dev")
.description("Run locally your ActorCore project.")
.addArgument(new Argument("[path]", "Location of the project"))
.addOption(
new Option("-p, --port [port]", "Specify which platform to use").default(
"6420",
),
)
.addOption(
new Option("--open", "Open the browser with ActorCore Studio").default(
true,
),
)
.option("--no-open", "Do not open the browser with ActorCore Studio")
.action(action);

export async function action(
cmdPath = ".",
opts: {
port?: string;
open?: boolean;
} = {},
) {
const cwd = path.join(process.cwd(), cmdPath);
await workflow("Run locally your ActorCore project", async function* (ctx) {
if (opts.open) {
open(
process.env._ACTOR_CORE_CLI_DEV
? "http://localhost:43708"
: "http://studio.actorcore.org",
);
}

const watcher = chokidar.watch(cwd, {
awaitWriteFinish: true,
ignoreInitial: true,
ignored: (path) => path.includes("node_modules"),
});

function createServer() {
return spawn(
process.execPath,
[
path.join(
path.dirname(require.resolve("@actor-core/cli")),
"server-entry.js",
),
],
{ env: { ...process.env, PORT: opts.port }, cwd },
);
}

let server: ReturnType<typeof spawn> | undefined = undefined;
let lock: ReturnType<typeof withResolvers> = withResolvers();

function createLock() {
if (lock) {
lock.resolve(undefined);
}
lock = withResolvers();
}

watcher.on("all", async (_, path) => {
if (path.includes("node_modules") || path.includes("/.")) return;

server?.kill();
});

while (true) {
yield* validateConfigTask(ctx, cwd);
server = createServer();
createLock();

server?.addListener("exit", () => {
lock.resolve(undefined);
});

server?.addListener("close", () => {
lock.resolve(undefined);
});

yield* ctx.task(
"Watching for changes...",
async () => {
await lock.promise;
},
{ success: <Text dimColor> (Changes detected, restarting!)</Text> },
);
}
}).render();
}
1 change: 1 addition & 0 deletions packages/actor-core-cli/src/mod.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import "./instrument";
export { deploy } from "./commands/deploy";
export { create, action as createAction } from "./commands/create";
export { dev } from "./commands/dev";
export { program } from "commander";
export default {};
17 changes: 17 additions & 0 deletions packages/actor-core-cli/src/server-entry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { validateConfig } from "./utils/config";
import { serve } from "@actor-core/nodejs";

async function run() {
const config = await validateConfig(process.cwd());
config.app.config.inspector = {
enabled: true,
};
serve(config.app, {
port: Number.parseInt(process.env.PORT || "6420", 10) || 6420,
});
}

run().catch((err) => {
console.error(err);
process.exit(1);
});
21 changes: 14 additions & 7 deletions packages/actor-core-cli/src/ui/Workflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { ExecaError } from "execa";
import { Box, Text, type TextProps } from "ink";
import Spinner from "ink-spinner";
import { useState } from "react";
import { type ReactNode, useState } from "react";
import stripAnsi from "strip-ansi";
import { type WorkflowAction, WorkflowError } from "../workflow";

Expand Down Expand Up @@ -63,22 +63,23 @@ function Tasks({
interactive?: boolean;
}) {
const currentTasks = tasks.filter((task) => task.meta.parent === parent);

if (currentTasks.length === 0) {
return null;
}
return (
<Box flexDirection="column">
{currentTasks.map((task) => (
<Box
key={task.meta.name}
key={task.meta.id}
flexDirection="column"
marginLeft={parent && parentOpts?.showLabel !== false ? 2 : 0}
>
<Task task={task} parent={parent} interactive={interactive} />
{"status" in task && task.status === "done" ? null : (
{"status" in task && task.status === "done" && interactive ? null : (
<Tasks
tasks={tasks}
parent={task.meta.name}
parent={task.meta.id}
parentOpts={task.meta.opts}
interactive={interactive}
/>
Expand Down Expand Up @@ -171,7 +172,11 @@ export function Task({
<>
{task.meta.opts?.showLabel === false &&
task.status !== "error" ? null : (
<Status value={task.status} interactive={interactive}>
<Status
value={task.status}
interactive={interactive}
done={task.meta.opts?.success}
>
{task.meta.name}
</Status>
)}
Expand Down Expand Up @@ -209,10 +214,12 @@ export function Status({
value,
children,
interactive,
done = <Text dimColor> (Done)</Text>,
...rest
}: TextProps & {
value: WorkflowAction.Progress["status"];
interactive?: boolean;
done?: ReactNode;
}) {
return (
<Text {...rest}>
Expand All @@ -229,7 +236,7 @@ export function Status({
</Text>{" "}
{children}
{value === "running" && !interactive ? <Text>…</Text> : null}
{value === "done" ? <Text dimColor> (Done)</Text> : null}
{value === "done" ? done : null}
</Text>
);
}
Expand Down Expand Up @@ -307,7 +314,7 @@ export function Logs({ logs }: { logs: WorkflowAction.Log[] }) {
if (log.type === "warn") {
return (
<Text key={i} color="yellow">
<Text>⚠ </Text>
<Text>⚠ </Text>
{log.message}
</Text>
);
Expand Down
Loading
Loading