@rivus/gateway 0.16.6 → 0.17.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.
Files changed (36) hide show
  1. package/LICENSE +674 -21
  2. package/README.md +25 -0
  3. package/dist/bootstrap/herdr-feishu.d.ts +37 -0
  4. package/dist/bootstrap/herdr-feishu.js +856 -0
  5. package/dist/bootstrap/pi-feishu.d.ts +281 -16
  6. package/dist/bootstrap/pi-feishu.js +17314 -344
  7. package/dist/chunks/background-session-authority.js +2 -38
  8. package/dist/chunks/rivus-daemon-cli.d.ts +1115 -0
  9. package/dist/chunks/rivus-node-entrypoint.js +700 -819
  10. package/dist/chunks/{node-rivus-deployment-manifest.js → runtime-cache.js} +1116 -1475
  11. package/dist/cli.d.ts +2 -1
  12. package/dist/cli.js +1 -0
  13. package/dist/index.d.ts +65 -3
  14. package/dist/index.js +3 -1215
  15. package/dist/mcp.d.ts +7 -63
  16. package/dist/mcp.js +3 -250
  17. package/package.json +21 -13
  18. package/templates/a-share-briefing-analysis.mjs +3 -1
  19. package/templates/a-share-briefing-renderer.mjs +15 -5
  20. package/templates/a-share-index-evidence.mjs +9 -3
  21. package/templates/a-share-market-briefing.mjs +3 -1
  22. package/templates/a-share-overseas-evidence.mjs +12 -4
  23. package/templates/a-share-policy-evidence.mjs +30 -10
  24. package/templates/a-share-sector-evidence.mjs +3 -1
  25. package/templates/acp-stdio-proxy.mjs +10 -4
  26. package/templates/current-weather.mjs +36 -12
  27. package/templates/herdr-feishu.mjs +30 -0
  28. package/templates/html-drive-tools.mjs +36 -12
  29. package/templates/pi-feishu-deployment.bootstrap.ts +1 -3
  30. package/templates/pi-feishu.bootstrap.ts +1 -242
  31. package/templates/rivus-agents.plugin.mjs +3 -1
  32. package/dist/chunks/background-session-control-input.js +0 -45
  33. package/dist/chunks/background-session-service.d.ts +0 -390
  34. package/dist/chunks/index.d.ts +0 -4703
  35. package/dist/chunks/service.js +0 -12112
  36. package/templates/langfuse-drive-e2e.mjs +0 -175
@@ -1,217 +1,18 @@
1
- import { l as narrowBackgroundSessionDefinition, o as createBackgroundSessionToolContracts } from "./background-session-authority.js";
2
- import { C as parseRivusModelCliArguments, D as deepFreeze, E as runDeploymentProcessEffect, M as disposeRuntimeCacheEntries, N as invokeRuntimeControl, O as toEffectAgentRuntime, S as createRivusModelManagementWireRequest, T as renderRivusModelCliHelp, a as InvalidRivusProjectSpace, c as RIVUS_RELEASE_DESCRIPTOR, f as gatewayTemplateDirectory, i as resolveFeishuEndpointCredentials, j as createRuntimeCache, k as toEffectAgentRuntimeInput, m as loadRivusDaemonConfig, n as loadRivusDeploymentManifest, o as validateRivusDeploymentManifest, s as validateRivusProjectSpaceDeployment, u as gatewayPackageManifestPath, w as renderRivusModelCliArgumentError, y as loadMergedLocalEnvFile } from "./node-rivus-deployment-manifest.js";
1
+ import { S as deepFreeze, _ as loadMergedLocalEnvFile, b as validateRivusDeploymentManifest, c as parseRivusModelCliArguments, f as gatewayPackageManifestPath, g as loadRivusDaemonConfig, h as loadRivusDeploymentManifest, i as RIVUS_RELEASE_DESCRIPTOR, l as renderRivusModelCliArgumentError, m as gatewayTemplateDirectory, n as disposeRuntimeCacheEntries, r as invokeRuntimeControl, s as createRivusModelManagementWireRequest, t as createRuntimeCache, u as renderRivusModelCliHelp, v as resolveFeishuEndpointCredentials, x as validateRivusProjectSpaceDeployment, y as InvalidRivusProjectSpace } from "./runtime-cache.js";
2
+ import { n as narrowBackgroundSessionDefinition, t as createBackgroundSessionToolContracts } from "./background-session-authority.js";
3
3
  import { createRequire } from "node:module";
4
- import { Cause, Effect, Either, Exit } from "effect";
5
- import { RIVUS_MEMORY_TOOL_PLUGIN_ID, RIVUS_RUNTIME_TOOL_IDS, createRivusMemoryToolContract, isRivusRuntimeToolId } from "@rivus/runtime";
6
4
  import { createSha256Digest, createStableId } from "@rivus/platform/identity";
7
- import { randomUUID } from "node:crypto";
8
- import { lstat, mkdir, open, readFile, readdir, realpath, rmdir, stat, unlink, writeFile } from "node:fs/promises";
9
- import { createConnection } from "node:net";
10
- import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
+ import { RIVUS_MEMORY_TOOL_PLUGIN_ID, RIVUS_RUNTIME_TOOL_IDS, createRivusMemoryToolContract, isRivusRuntimeToolId } from "@rivus/runtime";
11
6
  import { homedir } from "node:os";
7
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
12
8
  import { fileURLToPath, pathToFileURL } from "node:url";
9
+ import { Cause, Effect, Either, Exit } from "effect";
10
+ import { lstat, mkdir, open, readFile, readdir, realpath, rmdir, stat, unlink, writeFile } from "node:fs/promises";
11
+ import { randomUUID } from "node:crypto";
13
12
  import { assertPathWithin, isPathWithin } from "@rivus/platform/filesystem";
13
+ import { createConnection } from "node:net";
14
14
  import { constants as constants$1 } from "node:fs";
15
- //#region src/core/application/agent-host/registry/agent-instance-registry.ts
16
- var AgentInstanceConflict = class extends Error {
17
- name = "AgentInstanceConflict";
18
- };
19
- function createEffectAgentInstanceRegistry(identity, options = {}) {
20
- const records = /* @__PURE__ */ new Map();
21
- for (const record of options.initialRecords ?? []) {
22
- if (bindingKey(record.binding, record.agentId) !== record.bindingKey) throw new AgentInstanceConflict(`invalid binding key: ${record.bindingKey}`);
23
- if (records.has(record.bindingKey)) throw new AgentInstanceConflict(`duplicate binding: ${record.bindingKey}`);
24
- records.set(record.bindingKey, freezeRecord(record));
25
- }
26
- const resolveBinding = (instanceBinding, definition) => Effect.try({
27
- try: () => {
28
- const runtimeGenerationId = identity.createRuntimeGenerationId({
29
- agentId: definition.agentId,
30
- profileRevision: definition.profileRevision,
31
- projectSpaceId: definition.projectSpaceId ?? null,
32
- projectSpaceRevision: definition.projectSpaceRevision ?? null,
33
- runtimeToolGrantRevision: definition.runtimeToolGrantSet.revision,
34
- skillGrantRevision: definition.skillGrantSet.revision,
35
- toolGrantRevision: definition.toolGrantSet.revision
36
- });
37
- const key = bindingKey(instanceBinding, definition.agentId);
38
- const existing = records.get(key);
39
- if (existing) {
40
- if (existing.runtimeGenerationId !== runtimeGenerationId) throw new AgentInstanceConflict(`binding ${key} belongs to a different runtime generation`);
41
- return existing;
42
- }
43
- const record = freezeRecord({
44
- agentId: definition.agentId,
45
- binding: instanceBinding,
46
- bindingKey: key,
47
- instanceId: identity.createInstanceId({
48
- bindingKey: key,
49
- runtimeGenerationId
50
- }),
51
- runtimeGenerationId
52
- });
53
- records.set(key, record);
54
- return record;
55
- },
56
- catch: (error) => error instanceof AgentInstanceConflict ? error : new AgentInstanceConflict(String(error))
57
- });
58
- return {
59
- resolveAutomation: (automationId, definition) => resolveBinding({
60
- automationId,
61
- kind: "automation"
62
- }, definition),
63
- resolveBackgroundSession: (agentId, definition) => resolveBinding({
64
- agentId,
65
- kind: "background-session"
66
- }, definition),
67
- resolveEndpoint: (endpointId, definition) => resolveBinding({
68
- endpointId,
69
- kind: "endpoint"
70
- }, definition),
71
- snapshot: () => Effect.sync(() => Object.freeze([...records.values()]))
72
- };
73
- }
74
- function bindingKey(binding, agentId) {
75
- const bindingId = binding.kind === "endpoint" ? binding.endpointId : binding.kind === "automation" ? binding.automationId : binding.agentId;
76
- return `${binding.kind}:${bindingId}:${agentId}`;
77
- }
78
- function freezeRecord(record) {
79
- return Object.freeze({
80
- ...record,
81
- binding: Object.freeze({ ...record.binding })
82
- });
83
- }
84
- //#endregion
85
- //#region src/core/application/agent-host/routing/agent-host.ts
86
- var InvalidAgentHostBinding = class extends Error {
87
- name = "InvalidAgentHostBinding";
88
- };
89
- function createEffectAgentHost(options) {
90
- return Effect.gen(function* () {
91
- const definitions = new Map(options.definitions.map((definition) => [definition.agentId, definition]));
92
- const endpoints = /* @__PURE__ */ new Map();
93
- const automations = /* @__PURE__ */ new Map();
94
- const backgroundSessions = /* @__PURE__ */ new Map();
95
- for (const endpoint of options.endpoints) {
96
- if (endpoints.has(endpoint.id)) return yield* Effect.fail(new InvalidAgentHostBinding(`duplicate endpoint: ${endpoint.id}`));
97
- const definition = definitions.get(endpoint.agentId);
98
- if (!definition) return yield* Effect.fail(new InvalidAgentHostBinding(`unknown endpoint agent: ${endpoint.agentId}`));
99
- if (!definition.endpointIds.includes(endpoint.id)) return yield* Effect.fail(new InvalidAgentHostBinding(`endpoint ${endpoint.id} is not declared by ${endpoint.agentId}`));
100
- endpoints.set(endpoint.id, yield* options.registry.resolveEndpoint(endpoint.id, definition));
101
- }
102
- for (const automation of options.automations ?? []) {
103
- if (automations.has(automation.id)) return yield* Effect.fail(new InvalidAgentHostBinding(`duplicate automation: ${automation.id}`));
104
- if (!definitions.has(automation.definition.agentId)) return yield* Effect.fail(new InvalidAgentHostBinding(`unknown automation agent: ${automation.definition.agentId}`));
105
- automations.set(automation.id, yield* options.registry.resolveAutomation(automation.id, automation.definition));
106
- }
107
- for (const backgroundSession of options.backgroundSessions ?? []) {
108
- if (backgroundSession.definition.agentId !== backgroundSession.agentId) return yield* Effect.fail(new InvalidAgentHostBinding(`background session ${backgroundSession.agentId} cannot bind definition ${backgroundSession.definition.agentId}`));
109
- if (backgroundSessions.has(backgroundSession.agentId)) return yield* Effect.fail(new InvalidAgentHostBinding(`duplicate background session agent: ${backgroundSession.agentId}`));
110
- if (!definitions.has(backgroundSession.agentId)) return yield* Effect.fail(new InvalidAgentHostBinding(`unknown background session agent: ${backgroundSession.agentId}`));
111
- backgroundSessions.set(backgroundSession.agentId, yield* options.registry.resolveBackgroundSession(backgroundSession.agentId, backgroundSession.definition));
112
- }
113
- const resolve = (records, id, message) => {
114
- const instance = records.get(id);
115
- return instance ? Effect.succeed(instance) : Effect.fail(new InvalidAgentHostBinding(message));
116
- };
117
- const resolveEndpoint = (endpointId) => resolve(endpoints, endpointId, `unknown endpoint: ${endpointId}`);
118
- const resolveAutomation = (automationId) => resolve(automations, automationId, `unknown automation: ${automationId}`);
119
- const resolveBackgroundSession = (agentId) => resolve(backgroundSessions, agentId, `unknown background session agent: ${agentId}`);
120
- return {
121
- cancelBackgroundSession: (agentId, input) => resolveBackgroundSession(agentId).pipe(Effect.flatMap((instance) => options.runtime.cancel(instance, input))),
122
- cancelEndpoint: (endpointId, input) => resolveEndpoint(endpointId).pipe(Effect.flatMap((instance) => options.runtime.cancel(instance, input))),
123
- dispose: () => options.runtime.disposeAll(),
124
- handleAutomation: (automationId, input) => resolveAutomation(automationId).pipe(Effect.flatMap((instance) => options.runtime.run(instance, input))),
125
- handleBackgroundSession: (agentId, input) => resolveBackgroundSession(agentId).pipe(Effect.flatMap((instance) => options.runtime.run(instance, input))),
126
- handleEndpoint: (endpointId, input) => resolveEndpoint(endpointId).pipe(Effect.flatMap((instance) => options.runtime.run(instance, input))),
127
- resolveAutomation,
128
- resolveBackgroundSession,
129
- resolveEndpoint,
130
- steerEndpoint: (endpointId, input) => resolveEndpoint(endpointId).pipe(Effect.flatMap((instance) => options.runtime.steer(instance, input)))
131
- };
132
- });
133
- }
134
- //#endregion
135
- //#region src/platform/runtime-pool/runtime-pool.ts
136
- var RuntimeResourceBusy = class extends Error {
137
- name = "RuntimeResourceBusy";
138
- };
139
- var RuntimeResourceDisposed = class extends Error {
140
- name = "RuntimeResourceDisposed";
141
- };
142
- var RuntimePoolDisposalTimedOut = class extends Error {
143
- name = "RuntimePoolDisposalTimedOut";
144
- };
145
- const DEFAULT_RUNTIME_DISPOSE_TIMEOUT_MS = 1e4;
146
- function createEffectRuntimePool(options) {
147
- const runtimes = createRuntimeCache();
148
- const active = /* @__PURE__ */ new Map();
149
- const lifecycle = Effect.unsafeMakeSemaphore(1);
150
- const existingRuntime = (instance) => Effect.gen(function* () {
151
- const selected = yield* runtimes.getExisting(instance.instanceId);
152
- if (!selected || !(yield* runtimes.isCurrent(instance.instanceId, selected.entry))) return void 0;
153
- return selected.runtime;
154
- });
155
- return {
156
- cancel: (instance, input) => invokeRuntimeControl(existingRuntime(instance), (runtime) => runtime.cancel?.(input)),
157
- disposeAll: () => Effect.gen(function* () {
158
- const entries = yield* runtimes.drain();
159
- yield* lifecycle.withPermits(1)(Effect.sync(() => active.clear()));
160
- yield* disposeRuntimeCacheEntries({
161
- dispose: (runtime) => runtime.dispose?.() ?? Effect.void,
162
- entries,
163
- failureMessage: "runtime pool disposal failed",
164
- timeout: {
165
- milliseconds: options.disposeTimeoutMs ?? DEFAULT_RUNTIME_DISPOSE_TIMEOUT_MS,
166
- onTimeout: () => new RuntimePoolDisposalTimedOut(`runtime pool disposal timed out after ${options.disposeTimeoutMs ?? DEFAULT_RUNTIME_DISPOSE_TIMEOUT_MS}ms`)
167
- }
168
- });
169
- }),
170
- run: (instance, input) => Effect.gen(function* () {
171
- const selected = yield* runtimes.getOrCreate(instance.instanceId, () => options.createRuntime(instance));
172
- if (!(yield* runtimes.isCurrent(instance.instanceId, selected.entry))) return yield* Effect.fail(new RuntimeResourceDisposed(`runtime was disposed before run start: ${instance.instanceId}`));
173
- if (selected.runtime.concurrency === "managed") return yield* selected.runtime.run(input);
174
- const token = yield* lifecycle.withPermits(1)(Effect.gen(function* () {
175
- if (!(yield* runtimes.isCurrent(instance.instanceId, selected.entry))) return yield* Effect.fail(new RuntimeResourceDisposed(`runtime was disposed before run start: ${instance.instanceId}`));
176
- if (active.has(instance.instanceId)) return yield* Effect.fail(new RuntimeResourceBusy(`runtime already has an active run: ${instance.instanceId}`));
177
- const activeToken = Symbol(instance.instanceId);
178
- active.set(instance.instanceId, activeToken);
179
- return activeToken;
180
- }));
181
- return yield* selected.runtime.run(input).pipe(Effect.ensuring(lifecycle.withPermits(1)(Effect.sync(() => {
182
- if (active.get(instance.instanceId) === token) active.delete(instance.instanceId);
183
- }))));
184
- }),
185
- steer: (instance, input) => invokeRuntimeControl(existingRuntime(instance), (runtime) => runtime.steer?.(input))
186
- };
187
- }
188
- //#endregion
189
- //#region src/adapters/agent/runtime/effect-agent-runtime-pool.ts
190
- var AgentInstanceBusy = class extends Error {
191
- name = "AgentInstanceBusy";
192
- };
193
- var AgentRuntimeDisposed = class extends Error {
194
- name = "AgentRuntimeDisposed";
195
- };
196
- function createAgentHostRuntimePool(factory, disposeTimeoutMs) {
197
- const pool = createEffectRuntimePool({
198
- createRuntime: (instance) => factory.create(instance),
199
- ...disposeTimeoutMs === void 0 ? {} : { disposeTimeoutMs }
200
- });
201
- return {
202
- cancel: (instance, input) => pool.cancel(instance, input),
203
- disposeAll: () => pool.disposeAll().pipe(Effect.mapError(mapRuntimePoolError)),
204
- run: (instance, input) => pool.run(instance, input).pipe(Effect.mapError(mapRuntimePoolError)),
205
- steer: (instance, steering) => pool.steer(instance, steering)
206
- };
207
- }
208
- function mapRuntimePoolError(error) {
209
- if (error instanceof RuntimeResourceBusy) return new AgentInstanceBusy(error.message.replace(/^runtime /, "agent instance "));
210
- if (error instanceof RuntimeResourceDisposed) return new AgentRuntimeDisposed(error.message.replace(/^runtime /, "agent runtime "));
211
- if (error instanceof RuntimePoolDisposalTimedOut) return new AgentRuntimeDisposed(error.message.replace(/^runtime pool /, "agent runtime "));
212
- return error;
213
- }
214
- //#endregion
15
+ import { unwrapExit } from "@rivus/platform/effect";
215
16
  //#region src/core/application/agent-catalog/contracts/rivus-plugin.ts
216
17
  const RIVUS_PLUGIN_API_VERSION = "1";
217
18
  var InvalidRivusPlugin = class extends Error {
@@ -276,7 +77,7 @@ function uniqueRivusRuntimeToolIds(ids, owner) {
276
77
  }
277
78
  //#endregion
278
79
  //#region src/core/application/agent-catalog/catalog/rivus-plugin-catalog.ts
279
- function createRivusPluginCatalog(runtime) {
80
+ function createRivusPluginCatalog$1(runtime) {
280
81
  const plugins = /* @__PURE__ */ new Map();
281
82
  const profiles = /* @__PURE__ */ new Map();
282
83
  const tools = /* @__PURE__ */ new Map();
@@ -352,19 +153,6 @@ function narrowRivusToolGrantSet(parent, restrictions, runtime) {
352
153
  toolIds
353
154
  });
354
155
  }
355
- function intersectRivusToolIds(sets, runtime) {
356
- const toolIds = intersectToolIds(sets);
357
- return runtime.deepFreeze({
358
- revision: runtime.digest(JSON.stringify(toolIds)),
359
- toolIds
360
- });
361
- }
362
- function createRivusToolGrantSetOperations(runtime) {
363
- return Object.freeze({
364
- intersect: (sets) => intersectRivusToolIds(sets, runtime),
365
- narrow: (parent, restrictions) => narrowRivusToolGrantSet(parent, restrictions, runtime)
366
- });
367
- }
368
156
  function intersectToolIds(sets) {
369
157
  const [first = [], ...rest] = sets;
370
158
  return [...new Set(first)].filter((id) => rest.every((set) => set.includes(id))).sort();
@@ -435,17 +223,17 @@ function uniqueScopes(scopes) {
435
223
  //#endregion
436
224
  //#region src/core/application/agent-catalog/resolution/rivus-agent-definition-resolver.ts
437
225
  function createRivusAgentDefinitionResolver(providers, runtime) {
438
- return Object.freeze({ resolve: (catalog, deployment) => resolveRivusAgentDefinition(catalog, deployment, providers, runtime) });
226
+ return Object.freeze({ resolve: (catalog, deployment) => resolveRivusAgentDefinition$1(catalog, deployment, providers, runtime) });
439
227
  }
440
228
  function createRivusAgentCatalog(providers, runtime) {
441
229
  const resolver = createRivusAgentDefinitionResolver(providers, runtime);
442
230
  return Object.freeze({
443
- createPluginCatalog: () => createRivusPluginCatalog(runtime),
231
+ createPluginCatalog: () => createRivusPluginCatalog$1(runtime),
444
232
  resolve: (catalog, deployment) => resolver.resolve(catalog, deployment),
445
233
  restrictGrants: (definition, restriction) => restrictRivusAgentDefinitionGrants(definition, restriction, runtime)
446
234
  });
447
235
  }
448
- function resolveRivusAgentDefinition(catalog, deployment, providers, runtime) {
236
+ function resolveRivusAgentDefinition$1(catalog, deployment, providers, runtime) {
449
237
  const snapshot = catalog.snapshot();
450
238
  const plugin = snapshot.plugins.find((candidate) => candidate.id === deployment.pluginId);
451
239
  if (!plugin) throw new InvalidRivusPlugin(`unknown deployment plugin: ${deployment.pluginId}`);
@@ -632,239 +420,19 @@ function toRuntimeContribution(tool) {
632
420
  });
633
421
  }
634
422
  //#endregion
635
- //#region src/platform/project/setup/rivus-project-initializer.ts
636
- const TEMPLATE_FILES = Object.freeze({
637
- "current-weather.mjs": "current-weather.mjs",
638
- "https-response-reader.mjs": "https-response-reader.mjs",
639
- "rivus-agents.plugin.mjs": "rivus-starter.plugin.mjs",
640
- "rivus.bootstrap.ts": "pi-feishu-deployment.bootstrap.ts"
423
+ //#region src/bootstrap/catalog/rivus-agent-catalog.ts
424
+ const runtime = Object.freeze({
425
+ digest: createSha256Digest,
426
+ deepFreeze
641
427
  });
642
- async function initializeRivusProject(options) {
643
- const directory = resolve(options.directory);
644
- const descriptor = options.releaseDescriptor ?? RIVUS_RELEASE_DESCRIPTOR;
645
- const files = /* @__PURE__ */ new Map([
646
- [".env.example", environmentTemplate$1()],
647
- [".gitignore", ".env.local\n.rivus/\nnode_modules/\n"],
648
- ["deploy/launchd/com.rivus.agent.plist", launchdService(directory, options.nodeExecutable)],
649
- ["deploy/systemd/rivus.service", systemdService(directory, options.nodeExecutable)],
650
- ["package.json", projectPackageJson(directory, descriptor)],
651
- ["rivus.config.json", deploymentManifest$1()]
652
- ]);
653
- for (const [target, source] of Object.entries(TEMPLATE_FILES)) files.set(target, await readFile(join(options.templateDirectory, source), "utf8"));
654
- const paths = [...files.keys()].sort();
655
- await assertSafeProjectAncestors(directory, paths);
656
- const conflicts = await findConflicts(directory, paths);
657
- if (conflicts.length > 0) throw new Error(`Rivus project initialization refused; refusing to overwrite: ${conflicts.join(", ")}`);
658
- const createdDirectories = [];
659
- const createdFiles = [];
660
- const writeProjectFile = options.writeProjectFile ?? writeExclusiveProjectFile;
661
- try {
662
- for (const path of paths) {
663
- const destination = join(directory, path);
664
- await ensureDirectory(dirname(destination), directory, createdDirectories);
665
- await assertSafeProjectAncestors(directory, [path]);
666
- await writeProjectFile(destination, files.get(path));
667
- createdFiles.push(destination);
668
- }
669
- } catch (error) {
670
- const rollbackErrors = await rollbackCreatedPaths(createdFiles, createdDirectories);
671
- if (rollbackErrors.length > 0) throw new AggregateError([error, ...rollbackErrors], "Rivus project initialization failed and rollback was incomplete");
672
- throw error;
673
- }
674
- return {
675
- directory,
676
- files: Object.freeze(paths)
677
- };
678
- }
679
- async function writeExclusiveProjectFile(path, contents) {
680
- await writeFile(path, contents, {
681
- encoding: "utf8",
682
- flag: "wx"
683
- });
684
- }
685
- async function assertSafeProjectAncestors(directory, paths) {
686
- const rootState = await lstatOrUndefined(directory);
687
- if (rootState?.isSymbolicLink()) throw new Error("Rivus project initialization refused; symbolic link ancestor: .");
688
- if (rootState && !rootState.isDirectory()) throw new Error("Rivus project initialization refused; project path is not a directory");
689
- if (!rootState) return;
690
- for (const path of paths) {
691
- let current = directory;
692
- for (const segment of path.split("/").slice(0, -1)) {
693
- current = join(current, segment);
694
- const state = await lstatOrUndefined(current);
695
- if (!state) break;
696
- if (state.isSymbolicLink()) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(directory, current)}`);
697
- if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${relative(directory, current)}`);
698
- }
699
- }
700
- }
701
- async function ensureDirectory(path, projectRoot, createdDirectories) {
702
- try {
703
- await mkdir(path);
704
- createdDirectories.push(path);
705
- } catch (error) {
706
- if (isMissingPath$1(error)) {
707
- const parent = dirname(path);
708
- if (parent === path) throw error;
709
- await ensureDirectory(parent, projectRoot, createdDirectories);
710
- await ensureDirectory(path, projectRoot, createdDirectories);
711
- return;
712
- }
713
- if (!isAlreadyExists(error)) throw error;
714
- const state = await lstat(path);
715
- if (state.isSymbolicLink()) {
716
- if (isPathWithin(projectRoot, path)) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(projectRoot, path) || "."}`);
717
- if ((await stat(path)).isDirectory()) return;
718
- }
719
- if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${path}`);
720
- }
721
- }
722
- async function rollbackCreatedPaths(files, directories) {
723
- const errors = [];
724
- for (const path of files.reverse()) try {
725
- await unlink(path);
726
- } catch (error) {
727
- if (!isMissingPath$1(error)) errors.push(asError$1(error));
728
- }
729
- for (const path of directories.reverse()) try {
730
- await rmdir(path);
731
- } catch (error) {
732
- if (!isMissingPath$1(error) && !isDirectoryNotEmpty(error)) errors.push(asError$1(error));
733
- }
734
- return errors;
735
- }
736
- async function lstatOrUndefined(path) {
737
- try {
738
- return await lstat(path);
739
- } catch (error) {
740
- if (isMissingPath$1(error)) return void 0;
741
- throw error;
742
- }
743
- }
744
- function isAlreadyExists(error) {
745
- return error instanceof Error && "code" in error && error.code === "EEXIST";
746
- }
747
- function isDirectoryNotEmpty(error) {
748
- return error instanceof Error && "code" in error && error.code === "ENOTEMPTY";
749
- }
750
- function asError$1(error) {
751
- return error instanceof Error ? error : new Error(String(error));
752
- }
753
- async function findConflicts(directory, paths) {
754
- const conflicts = [];
755
- for (const path of paths) try {
756
- await lstat(join(directory, path));
757
- conflicts.push(path);
758
- } catch (error) {
759
- if (!isMissingPath$1(error)) throw error;
760
- }
761
- return conflicts;
762
- }
763
- function isMissingPath$1(error) {
764
- return error instanceof Error && "code" in error && error.code === "ENOENT";
765
- }
766
- function projectPackageJson(directory, descriptor) {
767
- const { dependencies, version } = descriptor;
768
- const projectName = sanitizePackageName(basename(directory));
769
- return `${JSON.stringify({
770
- name: projectName,
771
- private: true,
772
- type: "module",
773
- scripts: {
774
- "check-config": "rivus --manifest ./rivus.config.json --check-config",
775
- doctor: "rivus doctor .",
776
- start: "rivus --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json"
777
- },
778
- dependencies: {
779
- "@earendil-works/pi-coding-agent": dependencies["@earendil-works/pi-coding-agent"],
780
- "@larksuiteoapi/node-sdk": dependencies["@larksuiteoapi/node-sdk"],
781
- "@rivus/agent": `^${version}`,
782
- effect: dependencies.effect
783
- }
784
- }, null, 2)}\n`;
785
- }
786
- function sanitizePackageName(value) {
787
- return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "") || "rivus-app";
788
- }
789
- function deploymentManifest$1() {
790
- return `${JSON.stringify({
791
- plugins: [{
792
- id: "rivus-starter",
793
- module: "./rivus-agents.plugin.mjs",
794
- required: true
795
- }],
796
- agents: [{
797
- agentId: "agent-a",
798
- endpointIds: ["feishu-agent-a"],
799
- pluginId: "rivus-starter",
800
- profileId: "agent-a",
801
- skills: { allow: [] },
802
- tools: { allow: ["rivus-starter/current-weather"] }
803
- }],
804
- defaultAgentId: "agent-a",
805
- defaultEndpointId: "feishu-agent-a",
806
- endpoints: [{
807
- agentId: "agent-a",
808
- baseUrl: "https://open.feishu.cn",
809
- cardStreamLeaseMs: 51e4,
810
- credentialRef: "env:RIVUS_FEISHU",
811
- enabled: true,
812
- experimental: { cotMessages: false },
813
- groupPolicy: "mention-only",
814
- id: "feishu-agent-a",
815
- progressDisplay: "collapsed",
816
- required: true,
817
- sessionNamespace: "rivus-starter",
818
- streamMinIntervalMs: 200
819
- }]
820
- }, null, 2)}\n`;
821
- }
822
- function environmentTemplate$1() {
823
- return [
824
- "# Copy this file to .env.local and keep the real values untracked.",
825
- "RIVUS_FEISHU_APP_ID=",
826
- "RIVUS_FEISHU_APP_SECRET=",
827
- "PI_MODEL=",
828
- "PI_API_KEY=",
829
- "# PI_BASE_URL=",
830
- "RIVUS_WEATHER_DEFAULT_LOCATION=上海",
831
- "# LANGFUSE_BASE_URL=https://jp.cloud.langfuse.com",
832
- "# LANGFUSE_PUBLIC_KEY=",
833
- "# LANGFUSE_SECRET_KEY=",
834
- "# RIVUS_TELEMETRY_CONTENT=redacted",
835
- ""
836
- ].join("\n");
837
- }
838
- function systemdService(directory, nodeExecutable) {
839
- const cli = join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js");
840
- 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`;
841
- }
842
- function systemdPath(value) {
843
- return value.replaceAll("%", "%%");
844
- }
845
- function systemdQuote(value) {
846
- return `"${value.replace(/%/g, "%%").replace(/\$/g, () => "$$").replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
847
- }
848
- function launchdService(directory, nodeExecutable) {
849
- 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${[
850
- nodeExecutable,
851
- join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js"),
852
- "--env-file",
853
- ".env.local",
854
- "--bootstrap",
855
- "./rivus.bootstrap.ts",
856
- "--manifest",
857
- "./rivus.config.json"
858
- ].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`;
428
+ function createRivusPluginCatalog() {
429
+ return createRivusPluginCatalog$1(runtime);
859
430
  }
860
- function xmlEscape(value) {
861
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
431
+ function createBootstrapAgentCatalog(backgroundSessions = false) {
432
+ return createRivusAgentCatalog([createRivusHostToolDescriptorProvider({ backgroundSessions })], runtime);
862
433
  }
863
- //#endregion
864
- //#region src/adapters/deployment/plugin/rivus-builtin-specifiers.ts
865
- const RIVUS_BUILTIN_SPECIFIERS = /* @__PURE__ */ new Map([["@rivus/agent/bootstrap/pi-feishu", "@rivus/gateway/bootstrap/pi-feishu"], ["@rivus/agent/plugin/starter", "@rivus/gateway/plugin/starter"]]);
866
- function resolveRivusBuiltinSpecifier(specifier) {
867
- return RIVUS_BUILTIN_SPECIFIERS.get(specifier) ?? specifier;
434
+ function resolveRivusAgentDefinition(catalog, deployment, options = {}) {
435
+ return createBootstrapAgentCatalog(options.backgroundSessions === true).resolve(catalog, deployment);
868
436
  }
869
437
  //#endregion
870
438
  //#region src/adapters/deployment/plugin/rivus-plugin-module.ts
@@ -872,13 +440,13 @@ function resolveRivusPluginModule(module) {
872
440
  const candidate = "default" in module ? module.default : module;
873
441
  return (typeof candidate === "function" ? Effect.tryPromise({
874
442
  try: () => Promise.resolve(candidate()),
875
- catch: toError$5
443
+ catch: toError$4
876
444
  }) : Effect.succeed(candidate)).pipe(Effect.flatMap((plugin) => isRivusPlugin(plugin) ? Effect.succeed(plugin) : Effect.fail(/* @__PURE__ */ new Error("plugin module default export is not a RivusPlugin or factory"))));
877
445
  }
878
446
  function isRivusPlugin(value) {
879
447
  return value !== null && typeof value === "object" && "manifest" in value && "register" in value && typeof value.register === "function";
880
448
  }
881
- function toError$5(error) {
449
+ function toError$4(error) {
882
450
  return error instanceof Error ? error : new Error(String(error));
883
451
  }
884
452
  //#endregion
@@ -886,7 +454,8 @@ function toError$5(error) {
886
454
  function findTrustedPackageRoot(packageManifestPath) {
887
455
  return Effect.tryPromise({
888
456
  try: async () => {
889
- const packageRoot = dirname(await realpath(packageManifestPath));
457
+ const manifestRealpath = await realpath(packageManifestPath);
458
+ const packageRoot = dirname(manifestRealpath);
890
459
  let current = packageRoot;
891
460
  for (;;) {
892
461
  if (basename(current) === "node_modules") return current;
@@ -917,206 +486,50 @@ function createNodeRivusPluginModuleLoader(options = {}) {
917
486
  function loadNodeRivusPluginModule(request, options = {}) {
918
487
  return resolveNodeRivusPluginModulePath(request, options).pipe(Effect.flatMap((resolvedRealpath) => Effect.tryPromise({
919
488
  try: () => import(pathToFileURL(resolvedRealpath).href),
920
- catch: toError$4
489
+ catch: toError$3
921
490
  })));
922
491
  }
923
492
  function resolveNodeRivusPluginModulePath(request, options = {}) {
924
493
  return Effect.gen(function* () {
925
494
  const deploymentRoot = yield* Effect.tryPromise({
926
495
  try: () => realpath(request.deploymentRoot),
927
- catch: toError$4
496
+ catch: toError$3
928
497
  });
929
- const moduleSpecifier = resolveRivusBuiltinSpecifier(request.module);
498
+ const moduleSpecifier = request.module;
930
499
  const relativeModule = moduleSpecifier.startsWith("./") || moduleSpecifier.startsWith("../");
931
500
  const resolutionManifest = relativeModule ? join(deploymentRoot, "package.json") : options.packageManifestPath ?? join(deploymentRoot, "package.json");
932
501
  const resolved = yield* Effect.try({
933
502
  try: () => createRequire(resolutionManifest).resolve(moduleSpecifier),
934
- catch: toError$4
503
+ catch: toError$3
935
504
  });
936
505
  const resolvedRealpath = yield* Effect.tryPromise({
937
506
  try: () => realpath(resolved),
938
- catch: toError$4
507
+ catch: toError$3
939
508
  });
940
509
  return yield* validateTrustedModulePath(relativeModule ? deploymentRoot : options.packageManifestPath ? yield* findTrustedPackageRoot(options.packageManifestPath) : deploymentRoot, resolvedRealpath, `plugin module ${request.module}`);
941
510
  });
942
511
  }
943
- function toError$4(error) {
512
+ function toError$3(error) {
944
513
  return error instanceof Error ? error : new Error(String(error));
945
514
  }
946
515
  //#endregion
947
- //#region src/adapters/deployment/inspection/rivus-project-doctor.ts
948
- const REQUIRED_FILES = Object.freeze([
949
- "package.json",
950
- "rivus.bootstrap.ts",
951
- "rivus.config.json"
952
- ]);
953
- const REQUIRED_DEPENDENCIES = Object.freeze([
954
- "@rivus/agent",
955
- "@earendil-works/pi-coding-agent",
956
- "@larksuiteoapi/node-sdk",
957
- "effect"
958
- ]);
959
- function diagnoseRivusProject(options) {
960
- return Effect.gen(function* () {
961
- const directory = resolve(options.directory);
962
- const checks = [checkNode$1(options.nodeVersion)];
963
- checks.push(yield* Effect.tryPromise({
964
- try: () => checkFiles(directory),
965
- catch: toError$3
966
- }));
967
- checks.push(yield* Effect.tryPromise({
968
- try: () => checkDependencies(directory),
969
- catch: toError$3
970
- }));
971
- const manifestResult = yield* checkManifest$1(directory);
972
- checks.push(manifestResult.check);
973
- const envFilePath = resolve(directory, options.envFilePath ?? ".env.local");
974
- checks.push(yield* Effect.tryPromise({
975
- try: () => checkCredentials$1(manifestResult.manifest, envFilePath, options.env),
976
- catch: toError$3
977
- }));
978
- return Object.freeze({
979
- checks: Object.freeze(checks),
980
- directory,
981
- ready: checks.every(({ status }) => status === "pass")
982
- });
983
- });
984
- }
985
- function checkNode$1(version) {
986
- const [major, minor] = version.split(".").map(Number);
987
- if (major === 24 && Number.isInteger(minor) && minor >= 11) return {
988
- message: `Node.js ${version} satisfies the supported ^24.11 runtime`,
989
- name: "node",
990
- status: "pass"
991
- };
992
- return {
993
- message: `Node.js 24.11 or newer on major 24 is required; current version is ${version}`,
994
- name: "node",
995
- status: "fail"
996
- };
516
+ //#region src/adapters/deployment/inspection/rivus-home-deployment-inspector.ts
517
+ const DEFAULT_BOOTSTRAP_PEERS = Object.freeze(["@earendil-works/pi-coding-agent", "@larksuiteoapi/node-sdk"]);
518
+ function createRivusHomeDeploymentInspector(options = {}) {
519
+ const resolveModule = options.resolveModule ?? ((specifier) => defaultResolveModule(specifier, options.packageManifestPath));
520
+ const resolvePluginModule = options.resolvePluginModule ?? ((request) => resolveNodeRivusPluginModulePath(request, options.packageManifestPath ? { packageManifestPath: options.packageManifestPath } : {}));
521
+ return { inspect: (input) => Effect.gen(function* () {
522
+ const manifestResult = yield* checkManifest$1(input.home);
523
+ const credentials = yield* checkCredentials$1(input.home, manifestResult.manifest, input.env, input.envFilePath);
524
+ const modules = yield* checkModules(input.home, manifestResult.manifest, resolveModule, resolvePluginModule);
525
+ return {
526
+ credentials,
527
+ manifest: manifestResult.check,
528
+ modules
529
+ };
530
+ }) };
997
531
  }
998
- async function checkFiles(directory) {
999
- const missing = await missingRegularFiles(directory, REQUIRED_FILES);
1000
- return missing.length === 0 ? {
1001
- message: "required project files are present",
1002
- name: "files",
1003
- status: "pass"
1004
- } : {
1005
- message: `required project files are missing: ${missing.join(", ")}`,
1006
- name: "files",
1007
- status: "fail"
1008
- };
1009
- }
1010
- async function checkDependencies(directory) {
1011
- const packageFiles = REQUIRED_DEPENDENCIES.map((name) => join("node_modules", ...name.split("/"), "package.json"));
1012
- const missingIndexes = new Set((await missingRegularFiles(directory, packageFiles)).map((path) => packageFiles.indexOf(path)));
1013
- const missing = REQUIRED_DEPENDENCIES.filter((_, index) => missingIndexes.has(index));
1014
- return missing.length === 0 ? {
1015
- message: "Rivus, Pi, Feishu, and Effect dependencies are installed",
1016
- name: "dependencies",
1017
- status: "pass"
1018
- } : {
1019
- message: `run npm install; missing local dependencies: ${missing.join(", ")}`,
1020
- name: "dependencies",
1021
- status: "fail"
1022
- };
1023
- }
1024
- function checkManifest$1(directory) {
1025
- return loadRivusDeploymentManifest(join(directory, "rivus.config.json")).pipe(Effect.flatMap((manifest) => Effect.gen(function* () {
1026
- validateRivusDeploymentManifest(manifest);
1027
- const missingModules = [];
1028
- for (const plugin of manifest.plugins) {
1029
- const result = yield* resolveNodeRivusPluginModulePath({
1030
- deploymentRoot: directory,
1031
- module: plugin.module,
1032
- pluginId: plugin.id
1033
- }).pipe(Effect.either);
1034
- if (Either.isLeft(result)) missingModules.push(plugin.module);
1035
- }
1036
- if (missingModules.length > 0) return { check: {
1037
- message: `manifest Plugin modules are missing: ${missingModules.join(", ")}`,
1038
- name: "manifest",
1039
- status: "fail"
1040
- } };
1041
- return {
1042
- check: {
1043
- message: "deployment manifest is valid",
1044
- name: "manifest",
1045
- status: "pass"
1046
- },
1047
- manifest
1048
- };
1049
- })), Effect.catchAll((error) => Effect.succeed({ check: {
1050
- message: `deployment manifest is invalid: ${error.message}`,
1051
- name: "manifest",
1052
- status: "fail"
1053
- } })));
1054
- }
1055
- async function checkCredentials$1(manifest, envFilePath, env) {
1056
- let mergedEnv;
1057
- try {
1058
- mergedEnv = await loadMergedLocalEnvFile(envFilePath, env);
1059
- } catch (error) {
1060
- return {
1061
- message: `required env file is unavailable at ${envFilePath}: ${error instanceof Error ? error.message : String(error)}`,
1062
- name: "credentials",
1063
- status: "fail"
1064
- };
1065
- }
1066
- if (!manifest) return {
1067
- message: "enabled Endpoint credentials cannot be checked until the deployment manifest is valid",
1068
- name: "credentials",
1069
- status: "fail"
1070
- };
1071
- try {
1072
- for (const endpoint of manifest.endpoints.filter(({ enabled }) => enabled)) resolveFeishuEndpointCredentials(endpoint.credentialRef, mergedEnv);
1073
- return {
1074
- message: "enabled Endpoint credential references resolve",
1075
- name: "credentials",
1076
- status: "pass"
1077
- };
1078
- } catch (error) {
1079
- return {
1080
- message: `enabled Endpoint credentials are incomplete: ${error instanceof Error ? error.message : String(error)}`,
1081
- name: "credentials",
1082
- status: "fail"
1083
- };
1084
- }
1085
- }
1086
- async function missingRegularFiles(directory, paths) {
1087
- const missing = [];
1088
- for (const path of paths) try {
1089
- if (!(await stat(resolve(directory, path))).isFile()) missing.push(path);
1090
- } catch (error) {
1091
- if (!isMissingPath(error)) throw error;
1092
- missing.push(path);
1093
- }
1094
- return missing;
1095
- }
1096
- function isMissingPath(error) {
1097
- return error instanceof Error && "code" in error && error.code === "ENOENT";
1098
- }
1099
- function toError$3(error) {
1100
- return error instanceof Error ? error : new Error(String(error));
1101
- }
1102
- //#endregion
1103
- //#region src/adapters/deployment/inspection/rivus-home-deployment-inspector.ts
1104
- const DEFAULT_BOOTSTRAP_PEERS = Object.freeze(["@earendil-works/pi-coding-agent", "@larksuiteoapi/node-sdk"]);
1105
- function createRivusHomeDeploymentInspector(options = {}) {
1106
- const resolveModule = options.resolveModule ?? ((specifier) => defaultResolveModule(specifier, options.packageManifestPath));
1107
- const resolvePluginModule = options.resolvePluginModule ?? ((request) => resolveNodeRivusPluginModulePath(request, options.packageManifestPath ? { packageManifestPath: options.packageManifestPath } : {}));
1108
- return { inspect: (input) => Effect.gen(function* () {
1109
- const manifestResult = yield* checkManifest(input.home);
1110
- const credentials = yield* checkCredentials(input.home, manifestResult.manifest, input.env, input.envFilePath);
1111
- const modules = yield* checkModules(input.home, manifestResult.manifest, resolveModule, resolvePluginModule);
1112
- return {
1113
- credentials,
1114
- manifest: manifestResult.check,
1115
- modules
1116
- };
1117
- }) };
1118
- }
1119
- function checkManifest(home) {
532
+ function checkManifest$1(home) {
1120
533
  return loadRivusDeploymentManifest(home.manifestPath).pipe(Effect.map((manifest) => {
1121
534
  validateRivusDeploymentManifest(manifest);
1122
535
  return {
@@ -1139,7 +552,7 @@ function checkModules(home, manifest, resolveModule, resolvePluginModule) {
1139
552
  name: "modules",
1140
553
  status: "fail"
1141
554
  });
1142
- const specifiers = [resolveRivusBuiltinSpecifier(home.bootstrap), ...home.bootstrap === "@rivus/agent/bootstrap/pi-feishu" || home.bootstrap === "@rivus/gateway/bootstrap/pi-feishu" ? DEFAULT_BOOTSTRAP_PEERS : []];
555
+ const specifiers = [home.bootstrap, ...home.bootstrap === "@rivus/gateway/bootstrap/pi-feishu" ? DEFAULT_BOOTSTRAP_PEERS : []];
1143
556
  return Effect.gen(function* () {
1144
557
  const missing = [];
1145
558
  for (const specifier of specifiers) {
@@ -1149,7 +562,7 @@ function checkModules(home, manifest, resolveModule, resolvePluginModule) {
1149
562
  for (const plugin of manifest.plugins) {
1150
563
  const result = yield* toEffect(() => resolvePluginModule({
1151
564
  deploymentRoot: home.directory,
1152
- module: resolveRivusBuiltinSpecifier(plugin.module),
565
+ module: plugin.module,
1153
566
  pluginId: plugin.id
1154
567
  })).pipe(Effect.either);
1155
568
  if (result._tag === "Left") missing.push(`${plugin.module} (${formatError(result.left)})`);
@@ -1179,7 +592,7 @@ function toEffect(read) {
1179
592
  }
1180
593
  });
1181
594
  }
1182
- function checkCredentials(home, manifest, env, envFilePath) {
595
+ function checkCredentials$1(home, manifest, env, envFilePath) {
1183
596
  if (!manifest) return Effect.succeed({
1184
597
  message: "credentials cannot be checked until manifest is valid",
1185
598
  name: "credentials",
@@ -1239,7 +652,7 @@ function loadRivusHome(directoryPath) {
1239
652
  workspaceDirectory: resolveHomePath(directory, config.workspace, "workspace")
1240
653
  };
1241
654
  },
1242
- catch: asError
655
+ catch: asError$1
1243
656
  });
1244
657
  }
1245
658
  function parseRivusHomeConfig(value) {
@@ -1279,14 +692,14 @@ function record(value, owner) {
1279
692
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${owner} must be an object`);
1280
693
  return value;
1281
694
  }
1282
- function asError(error) {
695
+ function asError$1(error) {
1283
696
  return error instanceof Error ? error : new Error(String(error));
1284
697
  }
1285
698
  //#endregion
1286
699
  //#region src/platform/home/doctor/rivus-home-doctor.ts
1287
700
  function diagnoseRivusHome(input, options) {
1288
701
  return Effect.gen(function* () {
1289
- const checks = [checkNode(input.nodeVersion)];
702
+ const checks = [checkNode$1(input.nodeVersion)];
1290
703
  const loaded = yield* options.load(input.directory).pipe(Effect.either);
1291
704
  if (Either.isLeft(loaded)) {
1292
705
  checks.push({
@@ -1312,7 +725,7 @@ function diagnoseRivusHome(input, options) {
1312
725
  return report(input.directory, checks);
1313
726
  });
1314
727
  }
1315
- function checkNode(version) {
728
+ function checkNode$1(version) {
1316
729
  const [major, minor] = version.split(".").map(Number);
1317
730
  return major === 24 && Number.isInteger(minor) && minor >= 11 ? {
1318
731
  message: `Node.js ${version} satisfies the supported ^24.11 runtime`,
@@ -1366,10 +779,10 @@ function createRivusHomeLayout() {
1366
779
  return {
1367
780
  directories: HOME_DIRECTORIES,
1368
781
  files: /* @__PURE__ */ new Map([
1369
- [".env.example", environmentTemplate()],
782
+ [".env.example", environmentTemplate$1()],
1370
783
  [".gitignore", ".DS_Store\n.env\nlogs/\nstate/\nworkspace/work/tmp/\n"],
1371
784
  ["config.json", homeConfig()],
1372
- ["rivus.config.json", deploymentManifest()],
785
+ ["rivus.config.json", deploymentManifest$1()],
1373
786
  ["workspace/AGENTS.md", agentsTemplate()],
1374
787
  ["workspace/IDENTITY.md", "# Identity\n\nName: Rivus\n\nRole: Personal agent\n"],
1375
788
  ["workspace/MEMORY.md", "# Curated Memory\n\nStore confirmed, durable facts and decisions here.\n"],
@@ -1395,7 +808,7 @@ function homeConfig() {
1395
808
  workspace: "workspace"
1396
809
  }, null, 2)}\n`;
1397
810
  }
1398
- function deploymentManifest() {
811
+ function deploymentManifest$1() {
1399
812
  return `${JSON.stringify({
1400
813
  agents: [{
1401
814
  agentId: "personal",
@@ -1448,7 +861,7 @@ function deploymentManifest() {
1448
861
  }]
1449
862
  }, null, 2)}\n`;
1450
863
  }
1451
- function environmentTemplate() {
864
+ function environmentTemplate$1() {
1452
865
  return [
1453
866
  "# Copy this file to .env and keep the real values untracked.",
1454
867
  "RIVUS_FEISHU_APP_ID=",
@@ -1632,7 +1045,7 @@ function shellQuote(value) {
1632
1045
  }
1633
1046
  //#endregion
1634
1047
  //#region src/adapters/cli/model/rivus-model-management-socket-client.ts
1635
- const MAX_FRAME_BYTES = 64 * 1024;
1048
+ const MAX_FRAME_BYTES = 65536;
1636
1049
  const DEFAULT_TIMEOUT_MS = 1e4;
1637
1050
  var RivusModelManagementTransportError = class extends Error {
1638
1051
  code;
@@ -1705,7 +1118,8 @@ function resolveRivusModelSocketPath(options) {
1705
1118
  return resolve(configured);
1706
1119
  }
1707
1120
  const configuredHome = optional(options.env.RIVUS_HOME);
1708
- return join(configuredHome ? resolveAbsoluteHome(configuredHome) : resolve(options.homeDirectory, ".rivus-agent"), RIVUS_MODEL_SOCKET_RELATIVE_PATH);
1121
+ const home = configuredHome ? resolveAbsoluteHome(configuredHome) : resolve(options.homeDirectory, ".rivus-agent");
1122
+ return join(home, RIVUS_MODEL_SOCKET_RELATIVE_PATH);
1709
1123
  }
1710
1124
  function isRivusModelManagementEnabled(env) {
1711
1125
  const value = optional(env[RIVUS_MODEL_MANAGEMENT_ENABLED_ENV]);
@@ -1715,8 +1129,393 @@ function resolveAbsoluteHome(value) {
1715
1129
  if (!isAbsolute(value)) throw new Error("RIVUS_HOME must be an absolute path");
1716
1130
  return resolve(value);
1717
1131
  }
1718
- function optional(value) {
1719
- return value?.trim() || void 0;
1132
+ function optional(value) {
1133
+ return value?.trim() || void 0;
1134
+ }
1135
+ //#endregion
1136
+ //#region src/adapters/deployment/inspection/rivus-project-doctor.ts
1137
+ const REQUIRED_FILES = Object.freeze([
1138
+ "package.json",
1139
+ "rivus.bootstrap.ts",
1140
+ "rivus.config.json"
1141
+ ]);
1142
+ const REQUIRED_DEPENDENCIES = Object.freeze([
1143
+ "@rivus/agent",
1144
+ "@earendil-works/pi-coding-agent",
1145
+ "@larksuiteoapi/node-sdk",
1146
+ "effect"
1147
+ ]);
1148
+ function diagnoseRivusProject(options) {
1149
+ return Effect.gen(function* () {
1150
+ const directory = resolve(options.directory);
1151
+ const checks = [checkNode(options.nodeVersion)];
1152
+ checks.push(yield* Effect.tryPromise({
1153
+ try: () => checkFiles(directory),
1154
+ catch: toError$1
1155
+ }));
1156
+ checks.push(yield* Effect.tryPromise({
1157
+ try: () => checkDependencies(directory),
1158
+ catch: toError$1
1159
+ }));
1160
+ const manifestResult = yield* checkManifest(directory);
1161
+ checks.push(manifestResult.check);
1162
+ const envFilePath = resolve(directory, options.envFilePath ?? ".env.local");
1163
+ checks.push(yield* Effect.tryPromise({
1164
+ try: () => checkCredentials(manifestResult.manifest, envFilePath, options.env),
1165
+ catch: toError$1
1166
+ }));
1167
+ return Object.freeze({
1168
+ checks: Object.freeze(checks),
1169
+ directory,
1170
+ ready: checks.every(({ status }) => status === "pass")
1171
+ });
1172
+ });
1173
+ }
1174
+ function checkNode(version) {
1175
+ const [major, minor] = version.split(".").map(Number);
1176
+ if (major === 24 && Number.isInteger(minor) && minor >= 11) return {
1177
+ message: `Node.js ${version} satisfies the supported ^24.11 runtime`,
1178
+ name: "node",
1179
+ status: "pass"
1180
+ };
1181
+ return {
1182
+ message: `Node.js 24.11 or newer on major 24 is required; current version is ${version}`,
1183
+ name: "node",
1184
+ status: "fail"
1185
+ };
1186
+ }
1187
+ async function checkFiles(directory) {
1188
+ const missing = await missingRegularFiles(directory, REQUIRED_FILES);
1189
+ return missing.length === 0 ? {
1190
+ message: "required project files are present",
1191
+ name: "files",
1192
+ status: "pass"
1193
+ } : {
1194
+ message: `required project files are missing: ${missing.join(", ")}`,
1195
+ name: "files",
1196
+ status: "fail"
1197
+ };
1198
+ }
1199
+ async function checkDependencies(directory) {
1200
+ const packageFiles = REQUIRED_DEPENDENCIES.map((name) => join("node_modules", ...name.split("/"), "package.json"));
1201
+ const missingIndexes = new Set((await missingRegularFiles(directory, packageFiles)).map((path) => packageFiles.indexOf(path)));
1202
+ const missing = REQUIRED_DEPENDENCIES.filter((_, index) => missingIndexes.has(index));
1203
+ return missing.length === 0 ? {
1204
+ message: "Rivus, Pi, Feishu, and Effect dependencies are installed",
1205
+ name: "dependencies",
1206
+ status: "pass"
1207
+ } : {
1208
+ message: `run npm install; missing local dependencies: ${missing.join(", ")}`,
1209
+ name: "dependencies",
1210
+ status: "fail"
1211
+ };
1212
+ }
1213
+ function checkManifest(directory) {
1214
+ return loadRivusDeploymentManifest(join(directory, "rivus.config.json")).pipe(Effect.flatMap((manifest) => Effect.gen(function* () {
1215
+ validateRivusDeploymentManifest(manifest);
1216
+ const missingModules = [];
1217
+ for (const plugin of manifest.plugins) {
1218
+ const result = yield* resolveNodeRivusPluginModulePath({
1219
+ deploymentRoot: directory,
1220
+ module: plugin.module,
1221
+ pluginId: plugin.id
1222
+ }).pipe(Effect.either);
1223
+ if (Either.isLeft(result)) missingModules.push(plugin.module);
1224
+ }
1225
+ if (missingModules.length > 0) return { check: {
1226
+ message: `manifest Plugin modules are missing: ${missingModules.join(", ")}`,
1227
+ name: "manifest",
1228
+ status: "fail"
1229
+ } };
1230
+ return {
1231
+ check: {
1232
+ message: "deployment manifest is valid",
1233
+ name: "manifest",
1234
+ status: "pass"
1235
+ },
1236
+ manifest
1237
+ };
1238
+ })), Effect.catchAll((error) => Effect.succeed({ check: {
1239
+ message: `deployment manifest is invalid: ${error.message}`,
1240
+ name: "manifest",
1241
+ status: "fail"
1242
+ } })));
1243
+ }
1244
+ async function checkCredentials(manifest, envFilePath, env) {
1245
+ let mergedEnv;
1246
+ try {
1247
+ mergedEnv = await loadMergedLocalEnvFile(envFilePath, env);
1248
+ } catch (error) {
1249
+ return {
1250
+ message: `required env file is unavailable at ${envFilePath}: ${error instanceof Error ? error.message : String(error)}`,
1251
+ name: "credentials",
1252
+ status: "fail"
1253
+ };
1254
+ }
1255
+ if (!manifest) return {
1256
+ message: "enabled Endpoint credentials cannot be checked until the deployment manifest is valid",
1257
+ name: "credentials",
1258
+ status: "fail"
1259
+ };
1260
+ try {
1261
+ for (const endpoint of manifest.endpoints.filter(({ enabled }) => enabled)) resolveFeishuEndpointCredentials(endpoint.credentialRef, mergedEnv);
1262
+ return {
1263
+ message: "enabled Endpoint credential references resolve",
1264
+ name: "credentials",
1265
+ status: "pass"
1266
+ };
1267
+ } catch (error) {
1268
+ return {
1269
+ message: `enabled Endpoint credentials are incomplete: ${error instanceof Error ? error.message : String(error)}`,
1270
+ name: "credentials",
1271
+ status: "fail"
1272
+ };
1273
+ }
1274
+ }
1275
+ async function missingRegularFiles(directory, paths) {
1276
+ const missing = [];
1277
+ for (const path of paths) try {
1278
+ if (!(await stat(resolve(directory, path))).isFile()) missing.push(path);
1279
+ } catch (error) {
1280
+ if (!isMissingPath$1(error)) throw error;
1281
+ missing.push(path);
1282
+ }
1283
+ return missing;
1284
+ }
1285
+ function isMissingPath$1(error) {
1286
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
1287
+ }
1288
+ function toError$1(error) {
1289
+ return error instanceof Error ? error : new Error(String(error));
1290
+ }
1291
+ //#endregion
1292
+ //#region src/platform/project/setup/rivus-project-initializer.ts
1293
+ const TEMPLATE_FILES = Object.freeze({
1294
+ "current-weather.mjs": "current-weather.mjs",
1295
+ "https-response-reader.mjs": "https-response-reader.mjs",
1296
+ "rivus-agents.plugin.mjs": "rivus-starter.plugin.mjs",
1297
+ "rivus.bootstrap.ts": "pi-feishu-deployment.bootstrap.ts"
1298
+ });
1299
+ async function initializeRivusProject(options) {
1300
+ const directory = resolve(options.directory);
1301
+ const descriptor = options.releaseDescriptor ?? RIVUS_RELEASE_DESCRIPTOR;
1302
+ const files = /* @__PURE__ */ new Map([
1303
+ [".env.example", environmentTemplate()],
1304
+ [".gitignore", ".env.local\n.rivus/\nnode_modules/\n"],
1305
+ ["deploy/launchd/com.rivus.agent.plist", launchdService(directory, options.nodeExecutable)],
1306
+ ["deploy/systemd/rivus.service", systemdService(directory, options.nodeExecutable)],
1307
+ ["package.json", projectPackageJson(directory, descriptor)],
1308
+ ["rivus.config.json", deploymentManifest()]
1309
+ ]);
1310
+ for (const [target, source] of Object.entries(TEMPLATE_FILES)) files.set(target, await readFile(join(options.templateDirectory, source), "utf8"));
1311
+ const paths = [...files.keys()].sort();
1312
+ await assertSafeProjectAncestors(directory, paths);
1313
+ const conflicts = await findConflicts(directory, paths);
1314
+ if (conflicts.length > 0) throw new Error(`Rivus project initialization refused; refusing to overwrite: ${conflicts.join(", ")}`);
1315
+ const createdDirectories = [];
1316
+ const createdFiles = [];
1317
+ const writeProjectFile = options.writeProjectFile ?? writeExclusiveProjectFile;
1318
+ try {
1319
+ for (const path of paths) {
1320
+ const destination = join(directory, path);
1321
+ await ensureDirectory(dirname(destination), directory, createdDirectories);
1322
+ await assertSafeProjectAncestors(directory, [path]);
1323
+ await writeProjectFile(destination, files.get(path));
1324
+ createdFiles.push(destination);
1325
+ }
1326
+ } catch (error) {
1327
+ const rollbackErrors = await rollbackCreatedPaths(createdFiles, createdDirectories);
1328
+ if (rollbackErrors.length > 0) throw new AggregateError([error, ...rollbackErrors], "Rivus project initialization failed and rollback was incomplete");
1329
+ throw error;
1330
+ }
1331
+ return {
1332
+ directory,
1333
+ files: Object.freeze(paths)
1334
+ };
1335
+ }
1336
+ async function writeExclusiveProjectFile(path, contents) {
1337
+ await writeFile(path, contents, {
1338
+ encoding: "utf8",
1339
+ flag: "wx"
1340
+ });
1341
+ }
1342
+ async function assertSafeProjectAncestors(directory, paths) {
1343
+ const rootState = await lstatOrUndefined(directory);
1344
+ if (rootState?.isSymbolicLink()) throw new Error("Rivus project initialization refused; symbolic link ancestor: .");
1345
+ if (rootState && !rootState.isDirectory()) throw new Error("Rivus project initialization refused; project path is not a directory");
1346
+ if (!rootState) return;
1347
+ for (const path of paths) {
1348
+ let current = directory;
1349
+ for (const segment of path.split("/").slice(0, -1)) {
1350
+ current = join(current, segment);
1351
+ const state = await lstatOrUndefined(current);
1352
+ if (!state) break;
1353
+ if (state.isSymbolicLink()) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(directory, current)}`);
1354
+ if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${relative(directory, current)}`);
1355
+ }
1356
+ }
1357
+ }
1358
+ async function ensureDirectory(path, projectRoot, createdDirectories) {
1359
+ try {
1360
+ await mkdir(path);
1361
+ createdDirectories.push(path);
1362
+ } catch (error) {
1363
+ if (isMissingPath(error)) {
1364
+ const parent = dirname(path);
1365
+ if (parent === path) throw error;
1366
+ await ensureDirectory(parent, projectRoot, createdDirectories);
1367
+ await ensureDirectory(path, projectRoot, createdDirectories);
1368
+ return;
1369
+ }
1370
+ if (!isAlreadyExists(error)) throw error;
1371
+ const state = await lstat(path);
1372
+ if (state.isSymbolicLink()) {
1373
+ if (isPathWithin(projectRoot, path)) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(projectRoot, path) || "."}`);
1374
+ if ((await stat(path)).isDirectory()) return;
1375
+ }
1376
+ if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${path}`);
1377
+ }
1378
+ }
1379
+ async function rollbackCreatedPaths(files, directories) {
1380
+ const errors = [];
1381
+ for (const path of files.reverse()) try {
1382
+ await unlink(path);
1383
+ } catch (error) {
1384
+ if (!isMissingPath(error)) errors.push(asError(error));
1385
+ }
1386
+ for (const path of directories.reverse()) try {
1387
+ await rmdir(path);
1388
+ } catch (error) {
1389
+ if (!isMissingPath(error) && !isDirectoryNotEmpty(error)) errors.push(asError(error));
1390
+ }
1391
+ return errors;
1392
+ }
1393
+ async function lstatOrUndefined(path) {
1394
+ try {
1395
+ return await lstat(path);
1396
+ } catch (error) {
1397
+ if (isMissingPath(error)) return;
1398
+ throw error;
1399
+ }
1400
+ }
1401
+ function isAlreadyExists(error) {
1402
+ return error instanceof Error && "code" in error && error.code === "EEXIST";
1403
+ }
1404
+ function isDirectoryNotEmpty(error) {
1405
+ return error instanceof Error && "code" in error && error.code === "ENOTEMPTY";
1406
+ }
1407
+ function asError(error) {
1408
+ return error instanceof Error ? error : new Error(String(error));
1409
+ }
1410
+ async function findConflicts(directory, paths) {
1411
+ const conflicts = [];
1412
+ for (const path of paths) try {
1413
+ await lstat(join(directory, path));
1414
+ conflicts.push(path);
1415
+ } catch (error) {
1416
+ if (!isMissingPath(error)) throw error;
1417
+ }
1418
+ return conflicts;
1419
+ }
1420
+ function isMissingPath(error) {
1421
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
1422
+ }
1423
+ function projectPackageJson(directory, descriptor) {
1424
+ const { dependencies, version } = descriptor;
1425
+ const projectName = sanitizePackageName(basename(directory));
1426
+ return `${JSON.stringify({
1427
+ name: projectName,
1428
+ private: true,
1429
+ type: "module",
1430
+ scripts: {
1431
+ "check-config": "rivus --manifest ./rivus.config.json --check-config",
1432
+ doctor: "rivus doctor .",
1433
+ start: "rivus --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json"
1434
+ },
1435
+ dependencies: {
1436
+ "@earendil-works/pi-coding-agent": dependencies["@earendil-works/pi-coding-agent"],
1437
+ "@larksuiteoapi/node-sdk": dependencies["@larksuiteoapi/node-sdk"],
1438
+ "@rivus/agent": `^${version}`,
1439
+ effect: dependencies.effect
1440
+ }
1441
+ }, null, 2)}\n`;
1442
+ }
1443
+ function sanitizePackageName(value) {
1444
+ return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "") || "rivus-app";
1445
+ }
1446
+ function deploymentManifest() {
1447
+ return `${JSON.stringify({
1448
+ plugins: [{
1449
+ id: "rivus-starter",
1450
+ module: "./rivus-agents.plugin.mjs",
1451
+ required: true
1452
+ }],
1453
+ agents: [{
1454
+ agentId: "agent-a",
1455
+ endpointIds: ["feishu-agent-a"],
1456
+ pluginId: "rivus-starter",
1457
+ profileId: "agent-a",
1458
+ skills: { allow: [] },
1459
+ tools: { allow: ["rivus-starter/current-weather"] }
1460
+ }],
1461
+ defaultAgentId: "agent-a",
1462
+ defaultEndpointId: "feishu-agent-a",
1463
+ endpoints: [{
1464
+ agentId: "agent-a",
1465
+ baseUrl: "https://open.feishu.cn",
1466
+ cardStreamLeaseMs: 51e4,
1467
+ credentialRef: "env:RIVUS_FEISHU",
1468
+ enabled: true,
1469
+ experimental: { cotMessages: false },
1470
+ groupPolicy: "mention-only",
1471
+ id: "feishu-agent-a",
1472
+ progressDisplay: "collapsed",
1473
+ required: true,
1474
+ sessionNamespace: "rivus-starter",
1475
+ streamMinIntervalMs: 200
1476
+ }]
1477
+ }, null, 2)}\n`;
1478
+ }
1479
+ function environmentTemplate() {
1480
+ return [
1481
+ "# Copy this file to .env.local and keep the real values untracked.",
1482
+ "RIVUS_FEISHU_APP_ID=",
1483
+ "RIVUS_FEISHU_APP_SECRET=",
1484
+ "PI_MODEL=",
1485
+ "PI_API_KEY=",
1486
+ "# PI_BASE_URL=",
1487
+ "RIVUS_WEATHER_DEFAULT_LOCATION=上海",
1488
+ "# LANGFUSE_BASE_URL=https://jp.cloud.langfuse.com",
1489
+ "# LANGFUSE_PUBLIC_KEY=",
1490
+ "# LANGFUSE_SECRET_KEY=",
1491
+ "# RIVUS_TELEMETRY_CONTENT=redacted",
1492
+ ""
1493
+ ].join("\n");
1494
+ }
1495
+ function systemdService(directory, nodeExecutable) {
1496
+ const cli = join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js");
1497
+ 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`;
1498
+ }
1499
+ function systemdPath(value) {
1500
+ return value.replaceAll("%", "%%");
1501
+ }
1502
+ function systemdQuote(value) {
1503
+ return `"${value.replace(/%/g, "%%").replace(/\$/g, () => "$$").replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
1504
+ }
1505
+ function launchdService(directory, nodeExecutable) {
1506
+ 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${[
1507
+ nodeExecutable,
1508
+ join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js"),
1509
+ "--env-file",
1510
+ ".env.local",
1511
+ "--bootstrap",
1512
+ "./rivus.bootstrap.ts",
1513
+ "--manifest",
1514
+ "./rivus.config.json"
1515
+ ].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`;
1516
+ }
1517
+ function xmlEscape(value) {
1518
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1720
1519
  }
1721
1520
  //#endregion
1722
1521
  //#region src/adapters/openclaw/config/openclaw-env-import.ts
@@ -1987,12 +1786,12 @@ async function runRivusRecoveryCliCommand(control, command) {
1987
1786
  deliveryId: command.deliveryId,
1988
1787
  endpointId: command.endpointId,
1989
1788
  expectedRevision: command.expectedRevision,
1990
- note: await readPrivateTextFile(command.noteFilePath, "Recovery note", 16 * 1024)
1789
+ note: await readPrivateTextFile(command.noteFilePath, "Recovery note", 16384)
1991
1790
  }));
1992
1791
  case "resolve-tool-operation": {
1993
- const note = await readPrivateTextFile(command.noteFilePath, "Recovery note", 16 * 1024);
1792
+ const note = await readPrivateTextFile(command.noteFilePath, "Recovery note", 16384);
1994
1793
  const outcome = command.outcome.status === "applied" ? {
1995
- result: parseToolResult(await readPrivateTextFile(command.outcome.resultFilePath, "Tool result", 1024 * 1024)),
1794
+ result: parseToolResult(await readPrivateTextFile(command.outcome.resultFilePath, "Tool result", 1048576)),
1996
1795
  status: "applied"
1997
1796
  } : command.outcome;
1998
1797
  return Effect.runPromise(control.resolveToolOperation({
@@ -3056,98 +2855,210 @@ function createRivusDaemonShutdownController(options) {
3056
2855
  };
3057
2856
  }
3058
2857
  //#endregion
3059
- //#region src/adapters/deployment/process/process-deployment-adapters.ts
3060
- function createProcessDeploymentAdapterPorts(factories, runEffect) {
2858
+ //#region src/platform/runtime-pool/runtime-pool.ts
2859
+ var RuntimeResourceBusy = class extends Error {
2860
+ name = "RuntimeResourceBusy";
2861
+ };
2862
+ var RuntimeResourceDisposed = class extends Error {
2863
+ name = "RuntimeResourceDisposed";
2864
+ };
2865
+ var RuntimePoolDisposalTimedOut = class extends Error {
2866
+ name = "RuntimePoolDisposalTimedOut";
2867
+ };
2868
+ const DEFAULT_RUNTIME_DISPOSE_TIMEOUT_MS = 1e4;
2869
+ function createEffectRuntimePool(options) {
2870
+ const runtimes = createRuntimeCache();
2871
+ const active = /* @__PURE__ */ new Map();
2872
+ const lifecycle = Effect.unsafeMakeSemaphore(1);
2873
+ const existingRuntime = (instance) => Effect.gen(function* () {
2874
+ const selected = yield* runtimes.getExisting(instance.instanceId);
2875
+ if (!selected || !(yield* runtimes.isCurrent(instance.instanceId, selected.entry))) return;
2876
+ return selected.runtime;
2877
+ });
3061
2878
  return {
3062
- ...factories.createAutomation ? { automationFactory: { create: (input) => adaptAutomationFactory(factories.createAutomation, input, runEffect) } } : {},
3063
- ...factories.createBackgroundSession ? { backgroundSessionFactory: { create: (input) => adaptBackgroundSessionFactory(factories.createBackgroundSession, input, runEffect) } } : {},
3064
- endpointFactory: { create: (input) => adaptEndpointFactory(factories.createEndpoint, input, runEffect) },
3065
- runtimeFactory: { create: (input) => Effect.tryPromise({
3066
- try: () => Promise.resolve(factories.createRuntime(input)),
3067
- catch: toError$1
3068
- }).pipe(Effect.map((runtime) => toEffectAgentRuntime(runtime, runEffect))) }
2879
+ cancel: (instance, input) => invokeRuntimeControl(existingRuntime(instance), (runtime) => runtime.cancel?.(input)),
2880
+ disposeAll: () => Effect.gen(function* () {
2881
+ const entries = yield* runtimes.drain();
2882
+ yield* lifecycle.withPermits(1)(Effect.sync(() => active.clear()));
2883
+ yield* disposeRuntimeCacheEntries({
2884
+ dispose: (runtime) => runtime.dispose?.() ?? Effect.void,
2885
+ entries,
2886
+ failureMessage: "runtime pool disposal failed",
2887
+ timeout: {
2888
+ milliseconds: options.disposeTimeoutMs ?? DEFAULT_RUNTIME_DISPOSE_TIMEOUT_MS,
2889
+ onTimeout: () => new RuntimePoolDisposalTimedOut(`runtime pool disposal timed out after ${options.disposeTimeoutMs ?? DEFAULT_RUNTIME_DISPOSE_TIMEOUT_MS}ms`)
2890
+ }
2891
+ });
2892
+ }),
2893
+ run: (instance, input) => Effect.gen(function* () {
2894
+ const selected = yield* runtimes.getOrCreate(instance.instanceId, () => options.createRuntime(instance));
2895
+ if (!(yield* runtimes.isCurrent(instance.instanceId, selected.entry))) return yield* Effect.fail(new RuntimeResourceDisposed(`runtime was disposed before run start: ${instance.instanceId}`));
2896
+ if (selected.runtime.concurrency === "managed") return yield* selected.runtime.run(input);
2897
+ const token = yield* lifecycle.withPermits(1)(Effect.gen(function* () {
2898
+ if (!(yield* runtimes.isCurrent(instance.instanceId, selected.entry))) return yield* Effect.fail(new RuntimeResourceDisposed(`runtime was disposed before run start: ${instance.instanceId}`));
2899
+ if (active.has(instance.instanceId)) return yield* Effect.fail(new RuntimeResourceBusy(`runtime already has an active run: ${instance.instanceId}`));
2900
+ const activeToken = Symbol(instance.instanceId);
2901
+ active.set(instance.instanceId, activeToken);
2902
+ return activeToken;
2903
+ }));
2904
+ return yield* selected.runtime.run(input).pipe(Effect.ensuring(lifecycle.withPermits(1)(Effect.sync(() => {
2905
+ if (active.get(instance.instanceId) === token) active.delete(instance.instanceId);
2906
+ }))));
2907
+ }),
2908
+ steer: (instance, input) => invokeRuntimeControl(existingRuntime(instance), (runtime) => runtime.steer?.(input))
3069
2909
  };
3070
2910
  }
3071
- function adaptEndpointFactory(create, input, runEffect) {
3072
- return Effect.tryPromise({
3073
- try: async () => {
3074
- return toLifecycleAdapter(await create({
3075
- agentId: input.agentId,
3076
- cancel: (request) => runEffect(input.cancel(request)),
3077
- definition: input.definition,
3078
- endpointId: input.endpointId,
3079
- handle: (request) => runEffect(input.handle(toEffectAgentRuntimeInput(request))),
3080
- instanceId: input.instanceId,
3081
- ...input.projectSpaceId ? { projectSpaceId: input.projectSpaceId } : {},
3082
- steer: (request) => runEffect(input.steer(request))
3083
- }));
3084
- },
3085
- catch: toError$1
2911
+ //#endregion
2912
+ //#region src/adapters/agent/runtime/effect-agent-runtime-pool.ts
2913
+ var AgentInstanceBusy = class extends Error {
2914
+ name = "AgentInstanceBusy";
2915
+ };
2916
+ var AgentRuntimeDisposed = class extends Error {
2917
+ name = "AgentRuntimeDisposed";
2918
+ };
2919
+ function createAgentHostRuntimePool(factory, disposeTimeoutMs) {
2920
+ const pool = createEffectRuntimePool({
2921
+ createRuntime: (instance) => factory.create(instance),
2922
+ ...disposeTimeoutMs === void 0 ? {} : { disposeTimeoutMs }
3086
2923
  });
2924
+ return {
2925
+ cancel: (instance, input) => pool.cancel(instance, input),
2926
+ disposeAll: () => pool.disposeAll().pipe(Effect.mapError((error) => error instanceof AggregateError && error.errors.length === 1 ? error.errors[0] : mapRuntimePoolError(error))),
2927
+ run: (instance, input) => pool.run(instance, input).pipe(Effect.mapError(mapRuntimePoolError)),
2928
+ steer: (instance, steering) => pool.steer(instance, steering)
2929
+ };
3087
2930
  }
3088
- function adaptAutomationFactory(create, input, runEffect) {
3089
- return Effect.tryPromise({
3090
- try: async () => toLifecycleAdapter(await create({
3091
- automationId: input.automationId,
3092
- definition: input.definition,
3093
- deliveryEndpoint: input.deliveryEndpoint,
3094
- instanceId: input.instanceId,
3095
- run: (request) => runEffect(input.run(request))
3096
- })),
3097
- catch: toError$1
3098
- });
2931
+ function mapRuntimePoolError(error) {
2932
+ if (error instanceof RuntimeResourceBusy) return new AgentInstanceBusy(error.message.replace(/^runtime /, "agent instance "));
2933
+ if (error instanceof RuntimeResourceDisposed) return new AgentRuntimeDisposed(error.message.replace(/^runtime /, "agent runtime "));
2934
+ if (error instanceof RuntimePoolDisposalTimedOut) return new AgentRuntimeDisposed(error.message.replace(/^runtime pool /, "agent runtime "));
2935
+ return error;
3099
2936
  }
3100
- function adaptBackgroundSessionFactory(create, input, runEffect) {
3101
- return Effect.tryPromise({
3102
- try: async () => {
3103
- const adapter = await create({
3104
- agentIds: input.agentIds,
3105
- cancel: (request) => runEffect(input.cancel(request)),
3106
- config: input.config,
3107
- run: (request) => runEffect(input.run({
3108
- agentId: request.agentId,
3109
- invocation: request.invocation,
3110
- ...request.onUpdate ? { onUpdate: (update) => Effect.tryPromise({
3111
- try: async () => request.onUpdate(update),
3112
- catch: toError$1
3113
- }) } : {},
3114
- sessionKey: request.sessionKey,
3115
- text: request.text
3116
- }))
2937
+ //#endregion
2938
+ //#region src/core/application/agent-host/registry/agent-instance-registry.ts
2939
+ var AgentInstanceConflict = class extends Error {
2940
+ name = "AgentInstanceConflict";
2941
+ };
2942
+ function createEffectAgentInstanceRegistry(identity, options = {}) {
2943
+ const records = /* @__PURE__ */ new Map();
2944
+ for (const record of options.initialRecords ?? []) {
2945
+ if (bindingKey(record.binding, record.agentId) !== record.bindingKey) throw new AgentInstanceConflict(`invalid binding key: ${record.bindingKey}`);
2946
+ if (records.has(record.bindingKey)) throw new AgentInstanceConflict(`duplicate binding: ${record.bindingKey}`);
2947
+ records.set(record.bindingKey, freezeRecord(record));
2948
+ }
2949
+ const resolveBinding = (instanceBinding, definition) => Effect.try({
2950
+ try: () => {
2951
+ const runtimeGenerationId = identity.createRuntimeGenerationId({
2952
+ agentId: definition.agentId,
2953
+ profileRevision: definition.profileRevision,
2954
+ projectSpaceId: definition.projectSpaceId ?? null,
2955
+ projectSpaceRevision: definition.projectSpaceRevision ?? null,
2956
+ runtimeToolGrantRevision: definition.runtimeToolGrantSet.revision,
2957
+ skillGrantRevision: definition.skillGrantSet.revision,
2958
+ toolGrantRevision: definition.toolGrantSet.revision
3117
2959
  });
3118
- return {
3119
- ...toLifecycleAdapter(adapter),
3120
- ...adapter.status ? { status: () => adapter.status() } : {}
3121
- };
2960
+ const key = bindingKey(instanceBinding, definition.agentId);
2961
+ const existing = records.get(key);
2962
+ if (existing) {
2963
+ if (existing.runtimeGenerationId !== runtimeGenerationId) throw new AgentInstanceConflict(`binding ${key} belongs to a different runtime generation`);
2964
+ return existing;
2965
+ }
2966
+ const record = freezeRecord({
2967
+ agentId: definition.agentId,
2968
+ binding: instanceBinding,
2969
+ bindingKey: key,
2970
+ instanceId: identity.createInstanceId({
2971
+ bindingKey: key,
2972
+ runtimeGenerationId
2973
+ }),
2974
+ runtimeGenerationId
2975
+ });
2976
+ records.set(key, record);
2977
+ return record;
3122
2978
  },
3123
- catch: toError$1
2979
+ catch: (error) => error instanceof AgentInstanceConflict ? error : new AgentInstanceConflict(String(error))
3124
2980
  });
3125
- }
3126
- function toLifecycleAdapter(adapter) {
3127
2981
  return {
3128
- running: () => adapter.running(),
3129
- start: () => Effect.tryPromise({
3130
- try: () => Promise.resolve(adapter.start()),
3131
- catch: toError$1
3132
- }),
3133
- stop: () => Effect.tryPromise({
3134
- try: () => Promise.resolve(adapter.stop()),
3135
- catch: toError$1
3136
- })
2982
+ resolveAutomation: (automationId, definition) => resolveBinding({
2983
+ automationId,
2984
+ kind: "automation"
2985
+ }, definition),
2986
+ resolveBackgroundSession: (agentId, definition) => resolveBinding({
2987
+ agentId,
2988
+ kind: "background-session"
2989
+ }, definition),
2990
+ resolveEndpoint: (endpointId, definition) => resolveBinding({
2991
+ endpointId,
2992
+ kind: "endpoint"
2993
+ }, definition),
2994
+ snapshot: () => Effect.sync(() => Object.freeze([...records.values()]))
3137
2995
  };
3138
2996
  }
3139
- function toError$1(error) {
3140
- return error instanceof Error ? error : new Error(String(error));
2997
+ function bindingKey(binding, agentId) {
2998
+ const bindingId = binding.kind === "endpoint" ? binding.endpointId : binding.kind === "automation" ? binding.automationId : binding.agentId;
2999
+ return `${binding.kind}:${bindingId}:${agentId}`;
3000
+ }
3001
+ function freezeRecord(record) {
3002
+ return Object.freeze({
3003
+ ...record,
3004
+ binding: Object.freeze({ ...record.binding })
3005
+ });
3006
+ }
3007
+ //#endregion
3008
+ //#region src/core/application/agent-host/routing/agent-host.ts
3009
+ var InvalidAgentHostBinding = class extends Error {
3010
+ name = "InvalidAgentHostBinding";
3011
+ };
3012
+ function createEffectAgentHost(options) {
3013
+ return Effect.gen(function* () {
3014
+ const definitions = new Map(options.definitions.map((definition) => [definition.agentId, definition]));
3015
+ const endpoints = /* @__PURE__ */ new Map();
3016
+ const automations = /* @__PURE__ */ new Map();
3017
+ const backgroundSessions = /* @__PURE__ */ new Map();
3018
+ for (const endpoint of options.endpoints) {
3019
+ if (endpoints.has(endpoint.id)) return yield* Effect.fail(new InvalidAgentHostBinding(`duplicate endpoint: ${endpoint.id}`));
3020
+ const definition = definitions.get(endpoint.agentId);
3021
+ if (!definition) return yield* Effect.fail(new InvalidAgentHostBinding(`unknown endpoint agent: ${endpoint.agentId}`));
3022
+ if (!definition.endpointIds.includes(endpoint.id)) return yield* Effect.fail(new InvalidAgentHostBinding(`endpoint ${endpoint.id} is not declared by ${endpoint.agentId}`));
3023
+ endpoints.set(endpoint.id, yield* options.registry.resolveEndpoint(endpoint.id, definition));
3024
+ }
3025
+ for (const automation of options.automations ?? []) {
3026
+ if (automations.has(automation.id)) return yield* Effect.fail(new InvalidAgentHostBinding(`duplicate automation: ${automation.id}`));
3027
+ if (!definitions.has(automation.definition.agentId)) return yield* Effect.fail(new InvalidAgentHostBinding(`unknown automation agent: ${automation.definition.agentId}`));
3028
+ automations.set(automation.id, yield* options.registry.resolveAutomation(automation.id, automation.definition));
3029
+ }
3030
+ for (const backgroundSession of options.backgroundSessions ?? []) {
3031
+ if (backgroundSession.definition.agentId !== backgroundSession.agentId) return yield* Effect.fail(new InvalidAgentHostBinding(`background session ${backgroundSession.agentId} cannot bind definition ${backgroundSession.definition.agentId}`));
3032
+ if (backgroundSessions.has(backgroundSession.agentId)) return yield* Effect.fail(new InvalidAgentHostBinding(`duplicate background session agent: ${backgroundSession.agentId}`));
3033
+ if (!definitions.has(backgroundSession.agentId)) return yield* Effect.fail(new InvalidAgentHostBinding(`unknown background session agent: ${backgroundSession.agentId}`));
3034
+ backgroundSessions.set(backgroundSession.agentId, yield* options.registry.resolveBackgroundSession(backgroundSession.agentId, backgroundSession.definition));
3035
+ }
3036
+ const resolve = (records, id, message) => {
3037
+ const instance = records.get(id);
3038
+ return instance ? Effect.succeed(instance) : Effect.fail(new InvalidAgentHostBinding(message));
3039
+ };
3040
+ const resolveEndpoint = (endpointId) => resolve(endpoints, endpointId, `unknown endpoint: ${endpointId}`);
3041
+ const resolveAutomation = (automationId) => resolve(automations, automationId, `unknown automation: ${automationId}`);
3042
+ const resolveBackgroundSession = (agentId) => resolve(backgroundSessions, agentId, `unknown background session agent: ${agentId}`);
3043
+ return {
3044
+ cancelBackgroundSession: (agentId, input) => resolveBackgroundSession(agentId).pipe(Effect.flatMap((instance) => options.runtime.cancel(instance, input))),
3045
+ cancelEndpoint: (endpointId, input) => resolveEndpoint(endpointId).pipe(Effect.flatMap((instance) => options.runtime.cancel(instance, input))),
3046
+ dispose: () => options.runtime.disposeAll(),
3047
+ handleAutomation: (automationId, input) => resolveAutomation(automationId).pipe(Effect.flatMap((instance) => options.runtime.run(instance, input))),
3048
+ handleBackgroundSession: (agentId, input) => resolveBackgroundSession(agentId).pipe(Effect.flatMap((instance) => options.runtime.run(instance, input))),
3049
+ handleEndpoint: (endpointId, input) => resolveEndpoint(endpointId).pipe(Effect.flatMap((instance) => options.runtime.run(instance, input))),
3050
+ resolveAutomation,
3051
+ resolveBackgroundSession,
3052
+ resolveEndpoint,
3053
+ steerEndpoint: (endpointId, input) => resolveEndpoint(endpointId).pipe(Effect.flatMap((instance) => options.runtime.steer(instance, input)))
3054
+ };
3055
+ });
3141
3056
  }
3142
3057
  //#endregion
3143
3058
  //#region src/bootstrap/deployment/deployment-control-ports.ts
3144
- const agentCatalogRuntime = Object.freeze({
3145
- digest: createSha256Digest,
3146
- deepFreeze
3147
- });
3148
- function createProcessDeploymentControlPorts(factories, backgroundSessions, runEffect) {
3059
+ function createProcessDeploymentControlPorts(factories, backgroundSessions) {
3149
3060
  return {
3150
- agentCatalog: createRivusAgentCatalog([createRivusHostToolDescriptorProvider({ backgroundSessions })], agentCatalogRuntime),
3061
+ agentCatalog: createBootstrapAgentCatalog(backgroundSessions),
3151
3062
  agentHostFactory: { create: (input) => {
3152
3063
  const registry = createEffectAgentInstanceRegistry({
3153
3064
  createInstanceId: (identity) => createStableId("instance", identity),
@@ -3163,7 +3074,10 @@ function createProcessDeploymentControlPorts(factories, backgroundSessions, runE
3163
3074
  runtime
3164
3075
  });
3165
3076
  } },
3166
- ...createProcessDeploymentAdapterPorts(factories, runEffect)
3077
+ runtimeFactory: { create: factories.createRuntime },
3078
+ endpointFactory: { create: factories.createEndpoint },
3079
+ ...factories.createAutomation ? { automationFactory: { create: factories.createAutomation } } : {},
3080
+ ...factories.createBackgroundSession ? { backgroundSessionFactory: { create: factories.createBackgroundSession } } : {}
3167
3081
  };
3168
3082
  }
3169
3083
  //#endregion
@@ -3473,7 +3387,8 @@ function prepareDeployment(input) {
3473
3387
  definitions,
3474
3388
  deployment: effectiveDeployment,
3475
3389
  endpointSlots,
3476
- host
3390
+ host,
3391
+ projectSpaces
3477
3392
  };
3478
3393
  });
3479
3394
  }
@@ -3612,6 +3527,8 @@ function makeDeploymentControl(input) {
3612
3527
  let degraded = input.deployment.plugins.some(({ status: pluginStatus }) => pluginStatus === "failed");
3613
3528
  for (const slot of input.endpointSlots) degraded = (yield* startSlot(slot, slot.agentEnabled, `endpoint ${slot.definition.id}`, () => Effect.gen(function* () {
3614
3529
  const instance = yield* input.host.resolveEndpoint(slot.definition.id);
3530
+ const agentDefinition = input.definitions.get(slot.definition.agentId);
3531
+ const projectSpace = agentDefinition?.projectSpaceId ? input.projectSpaces.get(agentDefinition.projectSpaceId) : void 0;
3615
3532
  return yield* input.endpointFactory.create({
3616
3533
  agentId: slot.definition.agentId,
3617
3534
  cancel: (request) => input.host.cancelEndpoint(slot.definition.id, request),
@@ -3619,7 +3536,9 @@ function makeDeploymentControl(input) {
3619
3536
  endpointId: slot.definition.id,
3620
3537
  handle: (request) => handleEndpoint(slot.definition.id, request),
3621
3538
  instanceId: instance.instanceId,
3622
- ...input.definitions.get(slot.definition.agentId)?.projectSpaceId ? { projectSpaceId: input.definitions.get(slot.definition.agentId).projectSpaceId } : {},
3539
+ ...agentDefinition ? { runtimeDefinition: agentDefinition } : {},
3540
+ ...projectSpace ? { projectSpace } : {},
3541
+ ...agentDefinition?.projectSpaceId ? { projectSpaceId: agentDefinition.projectSpaceId } : {},
3623
3542
  steer: (request) => input.host.steerEndpoint(slot.definition.id, request)
3624
3543
  });
3625
3544
  }))) || degraded;
@@ -3888,22 +3807,22 @@ function trimOptional(value) {
3888
3807
  async function createRivusDeploymentCliProcess(factory, context) {
3889
3808
  const adapters = await factory(context);
3890
3809
  let adaptersDisposed = false;
3891
- let recoveryControlPromise;
3892
3810
  const disposeAdapters = async () => {
3893
3811
  if (adaptersDisposed) return;
3894
3812
  adaptersDisposed = true;
3895
3813
  await adapters.dispose?.();
3896
3814
  };
3897
3815
  let daemon;
3816
+ let openRecovery;
3898
3817
  try {
3899
- daemon = await runDeploymentProcessEffect(loadRivusDeploymentManifest(context.manifestPath).pipe(Effect.flatMap((manifest) => {
3818
+ const constructed = unwrapExit(await Effect.runPromiseExit(loadRivusDeploymentManifest(context.manifestPath).pipe(Effect.flatMap((manifest) => {
3900
3819
  const assemblyInput = {
3901
3820
  ...createProcessDeploymentControlPorts({
3902
3821
  ...adapters.createAutomation ? { createAutomation: adapters.createAutomation } : {},
3903
3822
  ...adapters.createBackgroundSession ? { createBackgroundSession: adapters.createBackgroundSession } : {},
3904
3823
  createEndpoint: adapters.createEndpoint,
3905
3824
  createRuntime: adapters.createRuntime
3906
- }, manifest.backgroundSessions?.enabled === true, runDeploymentProcessEffect),
3825
+ }, manifest.backgroundSessions?.enabled === true),
3907
3826
  deploymentRoot: dirname(context.manifestPath),
3908
3827
  ...adapters.initialInstanceRecords ? { initialInstanceRecords: adapters.initialInstanceRecords } : {},
3909
3828
  manifest,
@@ -3922,7 +3841,15 @@ async function createRivusDeploymentCliProcess(factory, context) {
3922
3841
  deployment,
3923
3842
  digest: createSha256Digest
3924
3843
  })));
3925
- })));
3844
+ })).pipe(Effect.flatMap((control) => Effect.gen(function* () {
3845
+ const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL(Effect.suspend(() => adapters.createRecoveryControl ? adapters.createRecoveryControl() : Effect.fail(/* @__PURE__ */ new Error("Deployment bootstrap does not expose Recovery Control"))), Infinity);
3846
+ return {
3847
+ control,
3848
+ openRecovery: cached.pipe(Effect.onExit((exit) => Exit.isFailure(exit) && !Cause.isInterruptedOnly(exit.cause) ? invalidate : Effect.void))
3849
+ };
3850
+ })))));
3851
+ daemon = constructed.control;
3852
+ openRecovery = constructed.openRecovery;
3926
3853
  } catch (constructionError) {
3927
3854
  try {
3928
3855
  await disposeAdapters();
@@ -3931,91 +3858,45 @@ async function createRivusDeploymentCliProcess(factory, context) {
3931
3858
  }
3932
3859
  throw constructionError;
3933
3860
  }
3934
- const start = async () => {
3935
- if (adaptersDisposed) throw new Error("Rivus deployment process cannot restart after its adapters have been disposed");
3936
- try {
3937
- await runDeploymentProcessEffect(daemon.start());
3938
- } catch (startError) {
3939
- const cleanupErrors = [];
3940
- try {
3941
- await runDeploymentProcessEffect(daemon.stop());
3942
- } catch (error) {
3943
- cleanupErrors.push(error);
3944
- }
3945
- try {
3946
- await disposeAdapters();
3947
- } catch (error) {
3948
- cleanupErrors.push(error);
3949
- }
3950
- if (cleanupErrors.length > 0) throw new AggregateError([startError, ...cleanupErrors], "deployment startup and cleanup failed");
3951
- throw startError;
3952
- }
3953
- };
3954
- const stop = async () => {
3955
- const errors = [];
3956
- try {
3957
- await runDeploymentProcessEffect(daemon.stop());
3958
- } catch (error) {
3959
- errors.push(error);
3960
- }
3961
- try {
3962
- await disposeAdapters();
3963
- } catch (error) {
3964
- errors.push(error);
3965
- }
3966
- if (errors.length === 1) throw errors[0];
3967
- if (errors.length > 1) throw new AggregateError(errors, "deployment and adapter cleanup failed");
3968
- };
3861
+ const cleanupErrors = Effect.all([Effect.exit(Effect.suspend(() => daemon.stop())), Effect.exit(Effect.tryPromise({
3862
+ try: disposeAdapters,
3863
+ catch: (error) => error
3864
+ }))]).pipe(Effect.map((exits) => exits.filter(Exit.isFailure).map((exit) => Cause.squash(exit.cause))));
3865
+ const startDeployment = Effect.uninterruptible(Effect.suspend(() => {
3866
+ if (adaptersDisposed) return Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot restart after its adapters have been disposed"));
3867
+ return Effect.suspend(() => daemon.start()).pipe(Effect.catchAllCause((cause) => {
3868
+ const startError = Cause.squash(cause);
3869
+ return cleanupErrors.pipe(Effect.flatMap((errors) => Effect.fail(errors.length > 0 ? new AggregateError([startError, ...errors], "deployment startup and cleanup failed") : startError)));
3870
+ }));
3871
+ }));
3872
+ const stopDeployment = Effect.uninterruptible(cleanupErrors.pipe(Effect.flatMap((errors) => {
3873
+ if (errors.length === 1) return Effect.fail(errors[0]);
3874
+ if (errors.length > 1) return Effect.fail(new AggregateError(errors, "deployment and adapter cleanup failed"));
3875
+ return Effect.void;
3876
+ })));
3969
3877
  const process = {
3970
3878
  defaultSessionKey: `local:${daemon.deployment.manifest.defaultAgentId}:cli`,
3971
- openRecoveryControl: () => Effect.tryPromise({
3972
- try: async () => {
3973
- if (adaptersDisposed) throw new Error("Rivus deployment process cannot open Recovery Control after disposal");
3974
- if (!adapters.createRecoveryControl) throw new Error("Deployment bootstrap does not expose Recovery Control");
3975
- recoveryControlPromise ??= Promise.resolve().then(() => adapters.createRecoveryControl());
3976
- try {
3977
- return await recoveryControlPromise;
3978
- } catch (error) {
3979
- recoveryControlPromise = void 0;
3980
- throw error;
3981
- }
3982
- },
3983
- catch: (error) => error
3984
- }),
3879
+ openRecoveryControl: () => Effect.suspend(() => adaptersDisposed ? Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot open Recovery Control after disposal")) : openRecovery),
3985
3880
  running: () => daemon.running(),
3986
- start: () => Effect.tryPromise({
3987
- try: start,
3988
- catch: (error) => error
3989
- }),
3881
+ start: () => startDeployment,
3990
3882
  status: () => Effect.sync(() => daemon.status()),
3991
- stop: () => Effect.tryPromise({
3992
- try: stop,
3993
- catch: (error) => error
3994
- }),
3995
- promptText: (command) => Effect.tryPromise({
3996
- try: async () => {
3997
- if (adaptersDisposed) throw new Error("Rivus deployment process cannot restart after its adapters have been disposed");
3998
- const projectSpaceId = daemon.deployment.definitions.find(({ agentId }) => agentId === daemon.deployment.manifest.defaultAgentId)?.projectSpaceId;
3999
- return readPromptFinalText(await runDeploymentProcessEffect(daemon.runDefaultAgent({
4000
- invocation: createLocalCliAgentInvocation({
4001
- endpointId: daemon.deployment.manifest.defaultEndpointId,
4002
- env: context.env,
4003
- ...projectSpaceId ? { projectSpaceId } : {}
4004
- }),
4005
- sessionKey: command.sessionKey,
4006
- text: command.text
4007
- })));
4008
- },
4009
- catch: (error) => error
4010
- })
3883
+ stop: () => stopDeployment,
3884
+ promptText: (command) => Effect.suspend(() => {
3885
+ if (adaptersDisposed) return Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot restart after its adapters have been disposed"));
3886
+ const projectSpaceId = daemon.deployment.definitions.find(({ agentId }) => agentId === daemon.deployment.manifest.defaultAgentId)?.projectSpaceId;
3887
+ return daemon.runDefaultAgent({
3888
+ invocation: createLocalCliAgentInvocation({
3889
+ endpointId: daemon.deployment.manifest.defaultEndpointId,
3890
+ env: context.env,
3891
+ ...projectSpaceId ? { projectSpaceId } : {}
3892
+ }),
3893
+ sessionKey: command.sessionKey,
3894
+ text: command.text
3895
+ }).pipe(Effect.map(readPromptFinalText));
3896
+ }).pipe(Effect.catchAllCause((cause) => Effect.fail(Cause.squash(cause))))
4011
3897
  };
4012
3898
  const replayReceiveMessage = adapters.replayReceiveMessage;
4013
- if (replayReceiveMessage) process.replayReceiveMessage = (payload, options) => Effect.tryPromise({
4014
- try: async () => {
4015
- if (!daemon.running()) await start();
4016
- },
4017
- catch: (error) => error
4018
- }).pipe(Effect.flatMap(() => replayReceiveMessage((input) => runDeploymentProcessEffect(daemon.handleDefault(toEffectAgentRuntimeInput(input))), payload, options)));
3899
+ if (replayReceiveMessage) process.replayReceiveMessage = (payload, options) => Effect.suspend(() => daemon.running() ? Effect.void : startDeployment).pipe(Effect.flatMap(() => replayReceiveMessage((input) => daemon.handleDefault(input), payload, options)));
4019
3900
  return process;
4020
3901
  }
4021
3902
  function readPromptFinalText(result) {
@@ -4063,8 +3944,7 @@ function runRivusDaemonCli(options) {
4063
3944
  try: () => loadCliEnv(parsed.envFilePath, options.env),
4064
3945
  catch: (error) => error
4065
3946
  });
4066
- const configuredBootstrapSpecifier = parsed.bootstrap ?? env.RIVUS_BOOTSTRAP_MODULE?.trim();
4067
- const bootstrapSpecifier = configuredBootstrapSpecifier ? resolveRivusBuiltinSpecifier(configuredBootstrapSpecifier) : void 0;
3947
+ const bootstrapSpecifier = parsed.bootstrap ?? env.RIVUS_BOOTSTRAP_MODULE?.trim();
4068
3948
  if (!parsed.checkConfig && !bootstrapSpecifier) {
4069
3949
  options.stderr.write(formatRivusDaemonUsageError("Missing --bootstrap <module> or RIVUS_BOOTSTRAP_MODULE"));
4070
3950
  return 1;
@@ -4461,4 +4341,5 @@ function toImportSpecifier(specifier) {
4461
4341
  return specifier;
4462
4342
  }
4463
4343
  //#endregion
4464
- export { InvalidRivusPlugin as A, createRivusHostToolDescriptorProvider as C, validateRivusCatalogIdentifier as D, createRivusPluginCatalog as E, InvalidAgentHostBinding as F, createEffectAgentHost as I, AgentInstanceConflict as L, AgentInstanceBusy as M, AgentRuntimeDisposed as N, validateRivusCatalogRegistration as O, createAgentHostRuntimePool as P, createEffectAgentInstanceRegistry as R, initializeRivusProject as S, createRivusToolGrantSetOperations as T, formatRivusEnvFile as _, resolveRivusProjectSpace as a, loadNodeRivusPluginModule as b, RivusDeploymentReadinessError as c, RivusPluginLoadError as d, resolveRivusDeployment as f, createRivusEnvFromOpenClawConfig as g, OpenClawEnvImportError as h, createRivusDeploymentCliProcess as i, RIVUS_PLUGIN_API_VERSION as j, validateRivusPluginManifest as k, createRivusDeploymentControl as l, createRivusDaemonShutdownController as m, runRivusCli as n, RivusDeploymentAutomationReadinessError as o, createProcessDeploymentControlPorts as p, runRivusDaemonCli as r, RivusDeploymentBackgroundSessionReadinessError as s, runRivusNodeEntrypoint as t, RivusDeploymentDaemonLifecycleError as u, diagnoseRivusProject as v, createRivusAgentCatalog as w, resolveRivusPluginModule as x, createNodeRivusPluginModuleLoader as y };
4344
+ export { RIVUS_PLUGIN_API_VERSION as i, createRivusPluginCatalog as n, resolveRivusAgentDefinition as r, runRivusNodeEntrypoint as t };
4345
+