@cfbender/cesium 0.3.5
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/ARCHITECTURE.md +304 -0
- package/CHANGELOG.md +335 -0
- package/LICENSE +21 -0
- package/README.md +479 -0
- package/agents/cesium.md +39 -0
- package/assets/styleguide.html +857 -0
- package/package.json +61 -0
- package/src/cli/commands/ls.ts +186 -0
- package/src/cli/commands/open.ts +208 -0
- package/src/cli/commands/prune.ts +348 -0
- package/src/cli/commands/restart.ts +38 -0
- package/src/cli/commands/serve.ts +214 -0
- package/src/cli/commands/stop.ts +130 -0
- package/src/cli/commands/theme.ts +333 -0
- package/src/cli/index.ts +78 -0
- package/src/config.ts +94 -0
- package/src/index.ts +35 -0
- package/src/prompt/system-fragment.md +97 -0
- package/src/render/client-js.ts +316 -0
- package/src/render/controls.ts +302 -0
- package/src/render/critique.ts +360 -0
- package/src/render/extract.ts +83 -0
- package/src/render/scrub.ts +141 -0
- package/src/render/theme.ts +712 -0
- package/src/render/validate.ts +524 -0
- package/src/render/wrap.ts +165 -0
- package/src/server/api.ts +166 -0
- package/src/server/http.ts +195 -0
- package/src/server/lifecycle.ts +331 -0
- package/src/server/stop.ts +124 -0
- package/src/storage/index-cache.ts +71 -0
- package/src/storage/index-gen.ts +447 -0
- package/src/storage/lock.ts +108 -0
- package/src/storage/mutate.ts +396 -0
- package/src/storage/paths.ts +159 -0
- package/src/storage/project-summaries.ts +19 -0
- package/src/storage/theme-write.ts +19 -0
- package/src/storage/write.ts +75 -0
- package/src/tools/ask.ts +353 -0
- package/src/tools/critique.ts +66 -0
- package/src/tools/publish.ts +404 -0
- package/src/tools/stop.ts +53 -0
- package/src/tools/styleguide.ts +23 -0
- package/src/tools/wait.ts +192 -0
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cfbender/cesium",
|
|
3
|
+
"version": "0.3.5",
|
|
4
|
+
"description": "Beautiful self-contained HTML artifacts from your opencode agent.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Cody Bender",
|
|
7
|
+
"homepage": "https://github.com/cfbender/cesium#readme",
|
|
8
|
+
"bugs": "https://github.com/cfbender/cesium/issues",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/cfbender/cesium.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"opencode",
|
|
15
|
+
"agent",
|
|
16
|
+
"html",
|
|
17
|
+
"artifact",
|
|
18
|
+
"plugin",
|
|
19
|
+
"cli",
|
|
20
|
+
"claret"
|
|
21
|
+
],
|
|
22
|
+
"bin": {
|
|
23
|
+
"cesium": "./src/cli/index.ts"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "src/index.ts",
|
|
27
|
+
"files": [
|
|
28
|
+
"src",
|
|
29
|
+
"assets/styleguide.html",
|
|
30
|
+
"agents",
|
|
31
|
+
"ARCHITECTURE.md",
|
|
32
|
+
"CHANGELOG.md"
|
|
33
|
+
],
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"bun": ">=1.0.0"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"test": "bun test",
|
|
42
|
+
"typecheck": "tsc --noEmit",
|
|
43
|
+
"format": "oxfmt .",
|
|
44
|
+
"format:check": "oxfmt --check .",
|
|
45
|
+
"lint": "oxlint",
|
|
46
|
+
"examples:bake": "bun run scripts/bake-examples.ts && oxfmt examples",
|
|
47
|
+
"cli": "bun run src/cli/index.ts",
|
|
48
|
+
"prepublishOnly": "bun run typecheck && bun test"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@opencode-ai/plugin": "latest",
|
|
52
|
+
"nanoid": "^5.0.0",
|
|
53
|
+
"parse5": "^7.1.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/bun": "latest",
|
|
57
|
+
"oxfmt": "^0.48.0",
|
|
58
|
+
"oxlint": "^1.63.0",
|
|
59
|
+
"typescript": "^5.4.0"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// cesium ls — list artifacts for current project (or all).
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { execSync } from "node:child_process";
|
|
6
|
+
import { loadConfig, type CesiumConfig } from "../../config.ts";
|
|
7
|
+
import { loadIndex, type IndexEntry } from "../../storage/index-cache.ts";
|
|
8
|
+
import { deriveProjectIdentity } from "../../storage/paths.ts";
|
|
9
|
+
|
|
10
|
+
export interface LsContext {
|
|
11
|
+
stdout: { write: (s: string) => void };
|
|
12
|
+
stderr: { write: (s: string) => void };
|
|
13
|
+
cwd: string;
|
|
14
|
+
loadConfig?: () => CesiumConfig;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function defaultCtx(): LsContext {
|
|
18
|
+
return {
|
|
19
|
+
stdout: process.stdout,
|
|
20
|
+
stderr: process.stderr,
|
|
21
|
+
cwd: process.cwd(),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Truncate a string to maxLen, appending "…" if truncated. */
|
|
26
|
+
function trunc(s: string, maxLen: number): string {
|
|
27
|
+
if (s.length <= maxLen) return s;
|
|
28
|
+
return s.slice(0, maxLen - 1) + "…";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Format an ISO date as "YYYY-MM-DDTHH:MM:SS" (no ms, no tz suffix). */
|
|
32
|
+
function fmtDate(iso: string): string {
|
|
33
|
+
return iso.slice(0, 19);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Derive SUPER column value for an entry. */
|
|
37
|
+
function superCol(entry: IndexEntry): string {
|
|
38
|
+
const parts: string[] = [];
|
|
39
|
+
if (entry.supersededBy !== null) {
|
|
40
|
+
parts.push(`→ ${entry.supersededBy.slice(0, 6)}`);
|
|
41
|
+
}
|
|
42
|
+
if (entry.supersedes !== null) {
|
|
43
|
+
parts.push(`← ${entry.supersedes.slice(0, 6)}`);
|
|
44
|
+
}
|
|
45
|
+
return parts.join(" ");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getGitRemote(cwd: string): string | null {
|
|
49
|
+
try {
|
|
50
|
+
const result = execSync("git config --get remote.origin.url", {
|
|
51
|
+
cwd,
|
|
52
|
+
encoding: "utf8",
|
|
53
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
54
|
+
}).trim();
|
|
55
|
+
return result || null;
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function lsCommand(argv: string[], ctx?: Partial<LsContext>): Promise<number> {
|
|
62
|
+
const resolved: LsContext = { ...defaultCtx(), ...ctx };
|
|
63
|
+
|
|
64
|
+
let values: {
|
|
65
|
+
all: boolean;
|
|
66
|
+
json: boolean;
|
|
67
|
+
limit: string | undefined;
|
|
68
|
+
help: boolean;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const parsed = parseArgs({
|
|
73
|
+
args: argv,
|
|
74
|
+
options: {
|
|
75
|
+
all: { type: "boolean", short: "a", default: false },
|
|
76
|
+
json: { type: "boolean", default: false },
|
|
77
|
+
limit: { type: "string", short: "n" },
|
|
78
|
+
help: { type: "boolean", short: "h", default: false },
|
|
79
|
+
},
|
|
80
|
+
allowPositionals: false,
|
|
81
|
+
strict: true,
|
|
82
|
+
});
|
|
83
|
+
values = parsed.values as typeof values;
|
|
84
|
+
} catch (err) {
|
|
85
|
+
const e = err as Error;
|
|
86
|
+
resolved.stderr.write(`cesium ls: ${e.message}\n`);
|
|
87
|
+
resolved.stderr.write(`Usage: cesium ls [--all] [--json] [--limit N]\n`);
|
|
88
|
+
return 1;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (values.help) {
|
|
92
|
+
resolved.stdout.write(
|
|
93
|
+
[
|
|
94
|
+
"Usage: cesium ls [options]",
|
|
95
|
+
"",
|
|
96
|
+
"Options:",
|
|
97
|
+
" --all, -a Show artifacts for all projects (default: current project only)",
|
|
98
|
+
" --json Output as JSON array",
|
|
99
|
+
" --limit, -n N Show at most N most recent artifacts (default: 50)",
|
|
100
|
+
" --help, -h Show this help message",
|
|
101
|
+
"",
|
|
102
|
+
].join("\n"),
|
|
103
|
+
);
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const limitRaw = values.limit !== undefined ? parseInt(values.limit, 10) : 50;
|
|
108
|
+
if (isNaN(limitRaw) || limitRaw < 1) {
|
|
109
|
+
resolved.stderr.write(`cesium ls: --limit must be a positive integer\n`);
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
const limit = limitRaw;
|
|
113
|
+
|
|
114
|
+
// Load config
|
|
115
|
+
const cfg = (resolved.loadConfig ?? loadConfig)();
|
|
116
|
+
|
|
117
|
+
// Determine which index.json to read
|
|
118
|
+
let jsonPath: string;
|
|
119
|
+
if (values.all) {
|
|
120
|
+
jsonPath = join(cfg.stateDir, "index.json");
|
|
121
|
+
} else {
|
|
122
|
+
const gitRemote = getGitRemote(resolved.cwd);
|
|
123
|
+
const identity = deriveProjectIdentity({ cwd: resolved.cwd, gitRemote });
|
|
124
|
+
jsonPath = join(cfg.stateDir, "projects", identity.slug, "index.json");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let entries: IndexEntry[];
|
|
128
|
+
try {
|
|
129
|
+
entries = await loadIndex(jsonPath);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
const e = err as Error;
|
|
132
|
+
resolved.stderr.write(`cesium ls: failed to read index: ${e.message}\n`);
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Already sorted newest-first by loadIndex / appendEntry; apply limit
|
|
137
|
+
const limited = entries.slice(0, limit);
|
|
138
|
+
|
|
139
|
+
if (values.json) {
|
|
140
|
+
resolved.stdout.write(JSON.stringify(limited, null, 2) + "\n");
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Table output
|
|
145
|
+
if (limited.length === 0) {
|
|
146
|
+
resolved.stdout.write("No artifacts found.\n");
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const COL_ID = 6;
|
|
151
|
+
const COL_KIND = 10;
|
|
152
|
+
const COL_TITLE = 37;
|
|
153
|
+
const COL_DATE = 19;
|
|
154
|
+
|
|
155
|
+
const header =
|
|
156
|
+
"ID".padEnd(COL_ID) +
|
|
157
|
+
" " +
|
|
158
|
+
"KIND".padEnd(COL_KIND) +
|
|
159
|
+
" " +
|
|
160
|
+
"TITLE".padEnd(COL_TITLE) +
|
|
161
|
+
" " +
|
|
162
|
+
"CREATED".padEnd(COL_DATE) +
|
|
163
|
+
" " +
|
|
164
|
+
"SUPER";
|
|
165
|
+
|
|
166
|
+
const sep = "─".repeat(header.length);
|
|
167
|
+
|
|
168
|
+
resolved.stdout.write(header + "\n");
|
|
169
|
+
resolved.stdout.write(sep + "\n");
|
|
170
|
+
|
|
171
|
+
for (const e of limited) {
|
|
172
|
+
const row =
|
|
173
|
+
e.id.slice(0, COL_ID).padEnd(COL_ID) +
|
|
174
|
+
" " +
|
|
175
|
+
trunc(e.kind, COL_KIND).padEnd(COL_KIND) +
|
|
176
|
+
" " +
|
|
177
|
+
trunc(e.title, COL_TITLE).padEnd(COL_TITLE) +
|
|
178
|
+
" " +
|
|
179
|
+
fmtDate(e.createdAt).padEnd(COL_DATE) +
|
|
180
|
+
" " +
|
|
181
|
+
superCol(e);
|
|
182
|
+
resolved.stdout.write(row + "\n");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// cesium open — find an artifact by id prefix and open it in the browser.
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { platform } from "node:os";
|
|
7
|
+
import { loadConfig, type CesiumConfig } from "../../config.ts";
|
|
8
|
+
import { loadIndex } from "../../storage/index-cache.ts";
|
|
9
|
+
import { pathsFor } from "../../storage/paths.ts";
|
|
10
|
+
import {
|
|
11
|
+
ensureRunning,
|
|
12
|
+
readPidFile,
|
|
13
|
+
isAlive,
|
|
14
|
+
type LifecycleConfig,
|
|
15
|
+
} from "../../server/lifecycle.ts";
|
|
16
|
+
import { resolveDisplayHost } from "../../tools/publish.ts";
|
|
17
|
+
|
|
18
|
+
export interface OpenContext {
|
|
19
|
+
stdout: { write: (s: string) => void };
|
|
20
|
+
stderr: { write: (s: string) => void };
|
|
21
|
+
loadConfig?: () => CesiumConfig;
|
|
22
|
+
opener?: (url: string) => Promise<void>;
|
|
23
|
+
ensureRunning?: (cfg: LifecycleConfig) => Promise<{ port: number; url: string } | null>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function defaultCtx(): OpenContext {
|
|
27
|
+
return {
|
|
28
|
+
stdout: process.stdout,
|
|
29
|
+
stderr: process.stderr,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Default OS-native URL opener. */
|
|
34
|
+
async function defaultOpener(url: string): Promise<void> {
|
|
35
|
+
const os = platform();
|
|
36
|
+
let cmd: string;
|
|
37
|
+
let args: string[];
|
|
38
|
+
|
|
39
|
+
if (os === "darwin") {
|
|
40
|
+
cmd = "open";
|
|
41
|
+
args = [url];
|
|
42
|
+
} else if (os === "linux") {
|
|
43
|
+
cmd = "xdg-open";
|
|
44
|
+
args = [url];
|
|
45
|
+
} else {
|
|
46
|
+
// Windows and others: not supported in v1
|
|
47
|
+
throw new Error(
|
|
48
|
+
"cesium open: browser launch is not supported on this platform. Use --print to get the URL.",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await new Promise<void>((resolve, reject) => {
|
|
53
|
+
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
54
|
+
child.unref();
|
|
55
|
+
child.on("error", reject);
|
|
56
|
+
child.on("spawn", resolve);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Try to resolve an http URL for the artifact. Returns null if server unavailable. */
|
|
61
|
+
async function tryGetHttpUrl(
|
|
62
|
+
cfg: CesiumConfig,
|
|
63
|
+
serverPath: string,
|
|
64
|
+
runEnsureRunning: (cfg: LifecycleConfig) => Promise<{ port: number; url: string } | null>,
|
|
65
|
+
): Promise<string | null> {
|
|
66
|
+
// First check existing PID file (fast path — no new server start needed for `open`)
|
|
67
|
+
const pidFilePath = join(cfg.stateDir, ".server.pid");
|
|
68
|
+
const pidContent = readPidFile(pidFilePath);
|
|
69
|
+
if (pidContent !== null && isAlive(pidContent.pid)) {
|
|
70
|
+
const displayHost = resolveDisplayHost(pidContent.hostname);
|
|
71
|
+
return `http://${displayHost}:${pidContent.port}${serverPath}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Try to start server
|
|
75
|
+
try {
|
|
76
|
+
const info = await runEnsureRunning({
|
|
77
|
+
stateDir: cfg.stateDir,
|
|
78
|
+
port: cfg.port,
|
|
79
|
+
portMax: cfg.portMax,
|
|
80
|
+
idleTimeoutMs: cfg.idleTimeoutMs,
|
|
81
|
+
hostname: cfg.hostname,
|
|
82
|
+
});
|
|
83
|
+
if (info !== null) {
|
|
84
|
+
const displayHost = resolveDisplayHost(cfg.hostname);
|
|
85
|
+
return `http://${displayHost}:${info.port}${serverPath}`;
|
|
86
|
+
}
|
|
87
|
+
} catch {
|
|
88
|
+
// server failed to start — fall back to file://
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function openCommand(argv: string[], ctx?: Partial<OpenContext>): Promise<number> {
|
|
94
|
+
const resolved: OpenContext = { ...defaultCtx(), ...ctx };
|
|
95
|
+
|
|
96
|
+
let values: { print: boolean; help: boolean };
|
|
97
|
+
let positionals: string[];
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const parsed = parseArgs({
|
|
101
|
+
args: argv,
|
|
102
|
+
options: {
|
|
103
|
+
print: { type: "boolean", default: false },
|
|
104
|
+
help: { type: "boolean", short: "h", default: false },
|
|
105
|
+
},
|
|
106
|
+
allowPositionals: true,
|
|
107
|
+
strict: true,
|
|
108
|
+
});
|
|
109
|
+
values = parsed.values as typeof values;
|
|
110
|
+
positionals = parsed.positionals;
|
|
111
|
+
} catch (err) {
|
|
112
|
+
const e = err as Error;
|
|
113
|
+
resolved.stderr.write(`cesium open: ${e.message}\n`);
|
|
114
|
+
resolved.stderr.write(`Usage: cesium open <id-prefix> [--print]\n`);
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (values.help) {
|
|
119
|
+
resolved.stdout.write(
|
|
120
|
+
[
|
|
121
|
+
"Usage: cesium open <id-prefix> [options]",
|
|
122
|
+
"",
|
|
123
|
+
"Options:",
|
|
124
|
+
" --print Print the URL instead of opening in the browser",
|
|
125
|
+
" --help, -h Show this help message",
|
|
126
|
+
"",
|
|
127
|
+
"Notes:",
|
|
128
|
+
" Browser launch is supported on macOS (open) and Linux (xdg-open).",
|
|
129
|
+
" On Windows, use --print to get the URL.",
|
|
130
|
+
"",
|
|
131
|
+
].join("\n"),
|
|
132
|
+
);
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const idPrefix = positionals[0];
|
|
137
|
+
if (idPrefix === undefined || idPrefix.length === 0) {
|
|
138
|
+
resolved.stderr.write(`cesium open: missing required argument <id-prefix>\n`);
|
|
139
|
+
resolved.stderr.write(`Usage: cesium open <id-prefix> [--print]\n`);
|
|
140
|
+
return 1;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const prefixLower = idPrefix.toLowerCase();
|
|
144
|
+
|
|
145
|
+
const cfg = (resolved.loadConfig ?? loadConfig)();
|
|
146
|
+
|
|
147
|
+
// Search global index for matches
|
|
148
|
+
const globalJsonPath = join(cfg.stateDir, "index.json");
|
|
149
|
+
let allEntries;
|
|
150
|
+
try {
|
|
151
|
+
allEntries = await loadIndex(globalJsonPath);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
const e = err as Error;
|
|
154
|
+
resolved.stderr.write(`cesium open: failed to read index: ${e.message}\n`);
|
|
155
|
+
return 1;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const matches = allEntries.filter((e) => e.id.toLowerCase().startsWith(prefixLower));
|
|
159
|
+
|
|
160
|
+
if (matches.length === 0) {
|
|
161
|
+
resolved.stderr.write(`cesium open: no artifact found with id prefix "${idPrefix}"\n`);
|
|
162
|
+
return 1;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (matches.length > 1) {
|
|
166
|
+
resolved.stderr.write(
|
|
167
|
+
`cesium open: ambiguous prefix "${idPrefix}" — ${matches.length} matches:\n`,
|
|
168
|
+
);
|
|
169
|
+
for (const m of matches) {
|
|
170
|
+
resolved.stderr.write(` ${m.id} ${m.title} (${m.kind})\n`);
|
|
171
|
+
}
|
|
172
|
+
return 2;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const entry = matches[0];
|
|
176
|
+
if (entry === undefined) {
|
|
177
|
+
// Unreachable: guarded by matches.length === 1, but satisfies the type checker
|
|
178
|
+
resolved.stderr.write(`cesium open: internal error — no match\n`);
|
|
179
|
+
return 1;
|
|
180
|
+
}
|
|
181
|
+
const paths = pathsFor({
|
|
182
|
+
stateDir: cfg.stateDir,
|
|
183
|
+
projectSlug: entry.projectSlug,
|
|
184
|
+
filename: entry.filename,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Resolve URL
|
|
188
|
+
const runEnsureRunning = resolved.ensureRunning ?? ensureRunning;
|
|
189
|
+
const httpUrl = await tryGetHttpUrl(cfg, paths.serverPath, runEnsureRunning);
|
|
190
|
+
const url = httpUrl ?? paths.fileUrl;
|
|
191
|
+
|
|
192
|
+
if (values.print) {
|
|
193
|
+
resolved.stdout.write(url + "\n");
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const open = resolved.opener ?? defaultOpener;
|
|
198
|
+
try {
|
|
199
|
+
await open(url);
|
|
200
|
+
} catch (err) {
|
|
201
|
+
const e = err as Error;
|
|
202
|
+
resolved.stderr.write(`cesium open: ${e.message}\n`);
|
|
203
|
+
resolved.stdout.write(`URL: ${url}\n`);
|
|
204
|
+
return 1;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return 0;
|
|
208
|
+
}
|