@rivus/gateway 0.16.6 → 0.18.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 +853 -0
  5. package/dist/bootstrap/pi-feishu.d.ts +281 -16
  6. package/dist/bootstrap/pi-feishu.js +17315 -345
  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 +735 -847
  10. package/dist/chunks/{node-rivus-deployment-manifest.js → runtime-cache.js} +1118 -1476
  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, Deferred, Effect, Exit, Result, Semaphore } 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
- };
428
+ function createRivusPluginCatalog() {
429
+ return createRivusPluginCatalog$1(runtime);
678
430
  }
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`;
431
+ function createBootstrapAgentCatalog(backgroundSessions = false) {
432
+ return createRivusAgentCatalog([createRivusHostToolDescriptorProvider({ backgroundSessions })], runtime);
859
433
  }
860
- function xmlEscape(value) {
861
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
862
- }
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 {
@@ -1127,7 +540,7 @@ function checkManifest(home) {
1127
540
  },
1128
541
  manifest
1129
542
  };
1130
- }), Effect.catchAll((error) => Effect.succeed({ check: {
543
+ }), Effect.catch((error) => Effect.succeed({ check: {
1131
544
  message: `deployment manifest is invalid: ${formatError(error)}`,
1132
545
  name: "manifest",
1133
546
  status: "fail"
@@ -1139,20 +552,20 @@ 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) {
1146
- const result = yield* toEffect(() => resolveModule(specifier)).pipe(Effect.either);
1147
- if (result._tag === "Left") missing.push(`${specifier} (${formatError(result.left)})`);
559
+ const result = yield* toEffect(() => resolveModule(specifier)).pipe(Effect.result);
560
+ if (result._tag === "Failure") missing.push(`${specifier} (${formatError(result.failure)})`);
1148
561
  }
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
- })).pipe(Effect.either);
1155
- if (result._tag === "Left") missing.push(`${plugin.module} (${formatError(result.left)})`);
567
+ })).pipe(Effect.result);
568
+ if (result._tag === "Failure") missing.push(`${plugin.module} (${formatError(result.failure)})`);
1156
569
  }
1157
570
  return missing.length === 0 ? {
1158
571
  message: "Bootstrap, Plugin, Pi, and Feishu modules resolve from the global installation",
@@ -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",
@@ -1196,7 +609,7 @@ function checkCredentials(home, manifest, env, envFilePath) {
1196
609
  };
1197
610
  },
1198
611
  catch: toError$2
1199
- }).pipe(Effect.catchAll((error) => Effect.succeed({
612
+ }).pipe(Effect.catch((error) => Effect.succeed({
1200
613
  message: `enabled Endpoint credentials are incomplete: ${formatError(error)}`,
1201
614
  name: "credentials",
1202
615
  status: "fail"
@@ -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,24 +692,24 @@ 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)];
1290
- const loaded = yield* options.load(input.directory).pipe(Effect.either);
1291
- if (Either.isLeft(loaded)) {
702
+ const checks = [checkNode$1(input.nodeVersion)];
703
+ const loaded = yield* options.load(input.directory).pipe(Effect.result);
704
+ if (Result.isFailure(loaded)) {
1292
705
  checks.push({
1293
- message: `Rivus Home is invalid: ${loaded.left.message}`,
706
+ message: `Rivus Home is invalid: ${loaded.failure.message}`,
1294
707
  name: "home",
1295
708
  status: "fail"
1296
709
  }, blockedCheck("workspace", "Workspace"), blockedCheck("manifest", "manifest"), blockedCheck("modules", "modules"), blockedCheck("credentials", "credentials"));
1297
710
  return report(input.directory, checks);
1298
711
  }
1299
- const home = loaded.right;
712
+ const home = loaded.success;
1300
713
  checks.push({
1301
714
  message: "config.json is valid and contained in Rivus Home",
1302
715
  name: "home",
@@ -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.result);
1223
+ if (Result.isFailure(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.catch((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 = Semaphore.makeUnsafe(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
@@ -3207,10 +3121,10 @@ function resolveRivusDeployment(input) {
3207
3121
  return plugin;
3208
3122
  },
3209
3123
  catch: toDeploymentFailure
3210
- })), Effect.either);
3211
- if (Either.isLeft(loaded)) {
3212
- const message = formatDeploymentFailure(loaded.left);
3213
- if (declaration.required) return yield* Effect.fail(new RivusPluginLoadError(declaration.id, declaration.module, `required plugin ${declaration.id} failed to load: ${message}`, { cause: loaded.left }));
3124
+ })), Effect.result);
3125
+ if (Result.isFailure(loaded)) {
3126
+ const message = formatDeploymentFailure(loaded.failure);
3127
+ if (declaration.required) return yield* Effect.fail(new RivusPluginLoadError(declaration.id, declaration.module, `required plugin ${declaration.id} failed to load: ${message}`, { cause: loaded.failure }));
3214
3128
  const status = Object.freeze({
3215
3129
  error: message,
3216
3130
  id: declaration.id,
@@ -3227,7 +3141,7 @@ function resolveRivusDeployment(input) {
3227
3141
  module: declaration.module,
3228
3142
  required: declaration.required,
3229
3143
  status: "loaded",
3230
- version: loaded.right.manifest.version
3144
+ version: loaded.success.manifest.version
3231
3145
  });
3232
3146
  pluginStatuses.push(status);
3233
3147
  statusByPlugin.set(declaration.id, status);
@@ -3261,23 +3175,23 @@ function resolveRivusDeployment(input) {
3261
3175
  }) : baseDefinition;
3262
3176
  },
3263
3177
  catch: toDeploymentFailure
3264
- }).pipe(Effect.either);
3265
- if (Either.isLeft(resolved)) {
3178
+ }).pipe(Effect.result);
3179
+ if (Result.isFailure(resolved)) {
3266
3180
  const declaration = input.manifest.plugins.find(({ id }) => id === agent.pluginId);
3267
- if (declaration.required) return yield* Effect.fail(new RivusPluginLoadError(declaration.id, declaration.module, `deployment ${agent.agentId} failed to resolve: ${resolved.left.message}`, { cause: resolved.left }));
3181
+ if (declaration.required) return yield* Effect.fail(new RivusPluginLoadError(declaration.id, declaration.module, `deployment ${agent.agentId} failed to resolve: ${resolved.failure.message}`, { cause: resolved.failure }));
3268
3182
  agentStatuses.push(Object.freeze({
3269
3183
  agentId: agent.agentId,
3270
3184
  pluginId: agent.pluginId,
3271
3185
  profileId: agent.profileId,
3272
- reason: resolved.left.message,
3186
+ reason: resolved.failure.message,
3273
3187
  status: "disabled"
3274
3188
  }));
3275
3189
  continue;
3276
3190
  }
3277
- definitions.push(resolved.right);
3191
+ definitions.push(resolved.success);
3278
3192
  agentStatuses.push(Object.freeze({
3279
3193
  agentId: agent.agentId,
3280
- definition: resolved.right,
3194
+ definition: resolved.success,
3281
3195
  pluginId: agent.pluginId,
3282
3196
  profileId: agent.profileId,
3283
3197
  status: "enabled"
@@ -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,22 @@ async function createRivusDeploymentCliProcess(factory, context) {
3922
3841
  deployment,
3923
3842
  digest: createSha256Digest
3924
3843
  })));
3925
- })));
3844
+ })).pipe(Effect.map((control) => {
3845
+ let opening;
3846
+ return {
3847
+ control,
3848
+ openRecovery: Effect.uninterruptible(Effect.suspend(() => {
3849
+ if (opening) return Deferred.await(opening);
3850
+ const current = Deferred.makeUnsafe();
3851
+ opening = current;
3852
+ return Effect.suspend(() => adapters.createRecoveryControl ? adapters.createRecoveryControl() : Effect.fail(/* @__PURE__ */ new Error("Deployment bootstrap does not expose Recovery Control"))).pipe(Effect.onExit((exit) => Effect.sync(() => {
3853
+ if (Exit.isFailure(exit) && opening === current) opening = void 0;
3854
+ }).pipe(Effect.andThen(Deferred.done(current, exit)))));
3855
+ }))
3856
+ };
3857
+ }))));
3858
+ daemon = constructed.control;
3859
+ openRecovery = constructed.openRecovery;
3926
3860
  } catch (constructionError) {
3927
3861
  try {
3928
3862
  await disposeAdapters();
@@ -3931,91 +3865,45 @@ async function createRivusDeploymentCliProcess(factory, context) {
3931
3865
  }
3932
3866
  throw constructionError;
3933
3867
  }
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
- };
3868
+ const cleanupErrors = Effect.all([Effect.exit(Effect.suspend(() => daemon.stop())), Effect.exit(Effect.tryPromise({
3869
+ try: disposeAdapters,
3870
+ catch: (error) => error
3871
+ }))]).pipe(Effect.map((exits) => exits.filter(Exit.isFailure).map((exit) => Cause.squash(exit.cause))));
3872
+ const startDeployment = Effect.uninterruptible(Effect.suspend(() => {
3873
+ if (adaptersDisposed) return Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot restart after its adapters have been disposed"));
3874
+ return Effect.suspend(() => daemon.start()).pipe(Effect.catchCause((cause) => {
3875
+ const startError = Cause.squash(cause);
3876
+ return cleanupErrors.pipe(Effect.flatMap((errors) => Effect.fail(errors.length > 0 ? new AggregateError([startError, ...errors], "deployment startup and cleanup failed") : startError)));
3877
+ }));
3878
+ }));
3879
+ const stopDeployment = Effect.uninterruptible(cleanupErrors.pipe(Effect.flatMap((errors) => {
3880
+ if (errors.length === 1) return Effect.fail(errors[0]);
3881
+ if (errors.length > 1) return Effect.fail(new AggregateError(errors, "deployment and adapter cleanup failed"));
3882
+ return Effect.void;
3883
+ })));
3969
3884
  const process = {
3970
3885
  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
- }),
3886
+ openRecoveryControl: () => Effect.suspend(() => adaptersDisposed ? Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot open Recovery Control after disposal")) : openRecovery),
3985
3887
  running: () => daemon.running(),
3986
- start: () => Effect.tryPromise({
3987
- try: start,
3988
- catch: (error) => error
3989
- }),
3888
+ start: () => startDeployment,
3990
3889
  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
- })
3890
+ stop: () => stopDeployment,
3891
+ promptText: (command) => Effect.suspend(() => {
3892
+ if (adaptersDisposed) return Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot restart after its adapters have been disposed"));
3893
+ const projectSpaceId = daemon.deployment.definitions.find(({ agentId }) => agentId === daemon.deployment.manifest.defaultAgentId)?.projectSpaceId;
3894
+ return daemon.runDefaultAgent({
3895
+ invocation: createLocalCliAgentInvocation({
3896
+ endpointId: daemon.deployment.manifest.defaultEndpointId,
3897
+ env: context.env,
3898
+ ...projectSpaceId ? { projectSpaceId } : {}
3899
+ }),
3900
+ sessionKey: command.sessionKey,
3901
+ text: command.text
3902
+ }).pipe(Effect.map(readPromptFinalText));
3903
+ }).pipe(Effect.catchCause((cause) => Effect.fail(Cause.squash(cause))))
4011
3904
  };
4012
3905
  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)));
3906
+ if (replayReceiveMessage) process.replayReceiveMessage = (payload, options) => Effect.suspend(() => daemon.running() ? Effect.void : startDeployment).pipe(Effect.flatMap(() => replayReceiveMessage((input) => daemon.handleDefault(input), payload, options)));
4019
3907
  return process;
4020
3908
  }
4021
3909
  function readPromptFinalText(result) {
@@ -4063,8 +3951,7 @@ function runRivusDaemonCli(options) {
4063
3951
  try: () => loadCliEnv(parsed.envFilePath, options.env),
4064
3952
  catch: (error) => error
4065
3953
  });
4066
- const configuredBootstrapSpecifier = parsed.bootstrap ?? env.RIVUS_BOOTSTRAP_MODULE?.trim();
4067
- const bootstrapSpecifier = configuredBootstrapSpecifier ? resolveRivusBuiltinSpecifier(configuredBootstrapSpecifier) : void 0;
3954
+ const bootstrapSpecifier = parsed.bootstrap ?? env.RIVUS_BOOTSTRAP_MODULE?.trim();
4068
3955
  if (!parsed.checkConfig && !bootstrapSpecifier) {
4069
3956
  options.stderr.write(formatRivusDaemonUsageError("Missing --bootstrap <module> or RIVUS_BOOTSTRAP_MODULE"));
4070
3957
  return 1;
@@ -4189,7 +4076,7 @@ function runRivusDaemonCli(options) {
4189
4076
  yield* daemon.start();
4190
4077
  options.stdout.write(RIVUS_DAEMON_STARTED_MESSAGE);
4191
4078
  return 0;
4192
- }).pipe(Effect.catchAll((error) => Effect.sync(() => {
4079
+ }).pipe(Effect.catch((error) => Effect.sync(() => {
4193
4080
  options.stderr.write(formatRivusDaemonLine(formatRivusDaemonError(error)));
4194
4081
  return 1;
4195
4082
  })));
@@ -4309,7 +4196,7 @@ function runModelCommand(options) {
4309
4196
  return Effect.tryPromise({
4310
4197
  try: () => client.execute(parsed),
4311
4198
  catch: (error) => error
4312
- }).pipe(Effect.tap((response) => Effect.sync(() => writeModelResponse(options.stdout, response))), Effect.map((response) => modelManagementExitCode(response)), Effect.catchAll((error) => Effect.sync(() => {
4199
+ }).pipe(Effect.tap((response) => Effect.sync(() => writeModelResponse(options.stdout, response))), Effect.map((response) => modelManagementExitCode(response)), Effect.catch((error) => Effect.sync(() => {
4313
4200
  writeModelResponse(options.stdout, modelTransportFailure(error));
4314
4201
  return 1;
4315
4202
  })));
@@ -4337,7 +4224,7 @@ function modelTransportFailure(error) {
4337
4224
  };
4338
4225
  }
4339
4226
  function runSetupCommand(options) {
4340
- return withOptionalDirectoryArgument(options, "setup", (argument) => resolveHomeDirectoryEffect(options, argument).pipe(Effect.flatMap((directory) => options.homeApi.setup(directory).pipe(Effect.tap(() => Effect.sync(() => options.stdout.write(renderRivusSetupSuccess(directory)))), Effect.as(0))), Effect.catchAll((error) => writeError(options, error))));
4227
+ return withOptionalDirectoryArgument(options, "setup", (argument) => resolveHomeDirectoryEffect(options, argument).pipe(Effect.flatMap((directory) => options.homeApi.setup(directory).pipe(Effect.tap(() => Effect.sync(() => options.stdout.write(renderRivusSetupSuccess(directory)))), Effect.as(0))), Effect.catch((error) => writeError(options, error))));
4341
4228
  }
4342
4229
  function runHomeDaemonCommand(options, command, daemonArgs) {
4343
4230
  if (hasRivusHomeCommandArguments(options.argv.slice(1))) return Effect.sync(() => {
@@ -4361,7 +4248,7 @@ function runHomeDaemonCommand(options, command, daemonArgs) {
4361
4248
  RIVUS_HOME: home.directory
4362
4249
  },
4363
4250
  pluginPackageManifestPath: options.pluginPackageManifestPath ?? gatewayPackageManifestPath
4364
- })), Effect.catchAll((error) => writeError(options, error)));
4251
+ })), Effect.catch((error) => writeError(options, error)));
4365
4252
  }
4366
4253
  function runInitCommand(options) {
4367
4254
  return withOptionalDirectoryArgument(options, "init", (argument) => {
@@ -4373,7 +4260,7 @@ function runInitCommand(options) {
4373
4260
  templateDirectory: gatewayTemplateDirectory
4374
4261
  }),
4375
4262
  catch: (error) => error
4376
- }).pipe(Effect.tap((result) => Effect.sync(() => options.stdout.write(renderRivusProjectInitializationSuccess(result.directory)))), Effect.as(0), Effect.catchAll((error) => writeError(options, error)));
4263
+ }).pipe(Effect.tap((result) => Effect.sync(() => options.stdout.write(renderRivusProjectInitializationSuccess(result.directory)))), Effect.as(0), Effect.catch((error) => writeError(options, error)));
4377
4264
  });
4378
4265
  }
4379
4266
  function withOptionalDirectoryArgument(options, command, run) {
@@ -4406,14 +4293,14 @@ function runDoctorCommand(options) {
4406
4293
  env: options.env,
4407
4294
  ...parsed.envFilePath ? { envFilePath: parsed.envFilePath } : {},
4408
4295
  nodeVersion: options.nodeVersion
4409
- })), Effect.map((report) => writeDoctorReport(options.stdout, report, "Home")), Effect.catchAll((error) => writeError(options, error)));
4296
+ })), Effect.map((report) => writeDoctorReport(options.stdout, report, "Home")), Effect.catch((error) => writeError(options, error)));
4410
4297
  const projectDirectory = parsed.directory;
4411
4298
  return diagnoseRivusProject({
4412
4299
  directory: resolve(options.cwd, projectDirectory),
4413
4300
  env: options.env,
4414
4301
  ...parsed.envFilePath ? { envFilePath: parsed.envFilePath } : {},
4415
4302
  nodeVersion: options.nodeVersion
4416
- }).pipe(Effect.map((report) => writeDoctorReport(options.stdout, report, "project")), Effect.catchAll((error) => writeError(options, error)));
4303
+ }).pipe(Effect.map((report) => writeDoctorReport(options.stdout, report, "project")), Effect.catch((error) => writeError(options, error)));
4417
4304
  }
4418
4305
  function resolveHomeDirectoryEffect(options, argument) {
4419
4306
  return Effect.try({
@@ -4461,4 +4348,5 @@ function toImportSpecifier(specifier) {
4461
4348
  return specifier;
4462
4349
  }
4463
4350
  //#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 };
4351
+ export { RIVUS_PLUGIN_API_VERSION as i, createRivusPluginCatalog as n, resolveRivusAgentDefinition as r, runRivusNodeEntrypoint as t };
4352
+