@rivus/agent 0.14.4 → 0.15.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.
@@ -1,144 +1,14 @@
1
+ import { t as createSha256Digest } from "./sha256-digest.js";
1
2
  import { f as isRivusRuntimeToolId, o as createRivusHostToolDescriptorProvider, p as deepFreeze, t as createRivusAgentCatalog } from "./rivus-agent-definition-resolver.js";
2
3
  import { l as narrowBackgroundSessionDefinition } from "./background-session-authority.js";
3
- import { t as createSha256Digest } from "./sha256-digest.js";
4
4
  import { createRequire } from "node:module";
5
5
  import { Cause, Deferred, Effect, Either, Exit, Option } from "effect";
6
6
  import { createHash, randomUUID } from "node:crypto";
7
- import { lstat, open, readFile, readdir, realpath, stat } from "node:fs/promises";
7
+ import { access, chmod, constants, lstat, mkdir, open, readFile, readdir, realpath, stat } from "node:fs/promises";
8
8
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
9
- import { constants } from "node:fs";
9
+ import { homedir } from "node:os";
10
10
  import { pathToFileURL } from "node:url";
11
- //#region src/platform/runtime/runtime-cache.ts
12
- function createRuntimeCache() {
13
- const entries = /* @__PURE__ */ new Map();
14
- const serial = Effect.unsafeMakeSemaphore(1);
15
- const reserve = (key) => serial.withPermits(1)(Effect.gen(function* () {
16
- const current = entries.get(key);
17
- if (current) return {
18
- created: false,
19
- entry: current
20
- };
21
- const entry = {
22
- deferred: yield* Deferred.make(),
23
- initializationStarted: false,
24
- key
25
- };
26
- entries.set(key, entry);
27
- return {
28
- created: true,
29
- entry
30
- };
31
- }));
32
- const start = (entry, create) => Effect.uninterruptible(Effect.gen(function* () {
33
- if (!(yield* serial.withPermits(1)(Effect.sync(() => {
34
- if (entry.initializationStarted) return false;
35
- entry.initializationStarted = true;
36
- return true;
37
- })))) return;
38
- const initialization = create().pipe(Effect.tapError(() => serial.withPermits(1)(Effect.sync(() => {
39
- if (entries.get(entry.key) === entry) entries.delete(entry.key);
40
- }))), Effect.exit, Effect.flatMap((exit) => Deferred.done(entry.deferred, exit)), Effect.asVoid);
41
- yield* Effect.forkDaemon(initialization);
42
- }));
43
- const getOrCreate = (key, create) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
44
- const selected = yield* reserve(key);
45
- yield* start(selected.entry, create);
46
- return {
47
- entry: selected.entry,
48
- runtime: yield* restore(Deferred.await(selected.entry.deferred))
49
- };
50
- }));
51
- return {
52
- drain: () => serial.withPermits(1)(Effect.sync(() => {
53
- const drained = Object.freeze([...entries.values()]);
54
- entries.clear();
55
- return drained;
56
- })),
57
- getExisting: (key) => Effect.gen(function* () {
58
- const entry = yield* serial.withPermits(1)(Effect.sync(() => entries.get(key)));
59
- if (!entry) return void 0;
60
- return {
61
- entry,
62
- runtime: yield* Deferred.await(entry.deferred)
63
- };
64
- }),
65
- getOrCreate,
66
- isCurrent: (key, entry) => serial.withPermits(1)(Effect.sync(() => entries.get(key) === entry)),
67
- reserve,
68
- size: () => serial.withPermits(1)(Effect.sync(() => entries.size)),
69
- start
70
- };
71
- }
72
- function disposeRuntimeCacheEntries(options) {
73
- const disposal = Effect.gen(function* () {
74
- const completions = yield* Effect.forEach(options.entries, (entry) => Effect.gen(function* () {
75
- const completion = yield* Deferred.make();
76
- yield* Effect.forkDaemon(Deferred.await(entry.deferred).pipe(Effect.flatMap(options.dispose), Effect.exit, Effect.flatMap((exit) => Deferred.succeed(completion, exit)), Effect.asVoid));
77
- return completion;
78
- }), { concurrency: "unbounded" });
79
- const failures = (yield* Effect.forEach(completions, Deferred.await, { concurrency: "unbounded" })).filter(Exit.isFailure).map(({ cause }) => Cause.squash(cause));
80
- if (failures.length > 0) return yield* Effect.fail(new AggregateError(failures, options.failureMessage));
81
- });
82
- return options.timeout ? disposal.pipe(Effect.timeoutFail({
83
- duration: options.timeout.milliseconds,
84
- onTimeout: options.timeout.onTimeout
85
- })) : disposal;
86
- }
87
- function invokeRuntimeControl(runtime, control) {
88
- return runtime.pipe(Effect.flatMap((selected) => selected ? control(selected) ?? Effect.succeed(false) : Effect.succeed(false)));
89
- }
90
- //#endregion
91
- //#region src/adapters/agent/runtime/process-agent-runtime-adapter.ts
92
- function toEffectAgentRuntimeInput(input) {
93
- const onUpdate = input.onUpdate;
94
- return {
95
- ...runtimeInputFields(input),
96
- ...onUpdate ? { onUpdate: (update) => Effect.tryPromise({
97
- try: async () => onUpdate(update),
98
- catch: (failure) => failure
99
- }) } : {}
100
- };
101
- }
102
- function toProcessAgentRuntimeInput(input, runEffect) {
103
- const onUpdate = input.onUpdate;
104
- return {
105
- ...runtimeInputFields(input),
106
- ...onUpdate ? { onUpdate: (update) => runEffect(onUpdate(update)) } : {}
107
- };
108
- }
109
- function toEffectAgentRuntime(runtime, runEffect) {
110
- const cancel = runtime.cancel?.bind(runtime);
111
- const dispose = runtime.dispose?.bind(runtime);
112
- const steer = runtime.steer?.bind(runtime);
113
- return {
114
- ...runtime.concurrency ? { concurrency: runtime.concurrency } : {},
115
- ...cancel ? { cancel: (input) => Effect.tryPromise({
116
- try: () => cancel(input),
117
- catch: (failure) => failure
118
- }) } : {},
119
- ...dispose ? { dispose: () => Effect.tryPromise({
120
- try: async () => dispose(),
121
- catch: (failure) => failure
122
- }) } : {},
123
- run: (input) => Effect.tryPromise({
124
- try: () => runtime.run(toProcessAgentRuntimeInput(input, runEffect)),
125
- catch: (failure) => failure
126
- }),
127
- ...steer ? { steer: (input) => Effect.tryPromise({
128
- try: () => steer(input),
129
- catch: (failure) => failure
130
- }) } : {}
131
- };
132
- }
133
- function runtimeInputFields(input) {
134
- return {
135
- ...input.invocation ? { invocation: input.invocation } : {},
136
- ...input.payload === void 0 ? {} : { payload: input.payload },
137
- sessionKey: input.sessionKey,
138
- text: input.text
139
- };
140
- }
141
- //#endregion
11
+ import { constants as constants$1 } from "node:fs";
142
12
  //#region src/platform/home/config/runtime/local-env-file.ts
143
13
  var LocalEnvFileError = class extends Error {
144
14
  constructor(message) {
@@ -195,6 +65,310 @@ function unescapeDoubleQuotedValue(value) {
195
65
  });
196
66
  }
197
67
  //#endregion
68
+ //#region src/platform/home/config/model-management/rivus-model-management-config-migration.ts
69
+ const RIVUS_MODEL_MANAGEMENT_ENABLED_ENV = "RIVUS_MODEL_MANAGEMENT_ENABLED";
70
+ const RIVUS_MODEL_MANAGEMENT_OWNER_OPEN_ID_ENV = "RIVUS_MODEL_MANAGEMENT_OWNER_OPEN_ID";
71
+ const RIVUS_MODEL_MANAGEMENT_TENANT_KEY_ENV = "RIVUS_MODEL_MANAGEMENT_TENANT_KEY";
72
+ const RIVUS_MODEL_MANAGEMENT_REQUIRE_APPROVAL_ENV = "RIVUS_MODEL_MANAGEMENT_REQUIRE_APPROVAL";
73
+ var RivusModelManagementConfigError = class extends Error {
74
+ code;
75
+ name = "RivusModelManagementConfigError";
76
+ constructor(code, message) {
77
+ super(message);
78
+ this.code = code;
79
+ }
80
+ };
81
+ /** Parse the Home capability flags without accepting truthy arbitrary strings. */
82
+ function parseRivusModelManagementHomeConfig(env) {
83
+ const enabled = parseRivusModelManagementEnabled(env[RIVUS_MODEL_MANAGEMENT_ENABLED_ENV]);
84
+ const requireApproval = parseStrictBoolean(env[RIVUS_MODEL_MANAGEMENT_REQUIRE_APPROVAL_ENV], RIVUS_MODEL_MANAGEMENT_REQUIRE_APPROVAL_ENV, false);
85
+ const ownerOpenId = optional$1(env[RIVUS_MODEL_MANAGEMENT_OWNER_OPEN_ID_ENV]);
86
+ const tenantKey = optional$1(env[RIVUS_MODEL_MANAGEMENT_TENANT_KEY_ENV]);
87
+ if (enabled && !ownerOpenId) throw new RivusModelManagementConfigError("owner_missing", `${RIVUS_MODEL_MANAGEMENT_OWNER_OPEN_ID_ENV} is required when model management is enabled`);
88
+ if (enabled && !tenantKey) throw new RivusModelManagementConfigError("tenant_missing", `${RIVUS_MODEL_MANAGEMENT_TENANT_KEY_ENV} is required when model management is enabled`);
89
+ return Object.freeze({
90
+ enabled,
91
+ ...ownerOpenId ? { ownerOpenId } : {},
92
+ requireApproval,
93
+ ...tenantKey ? { tenantKey } : {}
94
+ });
95
+ }
96
+ function parseRivusModelManagementEnabled(value) {
97
+ return parseStrictBoolean(value, RIVUS_MODEL_MANAGEMENT_ENABLED_ENV, false);
98
+ }
99
+ function parseStrictBoolean(value, variable, defaultValue) {
100
+ if (value === void 0) return defaultValue;
101
+ const normalized = value.trim();
102
+ if (normalized === "true") return true;
103
+ if (normalized === "false") return false;
104
+ throw new RivusModelManagementConfigError("invalid_enabled", `${variable} must be true or false`);
105
+ }
106
+ /**
107
+ * Migrate only the legacy model selection at the explicit enable/disable
108
+ * boundary. The helper does not read or write managed model state.
109
+ */
110
+ async function migrateRivusModelManagementConfig(input) {
111
+ if (typeof input.managementEnabled !== "boolean") throw new RivusModelManagementConfigError("invalid_enabled", "model management enabled state must be boolean");
112
+ if (input.managementEnabled) return enableModelManagement(input);
113
+ return disableModelManagement(input, parseModelReference(input.knownGoodProvider, input.knownGoodModel));
114
+ }
115
+ async function enableModelManagement(input) {
116
+ if (hasAmbientModelOverride(input.env)) return {
117
+ initialModel: parseConfiguredModel(input.env.PI_MODEL),
118
+ source: "ambient",
119
+ status: "enabled"
120
+ };
121
+ return {
122
+ initialModel: parseConfiguredModel((await loadEnvFile(requireEnvFilePath(input.envFilePath), input.env)).PI_MODEL),
123
+ source: "env-file",
124
+ status: "enabled"
125
+ };
126
+ }
127
+ async function disableModelManagement(input, knownGood) {
128
+ const envFilePath = requireEnvFilePath(input.envFilePath);
129
+ if (hasAmbientModelOverride(input.env)) throw new RivusModelManagementConfigError("ambient_model_override", "ambient PI_MODEL overrides the original env source and prevents verified model readback");
130
+ const original = await readWritableEnvFile(envFilePath);
131
+ const existingModel = parseOptionalConfiguredModel((await loadEnvFile(envFilePath, input.env)).PI_MODEL);
132
+ if (existingModel && sameModel(existingModel, knownGood)) return {
133
+ restoredModel: knownGood,
134
+ source: "env-file",
135
+ status: "unchanged"
136
+ };
137
+ const next = replacePiModel(original, knownGood);
138
+ try {
139
+ await input.writeAtomicTextFile(envFilePath, next, { durable: true });
140
+ } catch {
141
+ throw new RivusModelManagementConfigError("env_source_write_failed", "the original env source write did not complete with a known durable result");
142
+ }
143
+ let readBack;
144
+ try {
145
+ readBack = parseConfiguredModel((await loadMergedLocalEnvFile(envFilePath, input.env)).PI_MODEL);
146
+ } catch {
147
+ throw new RivusModelManagementConfigError("readback_mismatch", "the original env source could not be verified after restoring PI_MODEL");
148
+ }
149
+ if (readBack.provider !== knownGood.provider || readBack.model !== knownGood.model) throw new RivusModelManagementConfigError("readback_mismatch", "the original env source did not read back the known-good PI_MODEL");
150
+ return {
151
+ restoredModel: knownGood,
152
+ source: "env-file",
153
+ status: "exported"
154
+ };
155
+ }
156
+ function parseModelReference(provider, model) {
157
+ if (!isModelPart(provider) || !isModelPart(model)) throw new RivusModelManagementConfigError("invalid_model", "known-good model provider and id are invalid");
158
+ return Object.freeze({
159
+ model,
160
+ provider
161
+ });
162
+ }
163
+ function parseConfiguredModel(value) {
164
+ const configured = optional$1(value);
165
+ if (!configured) throw new RivusModelManagementConfigError("model_missing", "PI_MODEL is missing from the effective legacy config");
166
+ const separator = configured.indexOf("/");
167
+ if (separator <= 0 || separator === configured.length - 1 || configured.indexOf("/", separator + 1) !== -1) throw new RivusModelManagementConfigError("invalid_model", "PI_MODEL must use provider/model form");
168
+ return parseModelReference(configured.slice(0, separator), configured.slice(separator + 1));
169
+ }
170
+ function parseOptionalConfiguredModel(value) {
171
+ if (!optional$1(value)) return void 0;
172
+ try {
173
+ return parseConfiguredModel(value);
174
+ } catch {
175
+ return;
176
+ }
177
+ }
178
+ function sameModel(left, right) {
179
+ return left.provider === right.provider && left.model === right.model;
180
+ }
181
+ async function loadEnvFile(envFilePath, env) {
182
+ try {
183
+ return await loadMergedLocalEnvFile(envFilePath, env);
184
+ } catch {
185
+ throw new RivusModelManagementConfigError("env_source_unreadable", "the original env source could not be loaded");
186
+ }
187
+ }
188
+ async function readWritableEnvFile(envFilePath) {
189
+ try {
190
+ const contents = await readFile(envFilePath, "utf8");
191
+ if (((await stat(envFilePath)).mode & 146) === 0) throw new RivusModelManagementConfigError("env_source_unwritable", "the original env source is not writable");
192
+ await access(envFilePath, constants.W_OK);
193
+ return contents;
194
+ } catch (error) {
195
+ if (error instanceof RivusModelManagementConfigError) throw error;
196
+ if (isPermissionError(error)) throw new RivusModelManagementConfigError("env_source_unwritable", "the original env source is not writable");
197
+ throw new RivusModelManagementConfigError("env_source_unreadable", "the original env source is unavailable");
198
+ }
199
+ }
200
+ function replacePiModel(contents, model) {
201
+ const modelValue = `${model.provider}/${model.model}`;
202
+ const parts = contents.split(/(\r\n|\n|\r)/);
203
+ let replaced = false;
204
+ for (let index = 0; index < parts.length; index += 2) {
205
+ const line = parts[index];
206
+ if (line === void 0) continue;
207
+ const match = line.match(/^(\s*(?:export\s+)?PI_MODEL\s*=\s*)(.*)$/);
208
+ if (!match) continue;
209
+ const inlineComment = match[2].match(/(\s+#.*)$/)?.[1] ?? "";
210
+ parts[index] = `${match[1]}${modelValue}${inlineComment}`;
211
+ replaced = true;
212
+ }
213
+ if (replaced) return parts.join("");
214
+ const newline = contents.includes("\r\n") ? "\r\n" : contents.includes("\n") ? "\n" : "\n";
215
+ if (!contents) return `PI_MODEL=${modelValue}${newline}`;
216
+ return /(?:\r\n|\n|\r)$/.test(contents) ? `${contents}PI_MODEL=${modelValue}${newline}` : `${contents}${newline}PI_MODEL=${modelValue}`;
217
+ }
218
+ function requireEnvFilePath(value) {
219
+ const normalized = optional$1(value);
220
+ if (!normalized) throw new RivusModelManagementConfigError("env_source_missing", "an explicit writable original env source is required for model management migration");
221
+ return normalized;
222
+ }
223
+ function hasAmbientModelOverride(env) {
224
+ return Object.prototype.hasOwnProperty.call(env, "PI_MODEL") && env.PI_MODEL !== void 0;
225
+ }
226
+ function isModelPart(value) {
227
+ return value.trim() === value && value.length > 0 && !/[/\s]/.test(value);
228
+ }
229
+ function optional$1(value) {
230
+ return value?.trim() || void 0;
231
+ }
232
+ function isPermissionError(error) {
233
+ return typeof error === "object" && error !== null && "code" in error && (error.code === "EACCES" || error.code === "EPERM" || error.code === "EROFS");
234
+ }
235
+ //#endregion
236
+ //#region src/platform/home/config/model-management/rivus-runtime-management-skill-installer.ts
237
+ const SKILL_NAME = "runtime-management";
238
+ const SKILL_FILE = "SKILL.md";
239
+ const INSTALL_METADATA_FILE = ".rivus-install.json";
240
+ async function installRivusRuntimeManagementSkill(options) {
241
+ const writeAtomicTextFile = options.writeAtomicTextFile;
242
+ const skillDirectory = join(options.homeDirectory ?? homedir(), ".agents", "skills", SKILL_NAME);
243
+ const destination = join(skillDirectory, SKILL_FILE);
244
+ const metadataPath = join(skillDirectory, INSTALL_METADATA_FILE);
245
+ const source = await readFile(options.sourcePath, "utf8");
246
+ const sourceDigest = digest(source);
247
+ await mkdir(skillDirectory, { recursive: true });
248
+ const current = await readOptional(destination);
249
+ if (current === void 0) {
250
+ await writeAtomicTextFile(destination, source, { mode: 384 });
251
+ await writeMetadata(metadataPath, sourceDigest, writeAtomicTextFile);
252
+ return {
253
+ destination,
254
+ requiresRefresh: true,
255
+ sourceDigest,
256
+ status: "installed"
257
+ };
258
+ }
259
+ const currentDigest = digest(current);
260
+ if (currentDigest === sourceDigest) {
261
+ await writeMetadata(metadataPath, sourceDigest, writeAtomicTextFile);
262
+ return {
263
+ destination,
264
+ requiresRefresh: false,
265
+ sourceDigest,
266
+ status: "unchanged"
267
+ };
268
+ }
269
+ if ((await readMetadata(metadataPath))?.installedDigest !== currentDigest) return {
270
+ destination,
271
+ requiresRefresh: false,
272
+ sourceDigest,
273
+ status: "conflict"
274
+ };
275
+ await writeAtomicTextFile(destination, source, { mode: 384 });
276
+ await writeMetadata(metadataPath, sourceDigest, writeAtomicTextFile);
277
+ return {
278
+ destination,
279
+ requiresRefresh: true,
280
+ sourceDigest,
281
+ status: "updated"
282
+ };
283
+ }
284
+ function digest(value) {
285
+ return createHash("sha256").update(value, "utf8").digest("hex");
286
+ }
287
+ async function readOptional(path) {
288
+ try {
289
+ return await readFile(path, "utf8");
290
+ } catch (error) {
291
+ if (isMissing$1(error)) return void 0;
292
+ throw error;
293
+ }
294
+ }
295
+ async function readMetadata(path) {
296
+ const contents = await readOptional(path);
297
+ if (contents === void 0) return void 0;
298
+ try {
299
+ const value = JSON.parse(contents);
300
+ if (!isRecord(value) || typeof value.installedDigest !== "string") return void 0;
301
+ return { installedDigest: value.installedDigest };
302
+ } catch {
303
+ return;
304
+ }
305
+ }
306
+ async function writeMetadata(path, installedDigest, writeAtomicTextFile) {
307
+ await writeAtomicTextFile(path, `${JSON.stringify({
308
+ installedDigest,
309
+ version: 1
310
+ }, null, 2)}\n`, { mode: 384 });
311
+ }
312
+ function isRecord(value) {
313
+ return typeof value === "object" && value !== null && !Array.isArray(value);
314
+ }
315
+ function isMissing$1(error) {
316
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
317
+ }
318
+ //#endregion
319
+ //#region src/platform/home/config/model-management/rivus-model-management-cli-launcher.ts
320
+ const BIN_DIRECTORY_NAME = "bin";
321
+ const LAUNCHER_NAME = "rivus";
322
+ const PRIVATE_MODE = 448;
323
+ /**
324
+ * Install the private launcher used by model-management child processes.
325
+ *
326
+ * The launcher contains only fixed absolute executable paths. Per-Run
327
+ * context, credentials, and other authority data stay in the spawn
328
+ * environment owned by the Host and are never persisted in this file.
329
+ */
330
+ async function installRivusModelManagementCliLauncher(options) {
331
+ assertAbsolutePath("directory", options.directory);
332
+ assertAbsolutePath("nodeExecutable", options.nodeExecutable);
333
+ assertAbsolutePath("cliEntryPath", options.cliEntryPath);
334
+ const binDirectory = join(options.directory, BIN_DIRECTORY_NAME);
335
+ const launcherPath = join(binDirectory, LAUNCHER_NAME);
336
+ await mkdir(binDirectory, {
337
+ mode: PRIVATE_MODE,
338
+ recursive: true
339
+ });
340
+ await chmod(binDirectory, PRIVATE_MODE);
341
+ await chmodIfPresent(launcherPath, PRIVATE_MODE);
342
+ await options.writeAtomicTextFile(launcherPath, renderLauncher(options), { mode: PRIVATE_MODE });
343
+ await chmod(launcherPath, PRIVATE_MODE);
344
+ return Object.freeze({
345
+ binDirectory,
346
+ launcherPath
347
+ });
348
+ }
349
+ function renderLauncher(options) {
350
+ return `#!/bin/sh\nexec ${shellQuote(options.nodeExecutable)} ${shellQuote(options.cliEntryPath)} "$@"\n`;
351
+ }
352
+ function shellQuote(value) {
353
+ if (value.includes("\0")) throw new Error("launcher paths must not contain NUL bytes");
354
+ return `'${value.replaceAll("'", "'\\''")}'`;
355
+ }
356
+ function assertAbsolutePath(name, value) {
357
+ if (value.length === 0 || !isAbsolute(value)) throw new Error(`${name} must be an absolute path`);
358
+ if (value.includes("\0")) throw new Error(`${name} must not contain NUL bytes`);
359
+ }
360
+ async function chmodIfPresent(path, mode) {
361
+ try {
362
+ await chmod(path, mode);
363
+ } catch (error) {
364
+ if (isMissing(error)) return;
365
+ throw error;
366
+ }
367
+ }
368
+ function isMissing(error) {
369
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
370
+ }
371
+ //#endregion
198
372
  //#region src/platform/home/config/runtime/rivus-daemon-config.ts
199
373
  var RivusDaemonConfigError = class {
200
374
  variable;
@@ -287,6 +461,145 @@ function optionalThinkingLevel(value) {
287
461
  return Effect.fail(new RivusDaemonConfigError("PI_THINKING_LEVEL", "PI_THINKING_LEVEL must be one of off, minimal, low, medium, high, xhigh"));
288
462
  }
289
463
  //#endregion
464
+ //#region src/bootstrap/deployment/effect-runner.ts
465
+ async function runDeploymentProcessEffect(effect) {
466
+ const exit = await Effect.runPromiseExit(effect);
467
+ if (Exit.isSuccess(exit)) return exit.value;
468
+ const failure = Cause.failureOption(exit.cause);
469
+ throw Option.isSome(failure) ? failure.value : Cause.squash(exit.cause);
470
+ }
471
+ //#endregion
472
+ //#region src/platform/runtime/runtime-cache.ts
473
+ function createRuntimeCache() {
474
+ const entries = /* @__PURE__ */ new Map();
475
+ const serial = Effect.unsafeMakeSemaphore(1);
476
+ const reserve = (key) => serial.withPermits(1)(Effect.gen(function* () {
477
+ const current = entries.get(key);
478
+ if (current) return {
479
+ created: false,
480
+ entry: current
481
+ };
482
+ const entry = {
483
+ deferred: yield* Deferred.make(),
484
+ initializationStarted: false,
485
+ key
486
+ };
487
+ entries.set(key, entry);
488
+ return {
489
+ created: true,
490
+ entry
491
+ };
492
+ }));
493
+ const start = (entry, create) => Effect.uninterruptible(Effect.gen(function* () {
494
+ if (!(yield* serial.withPermits(1)(Effect.sync(() => {
495
+ if (entry.initializationStarted) return false;
496
+ entry.initializationStarted = true;
497
+ return true;
498
+ })))) return;
499
+ const initialization = create().pipe(Effect.tapError(() => serial.withPermits(1)(Effect.sync(() => {
500
+ if (entries.get(entry.key) === entry) entries.delete(entry.key);
501
+ }))), Effect.exit, Effect.flatMap((exit) => Deferred.done(entry.deferred, exit)), Effect.asVoid);
502
+ yield* Effect.forkDaemon(initialization);
503
+ }));
504
+ const getOrCreate = (key, create) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
505
+ const selected = yield* reserve(key);
506
+ yield* start(selected.entry, create);
507
+ return {
508
+ entry: selected.entry,
509
+ runtime: yield* restore(Deferred.await(selected.entry.deferred))
510
+ };
511
+ }));
512
+ return {
513
+ drain: () => serial.withPermits(1)(Effect.sync(() => {
514
+ const drained = Object.freeze([...entries.values()]);
515
+ entries.clear();
516
+ return drained;
517
+ })),
518
+ getExisting: (key) => Effect.gen(function* () {
519
+ const entry = yield* serial.withPermits(1)(Effect.sync(() => entries.get(key)));
520
+ if (!entry) return void 0;
521
+ return {
522
+ entry,
523
+ runtime: yield* Deferred.await(entry.deferred)
524
+ };
525
+ }),
526
+ getOrCreate,
527
+ isCurrent: (key, entry) => serial.withPermits(1)(Effect.sync(() => entries.get(key) === entry)),
528
+ reserve,
529
+ size: () => serial.withPermits(1)(Effect.sync(() => entries.size)),
530
+ start
531
+ };
532
+ }
533
+ function disposeRuntimeCacheEntries(options) {
534
+ const disposal = Effect.gen(function* () {
535
+ const completions = yield* Effect.forEach(options.entries, (entry) => Effect.gen(function* () {
536
+ const completion = yield* Deferred.make();
537
+ yield* Effect.forkDaemon(Deferred.await(entry.deferred).pipe(Effect.flatMap(options.dispose), Effect.exit, Effect.flatMap((exit) => Deferred.succeed(completion, exit)), Effect.asVoid));
538
+ return completion;
539
+ }), { concurrency: "unbounded" });
540
+ const failures = (yield* Effect.forEach(completions, Deferred.await, { concurrency: "unbounded" })).filter(Exit.isFailure).map(({ cause }) => Cause.squash(cause));
541
+ if (failures.length > 0) return yield* Effect.fail(new AggregateError(failures, options.failureMessage));
542
+ });
543
+ return options.timeout ? disposal.pipe(Effect.timeoutFail({
544
+ duration: options.timeout.milliseconds,
545
+ onTimeout: options.timeout.onTimeout
546
+ })) : disposal;
547
+ }
548
+ function invokeRuntimeControl(runtime, control) {
549
+ return runtime.pipe(Effect.flatMap((selected) => selected ? control(selected) ?? Effect.succeed(false) : Effect.succeed(false)));
550
+ }
551
+ //#endregion
552
+ //#region src/adapters/agent/runtime/process-agent-runtime-adapter.ts
553
+ function toEffectAgentRuntimeInput(input) {
554
+ const onUpdate = input.onUpdate;
555
+ return {
556
+ ...runtimeInputFields(input),
557
+ ...onUpdate ? { onUpdate: (update) => Effect.tryPromise({
558
+ try: async () => onUpdate(update),
559
+ catch: (failure) => failure
560
+ }) } : {}
561
+ };
562
+ }
563
+ function toProcessAgentRuntimeInput(input, runEffect) {
564
+ const onUpdate = input.onUpdate;
565
+ return {
566
+ ...runtimeInputFields(input),
567
+ ...onUpdate ? { onUpdate: (update) => runEffect(onUpdate(update)) } : {}
568
+ };
569
+ }
570
+ function toEffectAgentRuntime(runtime, runEffect) {
571
+ const cancel = runtime.cancel?.bind(runtime);
572
+ const dispose = runtime.dispose?.bind(runtime);
573
+ const steer = runtime.steer?.bind(runtime);
574
+ return {
575
+ ...runtime.concurrency ? { concurrency: runtime.concurrency } : {},
576
+ ...cancel ? { cancel: (input) => Effect.tryPromise({
577
+ try: () => cancel(input),
578
+ catch: (failure) => failure
579
+ }) } : {},
580
+ ...dispose ? { dispose: () => Effect.tryPromise({
581
+ try: async () => dispose(),
582
+ catch: (failure) => failure
583
+ }) } : {},
584
+ run: (input) => Effect.tryPromise({
585
+ try: () => runtime.run(toProcessAgentRuntimeInput(input, runEffect)),
586
+ catch: (failure) => failure
587
+ }),
588
+ ...steer ? { steer: (input) => Effect.tryPromise({
589
+ try: () => steer(input),
590
+ catch: (failure) => failure
591
+ }) } : {}
592
+ };
593
+ }
594
+ function runtimeInputFields(input) {
595
+ return {
596
+ ...input.invocation ? { invocation: input.invocation } : {},
597
+ ...input.payload === void 0 ? {} : { payload: input.payload },
598
+ sessionKey: input.sessionKey,
599
+ text: input.text
600
+ };
601
+ }
602
+ //#endregion
290
603
  //#region src/adapters/feishu/config/feishu-endpoint-credentials.ts
291
604
  var FeishuEndpointCredentialError = class extends Error {
292
605
  name = "FeishuEndpointCredentialError";
@@ -723,7 +1036,7 @@ function parsePositiveInteger(value) {
723
1036
  return value && /^[1-9]\d*$/.test(value) ? Number(value) : void 0;
724
1037
  }
725
1038
  async function readPrivateTextFile(filePath, label, maxBytes) {
726
- const handle = await open(filePath, constants.O_RDONLY | constants.O_NOFOLLOW);
1039
+ const handle = await open(filePath, constants$1.O_RDONLY | constants$1.O_NOFOLLOW);
727
1040
  try {
728
1041
  const metadata = await handle.stat();
729
1042
  if (!metadata.isFile()) throw new Error(`${label} must be a regular file`);
@@ -754,6 +1067,7 @@ Project commands:
754
1067
  rivus check-config
755
1068
  rivus init [directory]
756
1069
  rivus doctor [directory] [--env-file <path>]
1070
+ rivus model <status|set|rollback> ...
757
1071
 
758
1072
  Options:
759
1073
  --bootstrap <module> Module exporting createRivusDaemonProcess(context)
@@ -3158,14 +3472,6 @@ function trimOptional(value) {
3158
3472
  return value?.trim() || void 0;
3159
3473
  }
3160
3474
  //#endregion
3161
- //#region src/bootstrap/deployment/effect-runner.ts
3162
- async function runDeploymentProcessEffect(effect) {
3163
- const exit = await Effect.runPromiseExit(effect);
3164
- if (Exit.isSuccess(exit)) return exit.value;
3165
- const failure = Cause.failureOption(exit.cause);
3166
- throw Option.isSome(failure) ? failure.value : Cause.squash(exit.cause);
3167
- }
3168
- //#endregion
3169
3475
  //#region src/bootstrap/deployment/rivus-deployment-cli-process.ts
3170
3476
  async function createRivusDeploymentCliProcess(factory, context) {
3171
3477
  const adapters = await factory(context);
@@ -3387,6 +3693,8 @@ function runRivusDaemonCli(options) {
3387
3693
  try: () => parsed.manifestPath ? createCliDeploymentDaemon(module.createRivusDeploymentAdapters, {
3388
3694
  argv: options.argv,
3389
3695
  env,
3696
+ ...parsed.envFilePath ? { envFilePath: parsed.envFilePath } : {},
3697
+ environmentOverrides: options.env,
3390
3698
  manifestPath: parsed.manifestPath,
3391
3699
  ...options.pluginPackageManifestPath ? { pluginPackageManifestPath: options.pluginPackageManifestPath } : {}
3392
3700
  }) : createCliLegacyDaemon(module, {
@@ -3541,4 +3849,4 @@ function hasRecoveryRunner(daemon) {
3541
3849
  return typeof daemon.openRecoveryControl === "function";
3542
3850
  }
3543
3851
  //#endregion
3544
- export { InvalidRivusProjectSpace as A, loadMergedLocalEnvFile as B, createEffectAgentInstanceRegistry as C, createAgentHostRuntimePool as D, AgentRuntimeDisposed as E, formatRivusEnvFile as F, disposeRuntimeCacheEntries as G, toEffectAgentRuntimeInput as H, FeishuEndpointCredentialError as I, invokeRuntimeControl as K, resolveFeishuEndpointCredentials as L, createRivusDaemonShutdownController as M, OpenClawEnvImportError as N, RivusDeploymentManifestError as O, createRivusEnvFromOpenClawConfig as P, RivusDaemonConfigError as R, AgentInstanceConflict as S, AgentInstanceBusy as T, toProcessAgentRuntimeInput as U, toEffectAgentRuntime as V, createRuntimeCache as W, findTrustedPackageRoot as _, RivusDeploymentAutomationReadinessError as a, InvalidAgentHostBinding as b, createRivusDeploymentControl as c, resolveRivusDeployment as d, createNodeRivusPluginModuleLoader as f, isPathWithin as g, validateTrustedModulePath as h, resolveRivusProjectSpace as i, validateRivusDeploymentManifest as j, loadRivusDeploymentManifest as k, RivusDeploymentDaemonLifecycleError as l, resolveNodeRivusPluginModulePath as m, createRivusDeploymentCliProcess as n, RivusDeploymentBackgroundSessionReadinessError as o, loadNodeRivusPluginModule as p, runDeploymentProcessEffect as r, RivusDeploymentReadinessError as s, runRivusDaemonCli as t, RivusPluginLoadError as u, resolveRivusPluginModule as v, createStableId as w, createEffectAgentHost as x, createProcessDeploymentControlPorts as y, loadRivusDaemonConfig as z };
3852
+ export { validateRivusDeploymentManifest as A, createRuntimeCache as B, createStableId as C, RivusDeploymentManifestError as D, createAgentHostRuntimePool as E, FeishuEndpointCredentialError as F, loadRivusDaemonConfig as G, invokeRuntimeControl as H, resolveFeishuEndpointCredentials as I, migrateRivusModelManagementConfig as J, installRivusModelManagementCliLauncher as K, toEffectAgentRuntime as L, OpenClawEnvImportError as M, createRivusEnvFromOpenClawConfig as N, loadRivusDeploymentManifest as O, formatRivusEnvFile as P, toEffectAgentRuntimeInput as R, createEffectAgentInstanceRegistry as S, AgentRuntimeDisposed as T, runDeploymentProcessEffect as U, disposeRuntimeCacheEntries as V, RivusDaemonConfigError as W, loadMergedLocalEnvFile as X, parseRivusModelManagementHomeConfig as Y, resolveRivusPluginModule as _, RivusDeploymentBackgroundSessionReadinessError as a, createEffectAgentHost as b, RivusDeploymentDaemonLifecycleError as c, createNodeRivusPluginModuleLoader as d, loadNodeRivusPluginModule as f, findTrustedPackageRoot as g, isPathWithin as h, RivusDeploymentAutomationReadinessError as i, createRivusDaemonShutdownController as j, InvalidRivusProjectSpace as k, RivusPluginLoadError as l, validateTrustedModulePath as m, createRivusDeploymentCliProcess as n, RivusDeploymentReadinessError as o, resolveNodeRivusPluginModulePath as p, installRivusRuntimeManagementSkill as q, resolveRivusProjectSpace as r, createRivusDeploymentControl as s, runRivusDaemonCli as t, resolveRivusDeployment as u, createProcessDeploymentControlPorts as v, AgentInstanceBusy as w, AgentInstanceConflict as x, InvalidAgentHostBinding as y, toProcessAgentRuntimeInput as z };