@rivus/agent 0.1.1 → 0.4.0

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/cli.js CHANGED
@@ -1,17 +1,520 @@
1
1
  #!/usr/bin/env node
2
- import { t as runRivusDaemonCli } from "./rivus-daemon-cli.js";
3
- import { pathToFileURL } from "node:url";
4
- import { resolve } from "node:path";
2
+ import { C as resolveNodeRivusPluginModulePath, D as resolveFeishuEndpointCredentials, O as loadMergedLocalEnvFile, T as loadRivusDeploymentManifest, j as validateRivusDeploymentManifest, t as runRivusDaemonCli } from "./rivus-daemon-cli.js";
5
3
  import { Effect } from "effect";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
+ import { lstat, mkdir, readFile, rmdir, stat, unlink, writeFile } from "node:fs/promises";
7
+ //#region src/infrastructure/project/rivus-project-doctor.ts
8
+ const REQUIRED_FILES = Object.freeze([
9
+ "package.json",
10
+ "rivus.bootstrap.ts",
11
+ "rivus.config.json"
12
+ ]);
13
+ const REQUIRED_DEPENDENCIES = Object.freeze([
14
+ "@rivus/agent",
15
+ "@earendil-works/pi-coding-agent",
16
+ "@larksuiteoapi/node-sdk"
17
+ ]);
18
+ async function diagnoseRivusProject(options) {
19
+ const directory = resolve(options.directory);
20
+ const checks = [];
21
+ checks.push(checkNode(options.nodeVersion));
22
+ checks.push(await checkFiles(directory));
23
+ checks.push(await checkDependencies(directory));
24
+ const manifestResult = await checkManifest(directory);
25
+ checks.push(manifestResult.check);
26
+ const envFilePath = resolve(directory, options.envFilePath ?? ".env.local");
27
+ checks.push(await checkCredentials(manifestResult.manifest, envFilePath, options.env));
28
+ return Object.freeze({
29
+ checks: Object.freeze(checks),
30
+ directory,
31
+ ready: checks.every(({ status }) => status === "pass")
32
+ });
33
+ }
34
+ function checkNode(version) {
35
+ const [major, minor] = version.split(".").map(Number);
36
+ if (major === 24 && Number.isInteger(minor) && minor >= 11) return {
37
+ message: `Node.js ${version} satisfies the supported ^24.11 runtime`,
38
+ name: "node",
39
+ status: "pass"
40
+ };
41
+ return {
42
+ message: `Node.js 24.11 or newer on major 24 is required; current version is ${version}`,
43
+ name: "node",
44
+ status: "fail"
45
+ };
46
+ }
47
+ async function checkFiles(directory) {
48
+ const missing = await missingRegularFiles(directory, REQUIRED_FILES);
49
+ return missing.length === 0 ? {
50
+ message: "required project files are present",
51
+ name: "files",
52
+ status: "pass"
53
+ } : {
54
+ message: `required project files are missing: ${missing.join(", ")}`,
55
+ name: "files",
56
+ status: "fail"
57
+ };
58
+ }
59
+ async function checkDependencies(directory) {
60
+ const packageFiles = REQUIRED_DEPENDENCIES.map((name) => join("node_modules", ...name.split("/"), "package.json"));
61
+ const missingIndexes = new Set((await missingRegularFiles(directory, packageFiles)).map((path) => packageFiles.indexOf(path)));
62
+ const missing = REQUIRED_DEPENDENCIES.filter((_, index) => missingIndexes.has(index));
63
+ return missing.length === 0 ? {
64
+ message: "Rivus, Pi, and Feishu dependencies are installed",
65
+ name: "dependencies",
66
+ status: "pass"
67
+ } : {
68
+ message: `run npm install; missing local dependencies: ${missing.join(", ")}`,
69
+ name: "dependencies",
70
+ status: "fail"
71
+ };
72
+ }
73
+ async function checkManifest(directory) {
74
+ try {
75
+ const manifest = await loadRivusDeploymentManifest(join(directory, "rivus.config.json"));
76
+ validateRivusDeploymentManifest(manifest);
77
+ const missingModules = [];
78
+ for (const plugin of manifest.plugins) try {
79
+ await resolveNodeRivusPluginModulePath({
80
+ deploymentRoot: directory,
81
+ module: plugin.module,
82
+ pluginId: plugin.id
83
+ });
84
+ } catch {
85
+ missingModules.push(plugin.module);
86
+ }
87
+ if (missingModules.length > 0) return { check: {
88
+ message: `manifest Plugin modules are missing: ${missingModules.join(", ")}`,
89
+ name: "manifest",
90
+ status: "fail"
91
+ } };
92
+ return {
93
+ check: {
94
+ message: "deployment manifest is valid",
95
+ name: "manifest",
96
+ status: "pass"
97
+ },
98
+ manifest
99
+ };
100
+ } catch (error) {
101
+ return { check: {
102
+ message: `deployment manifest is invalid: ${error instanceof Error ? error.message : String(error)}`,
103
+ name: "manifest",
104
+ status: "fail"
105
+ } };
106
+ }
107
+ }
108
+ async function checkCredentials(manifest, envFilePath, env) {
109
+ let mergedEnv;
110
+ try {
111
+ mergedEnv = await loadMergedLocalEnvFile(envFilePath, env);
112
+ } catch (error) {
113
+ return {
114
+ message: `required env file is unavailable at ${envFilePath}: ${error instanceof Error ? error.message : String(error)}`,
115
+ name: "credentials",
116
+ status: "fail"
117
+ };
118
+ }
119
+ if (!manifest) return {
120
+ message: "enabled Endpoint credentials cannot be checked until the deployment manifest is valid",
121
+ name: "credentials",
122
+ status: "fail"
123
+ };
124
+ try {
125
+ for (const endpoint of manifest.endpoints.filter(({ enabled }) => enabled)) resolveFeishuEndpointCredentials(endpoint.credentialRef, mergedEnv);
126
+ return {
127
+ message: "enabled Endpoint credential references resolve",
128
+ name: "credentials",
129
+ status: "pass"
130
+ };
131
+ } catch (error) {
132
+ return {
133
+ message: `enabled Endpoint credentials are incomplete: ${error instanceof Error ? error.message : String(error)}`,
134
+ name: "credentials",
135
+ status: "fail"
136
+ };
137
+ }
138
+ }
139
+ async function missingRegularFiles(directory, paths) {
140
+ const missing = [];
141
+ for (const path of paths) try {
142
+ if (!(await stat(resolve(directory, path))).isFile()) missing.push(path);
143
+ } catch (error) {
144
+ if (!isMissingPath$1(error)) throw error;
145
+ missing.push(path);
146
+ }
147
+ return missing;
148
+ }
149
+ function isMissingPath$1(error) {
150
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
151
+ }
152
+ //#endregion
153
+ //#region src/infrastructure/project/rivus-project-initializer.ts
154
+ const TEMPLATE_FILES = Object.freeze({
155
+ "current-weather.mjs": "current-weather.mjs",
156
+ "https-response-reader.mjs": "https-response-reader.mjs",
157
+ "rivus-agents.plugin.mjs": "rivus-starter.plugin.mjs",
158
+ "rivus.bootstrap.ts": "pi-feishu-deployment.bootstrap.ts"
159
+ });
160
+ async function initializeRivusProject(options) {
161
+ const directory = resolve(options.directory);
162
+ const manifest = await readPackageManifest(options.packageManifestPath);
163
+ const files = /* @__PURE__ */ new Map([
164
+ [".env.example", environmentTemplate()],
165
+ [".gitignore", ".env.local\n.rivus/\nnode_modules/\n"],
166
+ ["deploy/launchd/com.rivus.agent.plist", launchdService(directory, options.nodeExecutable)],
167
+ ["deploy/systemd/rivus.service", systemdService(directory, options.nodeExecutable)],
168
+ ["package.json", projectPackageJson(directory, manifest)],
169
+ ["rivus.config.json", deploymentManifest()]
170
+ ]);
171
+ for (const [target, source] of Object.entries(TEMPLATE_FILES)) files.set(target, await readFile(join(options.templateDirectory, source), "utf8"));
172
+ const paths = [...files.keys()].sort();
173
+ await assertSafeProjectAncestors(directory, paths);
174
+ const conflicts = await findConflicts(directory, paths);
175
+ if (conflicts.length > 0) throw new Error(`Rivus project initialization refused; refusing to overwrite: ${conflicts.join(", ")}`);
176
+ const createdDirectories = [];
177
+ const createdFiles = [];
178
+ const writeProjectFile = options.writeProjectFile ?? writeExclusiveProjectFile;
179
+ try {
180
+ for (const path of paths) {
181
+ const destination = join(directory, path);
182
+ await ensureDirectory(dirname(destination), directory, createdDirectories);
183
+ await assertSafeProjectAncestors(directory, [path]);
184
+ await writeProjectFile(destination, files.get(path));
185
+ createdFiles.push(destination);
186
+ }
187
+ } catch (error) {
188
+ const rollbackErrors = await rollbackCreatedPaths(createdFiles, createdDirectories);
189
+ if (rollbackErrors.length > 0) throw new AggregateError([error, ...rollbackErrors], "Rivus project initialization failed and rollback was incomplete");
190
+ throw error;
191
+ }
192
+ return {
193
+ directory,
194
+ files: Object.freeze(paths)
195
+ };
196
+ }
197
+ async function writeExclusiveProjectFile(path, contents) {
198
+ await writeFile(path, contents, {
199
+ encoding: "utf8",
200
+ flag: "wx"
201
+ });
202
+ }
203
+ async function assertSafeProjectAncestors(directory, paths) {
204
+ const rootState = await lstatOrUndefined(directory);
205
+ if (rootState?.isSymbolicLink()) throw new Error("Rivus project initialization refused; symbolic link ancestor: .");
206
+ if (rootState && !rootState.isDirectory()) throw new Error("Rivus project initialization refused; project path is not a directory");
207
+ if (!rootState) return;
208
+ for (const path of paths) {
209
+ let current = directory;
210
+ for (const segment of path.split("/").slice(0, -1)) {
211
+ current = join(current, segment);
212
+ const state = await lstatOrUndefined(current);
213
+ if (!state) break;
214
+ if (state.isSymbolicLink()) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(directory, current)}`);
215
+ if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${relative(directory, current)}`);
216
+ }
217
+ }
218
+ }
219
+ async function ensureDirectory(path, projectRoot, createdDirectories) {
220
+ try {
221
+ await mkdir(path);
222
+ createdDirectories.push(path);
223
+ } catch (error) {
224
+ if (isMissingPath(error)) {
225
+ const parent = dirname(path);
226
+ if (parent === path) throw error;
227
+ await ensureDirectory(parent, projectRoot, createdDirectories);
228
+ await ensureDirectory(path, projectRoot, createdDirectories);
229
+ return;
230
+ }
231
+ if (!isAlreadyExists(error)) throw error;
232
+ const state = await lstat(path);
233
+ if (state.isSymbolicLink()) {
234
+ if (isWithin(projectRoot, path)) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(projectRoot, path) || "."}`);
235
+ if ((await stat(path)).isDirectory()) return;
236
+ }
237
+ if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${path}`);
238
+ }
239
+ }
240
+ async function rollbackCreatedPaths(files, directories) {
241
+ const errors = [];
242
+ for (const path of files.reverse()) try {
243
+ await unlink(path);
244
+ } catch (error) {
245
+ if (!isMissingPath(error)) errors.push(asError(error));
246
+ }
247
+ for (const path of directories.reverse()) try {
248
+ await rmdir(path);
249
+ } catch (error) {
250
+ if (!isMissingPath(error) && !isDirectoryNotEmpty(error)) errors.push(asError(error));
251
+ }
252
+ return errors;
253
+ }
254
+ async function lstatOrUndefined(path) {
255
+ try {
256
+ return await lstat(path);
257
+ } catch (error) {
258
+ if (isMissingPath(error)) return void 0;
259
+ throw error;
260
+ }
261
+ }
262
+ function isWithin(root, candidate) {
263
+ const child = relative(root, candidate);
264
+ return child === "" || !child.startsWith(`..${sep}`) && child !== ".." && !isAbsolute(child);
265
+ }
266
+ function isAlreadyExists(error) {
267
+ return error instanceof Error && "code" in error && error.code === "EEXIST";
268
+ }
269
+ function isDirectoryNotEmpty(error) {
270
+ return error instanceof Error && "code" in error && error.code === "ENOTEMPTY";
271
+ }
272
+ function asError(error) {
273
+ return error instanceof Error ? error : new Error(String(error));
274
+ }
275
+ async function readPackageManifest(path) {
276
+ const manifest = JSON.parse(await readFile(path, "utf8"));
277
+ if (manifest.name !== "@rivus/agent" || typeof manifest.version !== "string") throw new Error("Rivus package manifest is missing its release identity");
278
+ return manifest;
279
+ }
280
+ async function findConflicts(directory, paths) {
281
+ const conflicts = [];
282
+ for (const path of paths) try {
283
+ await lstat(join(directory, path));
284
+ conflicts.push(path);
285
+ } catch (error) {
286
+ if (!isMissingPath(error)) throw error;
287
+ }
288
+ return conflicts;
289
+ }
290
+ function isMissingPath(error) {
291
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
292
+ }
293
+ function projectPackageJson(directory, manifest) {
294
+ const pi = manifest.peerDependencies?.["@earendil-works/pi-coding-agent"];
295
+ const lark = manifest.peerDependencies?.["@larksuiteoapi/node-sdk"];
296
+ const effect = manifest.dependencies?.effect;
297
+ if (!pi || !lark || !effect) throw new Error("Rivus package manifest is missing its Effect, Pi, or Feishu dependency range");
298
+ const projectName = sanitizePackageName(basename(directory));
299
+ return `${JSON.stringify({
300
+ name: projectName,
301
+ private: true,
302
+ type: "module",
303
+ scripts: {
304
+ "check-config": "rivus --manifest ./rivus.config.json --check-config",
305
+ doctor: "rivus doctor .",
306
+ start: "rivus --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json"
307
+ },
308
+ dependencies: {
309
+ "@earendil-works/pi-coding-agent": pi,
310
+ "@larksuiteoapi/node-sdk": lark,
311
+ "@rivus/agent": `^${manifest.version}`,
312
+ effect
313
+ }
314
+ }, null, 2)}\n`;
315
+ }
316
+ function sanitizePackageName(value) {
317
+ return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "") || "rivus-app";
318
+ }
319
+ function deploymentManifest() {
320
+ return `${JSON.stringify({
321
+ plugins: [{
322
+ id: "rivus-starter",
323
+ module: "./rivus-agents.plugin.mjs",
324
+ required: true
325
+ }],
326
+ agents: [{
327
+ agentId: "agent-a",
328
+ endpointIds: ["feishu-agent-a"],
329
+ pluginId: "rivus-starter",
330
+ profileId: "agent-a",
331
+ skills: { allow: [] },
332
+ tools: { allow: ["rivus-starter/current-weather"] }
333
+ }],
334
+ defaultAgentId: "agent-a",
335
+ defaultEndpointId: "feishu-agent-a",
336
+ endpoints: [{
337
+ agentId: "agent-a",
338
+ baseUrl: "https://open.feishu.cn",
339
+ credentialRef: "env:RIVUS_FEISHU",
340
+ enabled: true,
341
+ experimental: { cotMessages: false },
342
+ groupPolicy: "mention-only",
343
+ id: "feishu-agent-a",
344
+ required: true,
345
+ sessionNamespace: "rivus-starter",
346
+ streamMinIntervalMs: 200
347
+ }]
348
+ }, null, 2)}\n`;
349
+ }
350
+ function environmentTemplate() {
351
+ return [
352
+ "# Copy this file to .env.local and keep the real values untracked.",
353
+ "RIVUS_FEISHU_APP_ID=",
354
+ "RIVUS_FEISHU_APP_SECRET=",
355
+ "PI_MODEL=",
356
+ "PI_API_KEY=",
357
+ "# PI_BASE_URL=",
358
+ "RIVUS_WEATHER_DEFAULT_LOCATION=上海",
359
+ "# LANGFUSE_BASE_URL=https://jp.cloud.langfuse.com",
360
+ "# LANGFUSE_PUBLIC_KEY=",
361
+ "# LANGFUSE_SECRET_KEY=",
362
+ "# RIVUS_TELEMETRY_CONTENT=redacted",
363
+ ""
364
+ ].join("\n");
365
+ }
366
+ function systemdService(directory, nodeExecutable) {
367
+ const cli = join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js");
368
+ return `[Unit]\nDescription=Rivus Agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nWorkingDirectory=${systemdPath(directory)}\nExecStart=${systemdQuote(nodeExecutable)} ${systemdQuote(cli)} --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json\nRestart=on-failure\nRestartSec=5\nEnvironment=NODE_ENV=production\n\n[Install]\nWantedBy=default.target\n`;
369
+ }
370
+ function systemdPath(value) {
371
+ return value.replaceAll("%", "%%");
372
+ }
373
+ function systemdQuote(value) {
374
+ return `"${value.replace(/%/g, "%%").replace(/\$/g, () => "$$").replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
375
+ }
376
+ function launchdService(directory, nodeExecutable) {
377
+ return `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n <key>Label</key>\n <string>com.rivus.agent</string>\n <key>ProgramArguments</key>\n <array>\n${[
378
+ nodeExecutable,
379
+ join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js"),
380
+ "--env-file",
381
+ ".env.local",
382
+ "--bootstrap",
383
+ "./rivus.bootstrap.ts",
384
+ "--manifest",
385
+ "./rivus.config.json"
386
+ ].map((value) => ` <string>${xmlEscape(value)}</string>`).join("\n")}\n </array>\n <key>WorkingDirectory</key>\n <string>${xmlEscape(directory)}</string>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <dict>\n <key>SuccessfulExit</key>\n <false/>\n </dict>\n <key>ThrottleInterval</key>\n <integer>5</integer>\n</dict>\n</plist>\n`;
387
+ }
388
+ function xmlEscape(value) {
389
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
390
+ }
391
+ //#endregion
392
+ //#region src/composition/rivus-cli.ts
393
+ const USAGE = `Usage:
394
+ rivus init [directory]
395
+ rivus doctor [directory] [--env-file <path>]
396
+ rivus --bootstrap <module> [--manifest <rivus.config.json>] [options]
397
+
398
+ Commands:
399
+ init Create a standalone local Rivus project without overwriting files
400
+ doctor Check Node, files, dependencies, manifest, and enabled Endpoint credentials
401
+
402
+ Run rivus --help for the complete daemon option list.
403
+ `;
404
+ function runRivusCli(options) {
405
+ const command = options.argv[0];
406
+ if (command === "init") return runInitCommand(options);
407
+ if (command === "doctor") return runDoctorCommand(options);
408
+ if (command && !command.startsWith("-")) return Effect.sync(() => {
409
+ options.stderr.write(`Unknown command: ${command}\n\n${USAGE}`);
410
+ return 1;
411
+ });
412
+ return runRivusDaemonCli(options);
413
+ }
414
+ function runInitCommand(options) {
415
+ return Effect.promise(async () => {
416
+ const args = options.argv.slice(1);
417
+ if (args.includes("--help") || args.includes("-h")) {
418
+ options.stdout.write("Usage: rivus init [directory]\n");
419
+ return 0;
420
+ }
421
+ if (args.length > 1 || args[0]?.startsWith("-")) {
422
+ options.stderr.write("Usage: rivus init [directory]\n");
423
+ return 1;
424
+ }
425
+ const directory = resolve(options.cwd, args[0] ?? ".");
426
+ try {
427
+ const result = await initializeRivusProject({
428
+ directory,
429
+ nodeExecutable: options.nodeExecutable,
430
+ packageManifestPath: options.packageManifestPath,
431
+ templateDirectory: options.templateDirectory
432
+ });
433
+ options.stdout.write(`Initialized Rivus project in ${result.directory}\n\nNext:\n cd ${shellQuote(result.directory)}\n npm install\n cp .env.example .env.local\n npm run doctor\n npm start\n`);
434
+ return 0;
435
+ } catch (error) {
436
+ options.stderr.write(`${formatError(error)}\n`);
437
+ return 1;
438
+ }
439
+ });
440
+ }
441
+ function runDoctorCommand(options) {
442
+ return Effect.promise(async () => {
443
+ const parsed = parseDoctorArguments(options.argv.slice(1));
444
+ if (parsed.help) {
445
+ options.stdout.write("Usage: rivus doctor [directory] [--env-file <path>]\n");
446
+ return 0;
447
+ }
448
+ if (parsed.error) {
449
+ options.stderr.write(`${parsed.error}\nUsage: rivus doctor [directory] [--env-file <path>]\n`);
450
+ return 1;
451
+ }
452
+ try {
453
+ const report = await diagnoseRivusProject({
454
+ directory: resolve(options.cwd, parsed.directory ?? "."),
455
+ env: options.env,
456
+ ...parsed.envFilePath ? { envFilePath: parsed.envFilePath } : {},
457
+ nodeVersion: options.nodeVersion
458
+ });
459
+ options.stdout.write(`Rivus doctor: ${report.directory}\n`);
460
+ for (const check of report.checks) options.stdout.write(`${check.status === "pass" ? "PASS" : "FAIL"} ${check.name}: ${check.message}\n`);
461
+ options.stdout.write(report.ready ? "Rivus project is ready\n" : "Rivus project is not ready\n");
462
+ return report.ready ? 0 : 1;
463
+ } catch (error) {
464
+ options.stderr.write(`${formatError(error)}\n`);
465
+ return 1;
466
+ }
467
+ });
468
+ }
469
+ function parseDoctorArguments(argv) {
470
+ let directory;
471
+ let envFilePath;
472
+ for (let index = 0; index < argv.length; index += 1) {
473
+ const argument = argv[index];
474
+ if (argument === "--help" || argument === "-h") return { help: true };
475
+ if (argument === "--env-file") {
476
+ const value = argv[index + 1];
477
+ if (!value) return { error: "--env-file requires a path" };
478
+ envFilePath = value;
479
+ index += 1;
480
+ continue;
481
+ }
482
+ if (argument.startsWith("--env-file=")) {
483
+ envFilePath = argument.slice(11);
484
+ if (!envFilePath) return { error: "--env-file requires a path" };
485
+ continue;
486
+ }
487
+ if (argument.startsWith("-")) return { error: `Unknown doctor option: ${argument}` };
488
+ if (directory !== void 0) return { error: "doctor accepts at most one directory" };
489
+ directory = argument;
490
+ }
491
+ return {
492
+ ...directory !== void 0 ? { directory } : {},
493
+ ...envFilePath !== void 0 ? { envFilePath } : {}
494
+ };
495
+ }
496
+ function formatError(error) {
497
+ return error instanceof Error ? error.message : String(error);
498
+ }
499
+ function shellQuote(value) {
500
+ return `'${value.replaceAll("'", "'\\''")}'`;
501
+ }
502
+ //#endregion
6
503
  //#region src/cli.ts
7
- const exitCode = await Effect.runPromise(runRivusDaemonCli({
504
+ const packageDirectory = fileURLToPath(new URL("..", import.meta.url));
505
+ const exitCode = await Effect.runPromise(runRivusCli({
8
506
  argv: process.argv.slice(2),
507
+ cwd: process.cwd(),
9
508
  env: process.env,
10
509
  exitAfterSignal: (code) => process.exit(code),
11
510
  loadBootstrap: (specifier) => import(toImportSpecifier(specifier)),
511
+ nodeExecutable: process.execPath,
512
+ nodeVersion: process.versions.node,
513
+ packageManifestPath: join(packageDirectory, "package.json"),
12
514
  signalSource: process,
13
515
  stderr: process.stderr,
14
- stdout: process.stdout
516
+ stdout: process.stdout,
517
+ templateDirectory: join(packageDirectory, "examples")
15
518
  }));
16
519
  process.exitCode = exitCode;
17
520
  function toImportSpecifier(specifier) {