@rivus/gateway 0.16.6 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -21
- package/README.md +25 -0
- package/dist/bootstrap/herdr-feishu.d.ts +37 -0
- package/dist/bootstrap/herdr-feishu.js +856 -0
- package/dist/bootstrap/pi-feishu.d.ts +281 -16
- package/dist/bootstrap/pi-feishu.js +17314 -344
- package/dist/chunks/background-session-authority.js +2 -38
- package/dist/chunks/rivus-daemon-cli.d.ts +1115 -0
- package/dist/chunks/rivus-node-entrypoint.js +700 -819
- package/dist/chunks/{node-rivus-deployment-manifest.js → runtime-cache.js} +1116 -1475
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +1 -0
- package/dist/index.d.ts +65 -3
- package/dist/index.js +3 -1215
- package/dist/mcp.d.ts +7 -63
- package/dist/mcp.js +3 -250
- package/package.json +21 -13
- package/templates/a-share-briefing-analysis.mjs +3 -1
- package/templates/a-share-briefing-renderer.mjs +15 -5
- package/templates/a-share-index-evidence.mjs +9 -3
- package/templates/a-share-market-briefing.mjs +3 -1
- package/templates/a-share-overseas-evidence.mjs +12 -4
- package/templates/a-share-policy-evidence.mjs +30 -10
- package/templates/a-share-sector-evidence.mjs +3 -1
- package/templates/acp-stdio-proxy.mjs +10 -4
- package/templates/current-weather.mjs +36 -12
- package/templates/herdr-feishu.mjs +30 -0
- package/templates/html-drive-tools.mjs +36 -12
- package/templates/pi-feishu-deployment.bootstrap.ts +1 -3
- package/templates/pi-feishu.bootstrap.ts +1 -242
- package/templates/rivus-agents.plugin.mjs +3 -1
- package/dist/chunks/background-session-control-input.js +0 -45
- package/dist/chunks/background-session-service.d.ts +0 -390
- package/dist/chunks/index.d.ts +0 -4703
- package/dist/chunks/service.js +0 -12112
- package/templates/langfuse-drive-e2e.mjs +0 -175
|
@@ -1,217 +1,18 @@
|
|
|
1
|
-
import { l as
|
|
2
|
-
import {
|
|
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 {
|
|
8
|
-
import { lstat, mkdir, open, readFile, readdir, realpath, rmdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
9
|
-
import { createConnection } from "node:net";
|
|
10
|
-
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
|
+
import { RIVUS_MEMORY_TOOL_PLUGIN_ID, RIVUS_RUNTIME_TOOL_IDS, createRivusMemoryToolContract, isRivusRuntimeToolId } from "@rivus/runtime";
|
|
11
6
|
import { homedir } from "node:os";
|
|
7
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
12
8
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
9
|
+
import { Cause, Effect, Either, Exit } from "effect";
|
|
10
|
+
import { lstat, mkdir, open, readFile, readdir, realpath, rmdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
11
|
+
import { randomUUID } from "node:crypto";
|
|
13
12
|
import { assertPathWithin, isPathWithin } from "@rivus/platform/filesystem";
|
|
13
|
+
import { createConnection } from "node:net";
|
|
14
14
|
import { constants as constants$1 } from "node:fs";
|
|
15
|
-
|
|
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/
|
|
636
|
-
const
|
|
637
|
-
|
|
638
|
-
|
|
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
|
-
|
|
643
|
-
|
|
644
|
-
const descriptor = options.releaseDescriptor ?? RIVUS_RELEASE_DESCRIPTOR;
|
|
645
|
-
const files = /* @__PURE__ */ new Map([
|
|
646
|
-
[".env.example", environmentTemplate$1()],
|
|
647
|
-
[".gitignore", ".env.local\n.rivus/\nnode_modules/\n"],
|
|
648
|
-
["deploy/launchd/com.rivus.agent.plist", launchdService(directory, options.nodeExecutable)],
|
|
649
|
-
["deploy/systemd/rivus.service", systemdService(directory, options.nodeExecutable)],
|
|
650
|
-
["package.json", projectPackageJson(directory, descriptor)],
|
|
651
|
-
["rivus.config.json", deploymentManifest$1()]
|
|
652
|
-
]);
|
|
653
|
-
for (const [target, source] of Object.entries(TEMPLATE_FILES)) files.set(target, await readFile(join(options.templateDirectory, source), "utf8"));
|
|
654
|
-
const paths = [...files.keys()].sort();
|
|
655
|
-
await assertSafeProjectAncestors(directory, paths);
|
|
656
|
-
const conflicts = await findConflicts(directory, paths);
|
|
657
|
-
if (conflicts.length > 0) throw new Error(`Rivus project initialization refused; refusing to overwrite: ${conflicts.join(", ")}`);
|
|
658
|
-
const createdDirectories = [];
|
|
659
|
-
const createdFiles = [];
|
|
660
|
-
const writeProjectFile = options.writeProjectFile ?? writeExclusiveProjectFile;
|
|
661
|
-
try {
|
|
662
|
-
for (const path of paths) {
|
|
663
|
-
const destination = join(directory, path);
|
|
664
|
-
await ensureDirectory(dirname(destination), directory, createdDirectories);
|
|
665
|
-
await assertSafeProjectAncestors(directory, [path]);
|
|
666
|
-
await writeProjectFile(destination, files.get(path));
|
|
667
|
-
createdFiles.push(destination);
|
|
668
|
-
}
|
|
669
|
-
} catch (error) {
|
|
670
|
-
const rollbackErrors = await rollbackCreatedPaths(createdFiles, createdDirectories);
|
|
671
|
-
if (rollbackErrors.length > 0) throw new AggregateError([error, ...rollbackErrors], "Rivus project initialization failed and rollback was incomplete");
|
|
672
|
-
throw error;
|
|
673
|
-
}
|
|
674
|
-
return {
|
|
675
|
-
directory,
|
|
676
|
-
files: Object.freeze(paths)
|
|
677
|
-
};
|
|
678
|
-
}
|
|
679
|
-
async function writeExclusiveProjectFile(path, contents) {
|
|
680
|
-
await writeFile(path, contents, {
|
|
681
|
-
encoding: "utf8",
|
|
682
|
-
flag: "wx"
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
async function assertSafeProjectAncestors(directory, paths) {
|
|
686
|
-
const rootState = await lstatOrUndefined(directory);
|
|
687
|
-
if (rootState?.isSymbolicLink()) throw new Error("Rivus project initialization refused; symbolic link ancestor: .");
|
|
688
|
-
if (rootState && !rootState.isDirectory()) throw new Error("Rivus project initialization refused; project path is not a directory");
|
|
689
|
-
if (!rootState) return;
|
|
690
|
-
for (const path of paths) {
|
|
691
|
-
let current = directory;
|
|
692
|
-
for (const segment of path.split("/").slice(0, -1)) {
|
|
693
|
-
current = join(current, segment);
|
|
694
|
-
const state = await lstatOrUndefined(current);
|
|
695
|
-
if (!state) break;
|
|
696
|
-
if (state.isSymbolicLink()) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(directory, current)}`);
|
|
697
|
-
if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${relative(directory, current)}`);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
async function ensureDirectory(path, projectRoot, createdDirectories) {
|
|
702
|
-
try {
|
|
703
|
-
await mkdir(path);
|
|
704
|
-
createdDirectories.push(path);
|
|
705
|
-
} catch (error) {
|
|
706
|
-
if (isMissingPath$1(error)) {
|
|
707
|
-
const parent = dirname(path);
|
|
708
|
-
if (parent === path) throw error;
|
|
709
|
-
await ensureDirectory(parent, projectRoot, createdDirectories);
|
|
710
|
-
await ensureDirectory(path, projectRoot, createdDirectories);
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
|
-
if (!isAlreadyExists(error)) throw error;
|
|
714
|
-
const state = await lstat(path);
|
|
715
|
-
if (state.isSymbolicLink()) {
|
|
716
|
-
if (isPathWithin(projectRoot, path)) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(projectRoot, path) || "."}`);
|
|
717
|
-
if ((await stat(path)).isDirectory()) return;
|
|
718
|
-
}
|
|
719
|
-
if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${path}`);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
async function rollbackCreatedPaths(files, directories) {
|
|
723
|
-
const errors = [];
|
|
724
|
-
for (const path of files.reverse()) try {
|
|
725
|
-
await unlink(path);
|
|
726
|
-
} catch (error) {
|
|
727
|
-
if (!isMissingPath$1(error)) errors.push(asError$1(error));
|
|
728
|
-
}
|
|
729
|
-
for (const path of directories.reverse()) try {
|
|
730
|
-
await rmdir(path);
|
|
731
|
-
} catch (error) {
|
|
732
|
-
if (!isMissingPath$1(error) && !isDirectoryNotEmpty(error)) errors.push(asError$1(error));
|
|
733
|
-
}
|
|
734
|
-
return errors;
|
|
735
|
-
}
|
|
736
|
-
async function lstatOrUndefined(path) {
|
|
737
|
-
try {
|
|
738
|
-
return await lstat(path);
|
|
739
|
-
} catch (error) {
|
|
740
|
-
if (isMissingPath$1(error)) return void 0;
|
|
741
|
-
throw error;
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
function isAlreadyExists(error) {
|
|
745
|
-
return error instanceof Error && "code" in error && error.code === "EEXIST";
|
|
746
|
-
}
|
|
747
|
-
function isDirectoryNotEmpty(error) {
|
|
748
|
-
return error instanceof Error && "code" in error && error.code === "ENOTEMPTY";
|
|
749
|
-
}
|
|
750
|
-
function asError$1(error) {
|
|
751
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
752
|
-
}
|
|
753
|
-
async function findConflicts(directory, paths) {
|
|
754
|
-
const conflicts = [];
|
|
755
|
-
for (const path of paths) try {
|
|
756
|
-
await lstat(join(directory, path));
|
|
757
|
-
conflicts.push(path);
|
|
758
|
-
} catch (error) {
|
|
759
|
-
if (!isMissingPath$1(error)) throw error;
|
|
760
|
-
}
|
|
761
|
-
return conflicts;
|
|
762
|
-
}
|
|
763
|
-
function isMissingPath$1(error) {
|
|
764
|
-
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
765
|
-
}
|
|
766
|
-
function projectPackageJson(directory, descriptor) {
|
|
767
|
-
const { dependencies, version } = descriptor;
|
|
768
|
-
const projectName = sanitizePackageName(basename(directory));
|
|
769
|
-
return `${JSON.stringify({
|
|
770
|
-
name: projectName,
|
|
771
|
-
private: true,
|
|
772
|
-
type: "module",
|
|
773
|
-
scripts: {
|
|
774
|
-
"check-config": "rivus --manifest ./rivus.config.json --check-config",
|
|
775
|
-
doctor: "rivus doctor .",
|
|
776
|
-
start: "rivus --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json"
|
|
777
|
-
},
|
|
778
|
-
dependencies: {
|
|
779
|
-
"@earendil-works/pi-coding-agent": dependencies["@earendil-works/pi-coding-agent"],
|
|
780
|
-
"@larksuiteoapi/node-sdk": dependencies["@larksuiteoapi/node-sdk"],
|
|
781
|
-
"@rivus/agent": `^${version}`,
|
|
782
|
-
effect: dependencies.effect
|
|
783
|
-
}
|
|
784
|
-
}, null, 2)}\n`;
|
|
785
|
-
}
|
|
786
|
-
function sanitizePackageName(value) {
|
|
787
|
-
return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "") || "rivus-app";
|
|
788
|
-
}
|
|
789
|
-
function deploymentManifest$1() {
|
|
790
|
-
return `${JSON.stringify({
|
|
791
|
-
plugins: [{
|
|
792
|
-
id: "rivus-starter",
|
|
793
|
-
module: "./rivus-agents.plugin.mjs",
|
|
794
|
-
required: true
|
|
795
|
-
}],
|
|
796
|
-
agents: [{
|
|
797
|
-
agentId: "agent-a",
|
|
798
|
-
endpointIds: ["feishu-agent-a"],
|
|
799
|
-
pluginId: "rivus-starter",
|
|
800
|
-
profileId: "agent-a",
|
|
801
|
-
skills: { allow: [] },
|
|
802
|
-
tools: { allow: ["rivus-starter/current-weather"] }
|
|
803
|
-
}],
|
|
804
|
-
defaultAgentId: "agent-a",
|
|
805
|
-
defaultEndpointId: "feishu-agent-a",
|
|
806
|
-
endpoints: [{
|
|
807
|
-
agentId: "agent-a",
|
|
808
|
-
baseUrl: "https://open.feishu.cn",
|
|
809
|
-
cardStreamLeaseMs: 51e4,
|
|
810
|
-
credentialRef: "env:RIVUS_FEISHU",
|
|
811
|
-
enabled: true,
|
|
812
|
-
experimental: { cotMessages: false },
|
|
813
|
-
groupPolicy: "mention-only",
|
|
814
|
-
id: "feishu-agent-a",
|
|
815
|
-
progressDisplay: "collapsed",
|
|
816
|
-
required: true,
|
|
817
|
-
sessionNamespace: "rivus-starter",
|
|
818
|
-
streamMinIntervalMs: 200
|
|
819
|
-
}]
|
|
820
|
-
}, null, 2)}\n`;
|
|
821
|
-
}
|
|
822
|
-
function environmentTemplate$1() {
|
|
823
|
-
return [
|
|
824
|
-
"# Copy this file to .env.local and keep the real values untracked.",
|
|
825
|
-
"RIVUS_FEISHU_APP_ID=",
|
|
826
|
-
"RIVUS_FEISHU_APP_SECRET=",
|
|
827
|
-
"PI_MODEL=",
|
|
828
|
-
"PI_API_KEY=",
|
|
829
|
-
"# PI_BASE_URL=",
|
|
830
|
-
"RIVUS_WEATHER_DEFAULT_LOCATION=上海",
|
|
831
|
-
"# LANGFUSE_BASE_URL=https://jp.cloud.langfuse.com",
|
|
832
|
-
"# LANGFUSE_PUBLIC_KEY=",
|
|
833
|
-
"# LANGFUSE_SECRET_KEY=",
|
|
834
|
-
"# RIVUS_TELEMETRY_CONTENT=redacted",
|
|
835
|
-
""
|
|
836
|
-
].join("\n");
|
|
837
|
-
}
|
|
838
|
-
function systemdService(directory, nodeExecutable) {
|
|
839
|
-
const cli = join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js");
|
|
840
|
-
return `[Unit]\nDescription=Rivus Agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nWorkingDirectory=${systemdPath(directory)}\nExecStart=${systemdQuote(nodeExecutable)} ${systemdQuote(cli)} --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json\nRestart=on-failure\nRestartSec=5\nEnvironment=NODE_ENV=production\n\n[Install]\nWantedBy=default.target\n`;
|
|
841
|
-
}
|
|
842
|
-
function systemdPath(value) {
|
|
843
|
-
return value.replaceAll("%", "%%");
|
|
844
|
-
}
|
|
845
|
-
function systemdQuote(value) {
|
|
846
|
-
return `"${value.replace(/%/g, "%%").replace(/\$/g, () => "$$").replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
847
|
-
}
|
|
848
|
-
function launchdService(directory, nodeExecutable) {
|
|
849
|
-
return `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n <key>Label</key>\n <string>com.rivus.agent</string>\n <key>ProgramArguments</key>\n <array>\n${[
|
|
850
|
-
nodeExecutable,
|
|
851
|
-
join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js"),
|
|
852
|
-
"--env-file",
|
|
853
|
-
".env.local",
|
|
854
|
-
"--bootstrap",
|
|
855
|
-
"./rivus.bootstrap.ts",
|
|
856
|
-
"--manifest",
|
|
857
|
-
"./rivus.config.json"
|
|
858
|
-
].map((value) => ` <string>${xmlEscape(value)}</string>`).join("\n")}\n </array>\n <key>WorkingDirectory</key>\n <string>${xmlEscape(directory)}</string>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <dict>\n <key>SuccessfulExit</key>\n <false/>\n </dict>\n <key>ThrottleInterval</key>\n <integer>5</integer>\n</dict>\n</plist>\n`;
|
|
428
|
+
function createRivusPluginCatalog() {
|
|
429
|
+
return createRivusPluginCatalog$1(runtime);
|
|
859
430
|
}
|
|
860
|
-
function
|
|
861
|
-
return
|
|
431
|
+
function createBootstrapAgentCatalog(backgroundSessions = false) {
|
|
432
|
+
return createRivusAgentCatalog([createRivusHostToolDescriptorProvider({ backgroundSessions })], runtime);
|
|
862
433
|
}
|
|
863
|
-
|
|
864
|
-
|
|
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$
|
|
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$
|
|
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
|
|
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$
|
|
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$
|
|
496
|
+
catch: toError$3
|
|
928
497
|
});
|
|
929
|
-
const moduleSpecifier =
|
|
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$
|
|
503
|
+
catch: toError$3
|
|
935
504
|
});
|
|
936
505
|
const resolvedRealpath = yield* Effect.tryPromise({
|
|
937
506
|
try: () => realpath(resolved),
|
|
938
|
-
catch: toError$
|
|
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$
|
|
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-
|
|
948
|
-
const
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
const
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
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
|
-
|
|
999
|
-
const missing = await missingRegularFiles(directory, REQUIRED_FILES);
|
|
1000
|
-
return missing.length === 0 ? {
|
|
1001
|
-
message: "required project files are present",
|
|
1002
|
-
name: "files",
|
|
1003
|
-
status: "pass"
|
|
1004
|
-
} : {
|
|
1005
|
-
message: `required project files are missing: ${missing.join(", ")}`,
|
|
1006
|
-
name: "files",
|
|
1007
|
-
status: "fail"
|
|
1008
|
-
};
|
|
1009
|
-
}
|
|
1010
|
-
async function checkDependencies(directory) {
|
|
1011
|
-
const packageFiles = REQUIRED_DEPENDENCIES.map((name) => join("node_modules", ...name.split("/"), "package.json"));
|
|
1012
|
-
const missingIndexes = new Set((await missingRegularFiles(directory, packageFiles)).map((path) => packageFiles.indexOf(path)));
|
|
1013
|
-
const missing = REQUIRED_DEPENDENCIES.filter((_, index) => missingIndexes.has(index));
|
|
1014
|
-
return missing.length === 0 ? {
|
|
1015
|
-
message: "Rivus, Pi, Feishu, and Effect dependencies are installed",
|
|
1016
|
-
name: "dependencies",
|
|
1017
|
-
status: "pass"
|
|
1018
|
-
} : {
|
|
1019
|
-
message: `run npm install; missing local dependencies: ${missing.join(", ")}`,
|
|
1020
|
-
name: "dependencies",
|
|
1021
|
-
status: "fail"
|
|
1022
|
-
};
|
|
1023
|
-
}
|
|
1024
|
-
function checkManifest$1(directory) {
|
|
1025
|
-
return loadRivusDeploymentManifest(join(directory, "rivus.config.json")).pipe(Effect.flatMap((manifest) => Effect.gen(function* () {
|
|
1026
|
-
validateRivusDeploymentManifest(manifest);
|
|
1027
|
-
const missingModules = [];
|
|
1028
|
-
for (const plugin of manifest.plugins) {
|
|
1029
|
-
const result = yield* resolveNodeRivusPluginModulePath({
|
|
1030
|
-
deploymentRoot: directory,
|
|
1031
|
-
module: plugin.module,
|
|
1032
|
-
pluginId: plugin.id
|
|
1033
|
-
}).pipe(Effect.either);
|
|
1034
|
-
if (Either.isLeft(result)) missingModules.push(plugin.module);
|
|
1035
|
-
}
|
|
1036
|
-
if (missingModules.length > 0) return { check: {
|
|
1037
|
-
message: `manifest Plugin modules are missing: ${missingModules.join(", ")}`,
|
|
1038
|
-
name: "manifest",
|
|
1039
|
-
status: "fail"
|
|
1040
|
-
} };
|
|
1041
|
-
return {
|
|
1042
|
-
check: {
|
|
1043
|
-
message: "deployment manifest is valid",
|
|
1044
|
-
name: "manifest",
|
|
1045
|
-
status: "pass"
|
|
1046
|
-
},
|
|
1047
|
-
manifest
|
|
1048
|
-
};
|
|
1049
|
-
})), Effect.catchAll((error) => Effect.succeed({ check: {
|
|
1050
|
-
message: `deployment manifest is invalid: ${error.message}`,
|
|
1051
|
-
name: "manifest",
|
|
1052
|
-
status: "fail"
|
|
1053
|
-
} })));
|
|
1054
|
-
}
|
|
1055
|
-
async function checkCredentials$1(manifest, envFilePath, env) {
|
|
1056
|
-
let mergedEnv;
|
|
1057
|
-
try {
|
|
1058
|
-
mergedEnv = await loadMergedLocalEnvFile(envFilePath, env);
|
|
1059
|
-
} catch (error) {
|
|
1060
|
-
return {
|
|
1061
|
-
message: `required env file is unavailable at ${envFilePath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1062
|
-
name: "credentials",
|
|
1063
|
-
status: "fail"
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
if (!manifest) return {
|
|
1067
|
-
message: "enabled Endpoint credentials cannot be checked until the deployment manifest is valid",
|
|
1068
|
-
name: "credentials",
|
|
1069
|
-
status: "fail"
|
|
1070
|
-
};
|
|
1071
|
-
try {
|
|
1072
|
-
for (const endpoint of manifest.endpoints.filter(({ enabled }) => enabled)) resolveFeishuEndpointCredentials(endpoint.credentialRef, mergedEnv);
|
|
1073
|
-
return {
|
|
1074
|
-
message: "enabled Endpoint credential references resolve",
|
|
1075
|
-
name: "credentials",
|
|
1076
|
-
status: "pass"
|
|
1077
|
-
};
|
|
1078
|
-
} catch (error) {
|
|
1079
|
-
return {
|
|
1080
|
-
message: `enabled Endpoint credentials are incomplete: ${error instanceof Error ? error.message : String(error)}`,
|
|
1081
|
-
name: "credentials",
|
|
1082
|
-
status: "fail"
|
|
1083
|
-
};
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
async function missingRegularFiles(directory, paths) {
|
|
1087
|
-
const missing = [];
|
|
1088
|
-
for (const path of paths) try {
|
|
1089
|
-
if (!(await stat(resolve(directory, path))).isFile()) missing.push(path);
|
|
1090
|
-
} catch (error) {
|
|
1091
|
-
if (!isMissingPath(error)) throw error;
|
|
1092
|
-
missing.push(path);
|
|
1093
|
-
}
|
|
1094
|
-
return missing;
|
|
1095
|
-
}
|
|
1096
|
-
function isMissingPath(error) {
|
|
1097
|
-
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
1098
|
-
}
|
|
1099
|
-
function toError$3(error) {
|
|
1100
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
1101
|
-
}
|
|
1102
|
-
//#endregion
|
|
1103
|
-
//#region src/adapters/deployment/inspection/rivus-home-deployment-inspector.ts
|
|
1104
|
-
const DEFAULT_BOOTSTRAP_PEERS = Object.freeze(["@earendil-works/pi-coding-agent", "@larksuiteoapi/node-sdk"]);
|
|
1105
|
-
function createRivusHomeDeploymentInspector(options = {}) {
|
|
1106
|
-
const resolveModule = options.resolveModule ?? ((specifier) => defaultResolveModule(specifier, options.packageManifestPath));
|
|
1107
|
-
const resolvePluginModule = options.resolvePluginModule ?? ((request) => resolveNodeRivusPluginModulePath(request, options.packageManifestPath ? { packageManifestPath: options.packageManifestPath } : {}));
|
|
1108
|
-
return { inspect: (input) => Effect.gen(function* () {
|
|
1109
|
-
const manifestResult = yield* checkManifest(input.home);
|
|
1110
|
-
const credentials = yield* checkCredentials(input.home, manifestResult.manifest, input.env, input.envFilePath);
|
|
1111
|
-
const modules = yield* checkModules(input.home, manifestResult.manifest, resolveModule, resolvePluginModule);
|
|
1112
|
-
return {
|
|
1113
|
-
credentials,
|
|
1114
|
-
manifest: manifestResult.check,
|
|
1115
|
-
modules
|
|
1116
|
-
};
|
|
1117
|
-
}) };
|
|
1118
|
-
}
|
|
1119
|
-
function checkManifest(home) {
|
|
532
|
+
function checkManifest$1(home) {
|
|
1120
533
|
return loadRivusDeploymentManifest(home.manifestPath).pipe(Effect.map((manifest) => {
|
|
1121
534
|
validateRivusDeploymentManifest(manifest);
|
|
1122
535
|
return {
|
|
@@ -1139,7 +552,7 @@ function checkModules(home, manifest, resolveModule, resolvePluginModule) {
|
|
|
1139
552
|
name: "modules",
|
|
1140
553
|
status: "fail"
|
|
1141
554
|
});
|
|
1142
|
-
const specifiers = [
|
|
555
|
+
const specifiers = [home.bootstrap, ...home.bootstrap === "@rivus/gateway/bootstrap/pi-feishu" ? DEFAULT_BOOTSTRAP_PEERS : []];
|
|
1143
556
|
return Effect.gen(function* () {
|
|
1144
557
|
const missing = [];
|
|
1145
558
|
for (const specifier of specifiers) {
|
|
@@ -1149,7 +562,7 @@ function checkModules(home, manifest, resolveModule, resolvePluginModule) {
|
|
|
1149
562
|
for (const plugin of manifest.plugins) {
|
|
1150
563
|
const result = yield* toEffect(() => resolvePluginModule({
|
|
1151
564
|
deploymentRoot: home.directory,
|
|
1152
|
-
module:
|
|
565
|
+
module: plugin.module,
|
|
1153
566
|
pluginId: plugin.id
|
|
1154
567
|
})).pipe(Effect.either);
|
|
1155
568
|
if (result._tag === "Left") missing.push(`${plugin.module} (${formatError(result.left)})`);
|
|
@@ -1179,7 +592,7 @@ function toEffect(read) {
|
|
|
1179
592
|
}
|
|
1180
593
|
});
|
|
1181
594
|
}
|
|
1182
|
-
function checkCredentials(home, manifest, env, envFilePath) {
|
|
595
|
+
function checkCredentials$1(home, manifest, env, envFilePath) {
|
|
1183
596
|
if (!manifest) return Effect.succeed({
|
|
1184
597
|
message: "credentials cannot be checked until manifest is valid",
|
|
1185
598
|
name: "credentials",
|
|
@@ -1239,7 +652,7 @@ function loadRivusHome(directoryPath) {
|
|
|
1239
652
|
workspaceDirectory: resolveHomePath(directory, config.workspace, "workspace")
|
|
1240
653
|
};
|
|
1241
654
|
},
|
|
1242
|
-
catch: asError
|
|
655
|
+
catch: asError$1
|
|
1243
656
|
});
|
|
1244
657
|
}
|
|
1245
658
|
function parseRivusHomeConfig(value) {
|
|
@@ -1279,14 +692,14 @@ function record(value, owner) {
|
|
|
1279
692
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${owner} must be an object`);
|
|
1280
693
|
return value;
|
|
1281
694
|
}
|
|
1282
|
-
function asError(error) {
|
|
695
|
+
function asError$1(error) {
|
|
1283
696
|
return error instanceof Error ? error : new Error(String(error));
|
|
1284
697
|
}
|
|
1285
698
|
//#endregion
|
|
1286
699
|
//#region src/platform/home/doctor/rivus-home-doctor.ts
|
|
1287
700
|
function diagnoseRivusHome(input, options) {
|
|
1288
701
|
return Effect.gen(function* () {
|
|
1289
|
-
const checks = [checkNode(input.nodeVersion)];
|
|
702
|
+
const checks = [checkNode$1(input.nodeVersion)];
|
|
1290
703
|
const loaded = yield* options.load(input.directory).pipe(Effect.either);
|
|
1291
704
|
if (Either.isLeft(loaded)) {
|
|
1292
705
|
checks.push({
|
|
@@ -1312,7 +725,7 @@ function diagnoseRivusHome(input, options) {
|
|
|
1312
725
|
return report(input.directory, checks);
|
|
1313
726
|
});
|
|
1314
727
|
}
|
|
1315
|
-
function checkNode(version) {
|
|
728
|
+
function checkNode$1(version) {
|
|
1316
729
|
const [major, minor] = version.split(".").map(Number);
|
|
1317
730
|
return major === 24 && Number.isInteger(minor) && minor >= 11 ? {
|
|
1318
731
|
message: `Node.js ${version} satisfies the supported ^24.11 runtime`,
|
|
@@ -1366,10 +779,10 @@ function createRivusHomeLayout() {
|
|
|
1366
779
|
return {
|
|
1367
780
|
directories: HOME_DIRECTORIES,
|
|
1368
781
|
files: /* @__PURE__ */ new Map([
|
|
1369
|
-
[".env.example", environmentTemplate()],
|
|
782
|
+
[".env.example", environmentTemplate$1()],
|
|
1370
783
|
[".gitignore", ".DS_Store\n.env\nlogs/\nstate/\nworkspace/work/tmp/\n"],
|
|
1371
784
|
["config.json", homeConfig()],
|
|
1372
|
-
["rivus.config.json", deploymentManifest()],
|
|
785
|
+
["rivus.config.json", deploymentManifest$1()],
|
|
1373
786
|
["workspace/AGENTS.md", agentsTemplate()],
|
|
1374
787
|
["workspace/IDENTITY.md", "# Identity\n\nName: Rivus\n\nRole: Personal agent\n"],
|
|
1375
788
|
["workspace/MEMORY.md", "# Curated Memory\n\nStore confirmed, durable facts and decisions here.\n"],
|
|
@@ -1395,7 +808,7 @@ function homeConfig() {
|
|
|
1395
808
|
workspace: "workspace"
|
|
1396
809
|
}, null, 2)}\n`;
|
|
1397
810
|
}
|
|
1398
|
-
function deploymentManifest() {
|
|
811
|
+
function deploymentManifest$1() {
|
|
1399
812
|
return `${JSON.stringify({
|
|
1400
813
|
agents: [{
|
|
1401
814
|
agentId: "personal",
|
|
@@ -1448,7 +861,7 @@ function deploymentManifest() {
|
|
|
1448
861
|
}]
|
|
1449
862
|
}, null, 2)}\n`;
|
|
1450
863
|
}
|
|
1451
|
-
function environmentTemplate() {
|
|
864
|
+
function environmentTemplate$1() {
|
|
1452
865
|
return [
|
|
1453
866
|
"# Copy this file to .env and keep the real values untracked.",
|
|
1454
867
|
"RIVUS_FEISHU_APP_ID=",
|
|
@@ -1632,7 +1045,7 @@ function shellQuote(value) {
|
|
|
1632
1045
|
}
|
|
1633
1046
|
//#endregion
|
|
1634
1047
|
//#region src/adapters/cli/model/rivus-model-management-socket-client.ts
|
|
1635
|
-
const MAX_FRAME_BYTES =
|
|
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
|
-
|
|
1121
|
+
const home = configuredHome ? resolveAbsoluteHome(configuredHome) : resolve(options.homeDirectory, ".rivus-agent");
|
|
1122
|
+
return join(home, RIVUS_MODEL_SOCKET_RELATIVE_PATH);
|
|
1709
1123
|
}
|
|
1710
1124
|
function isRivusModelManagementEnabled(env) {
|
|
1711
1125
|
const value = optional(env[RIVUS_MODEL_MANAGEMENT_ENABLED_ENV]);
|
|
@@ -1715,8 +1129,393 @@ function resolveAbsoluteHome(value) {
|
|
|
1715
1129
|
if (!isAbsolute(value)) throw new Error("RIVUS_HOME must be an absolute path");
|
|
1716
1130
|
return resolve(value);
|
|
1717
1131
|
}
|
|
1718
|
-
function optional(value) {
|
|
1719
|
-
return value?.trim() || void 0;
|
|
1132
|
+
function optional(value) {
|
|
1133
|
+
return value?.trim() || void 0;
|
|
1134
|
+
}
|
|
1135
|
+
//#endregion
|
|
1136
|
+
//#region src/adapters/deployment/inspection/rivus-project-doctor.ts
|
|
1137
|
+
const REQUIRED_FILES = Object.freeze([
|
|
1138
|
+
"package.json",
|
|
1139
|
+
"rivus.bootstrap.ts",
|
|
1140
|
+
"rivus.config.json"
|
|
1141
|
+
]);
|
|
1142
|
+
const REQUIRED_DEPENDENCIES = Object.freeze([
|
|
1143
|
+
"@rivus/agent",
|
|
1144
|
+
"@earendil-works/pi-coding-agent",
|
|
1145
|
+
"@larksuiteoapi/node-sdk",
|
|
1146
|
+
"effect"
|
|
1147
|
+
]);
|
|
1148
|
+
function diagnoseRivusProject(options) {
|
|
1149
|
+
return Effect.gen(function* () {
|
|
1150
|
+
const directory = resolve(options.directory);
|
|
1151
|
+
const checks = [checkNode(options.nodeVersion)];
|
|
1152
|
+
checks.push(yield* Effect.tryPromise({
|
|
1153
|
+
try: () => checkFiles(directory),
|
|
1154
|
+
catch: toError$1
|
|
1155
|
+
}));
|
|
1156
|
+
checks.push(yield* Effect.tryPromise({
|
|
1157
|
+
try: () => checkDependencies(directory),
|
|
1158
|
+
catch: toError$1
|
|
1159
|
+
}));
|
|
1160
|
+
const manifestResult = yield* checkManifest(directory);
|
|
1161
|
+
checks.push(manifestResult.check);
|
|
1162
|
+
const envFilePath = resolve(directory, options.envFilePath ?? ".env.local");
|
|
1163
|
+
checks.push(yield* Effect.tryPromise({
|
|
1164
|
+
try: () => checkCredentials(manifestResult.manifest, envFilePath, options.env),
|
|
1165
|
+
catch: toError$1
|
|
1166
|
+
}));
|
|
1167
|
+
return Object.freeze({
|
|
1168
|
+
checks: Object.freeze(checks),
|
|
1169
|
+
directory,
|
|
1170
|
+
ready: checks.every(({ status }) => status === "pass")
|
|
1171
|
+
});
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
function checkNode(version) {
|
|
1175
|
+
const [major, minor] = version.split(".").map(Number);
|
|
1176
|
+
if (major === 24 && Number.isInteger(minor) && minor >= 11) return {
|
|
1177
|
+
message: `Node.js ${version} satisfies the supported ^24.11 runtime`,
|
|
1178
|
+
name: "node",
|
|
1179
|
+
status: "pass"
|
|
1180
|
+
};
|
|
1181
|
+
return {
|
|
1182
|
+
message: `Node.js 24.11 or newer on major 24 is required; current version is ${version}`,
|
|
1183
|
+
name: "node",
|
|
1184
|
+
status: "fail"
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
async function checkFiles(directory) {
|
|
1188
|
+
const missing = await missingRegularFiles(directory, REQUIRED_FILES);
|
|
1189
|
+
return missing.length === 0 ? {
|
|
1190
|
+
message: "required project files are present",
|
|
1191
|
+
name: "files",
|
|
1192
|
+
status: "pass"
|
|
1193
|
+
} : {
|
|
1194
|
+
message: `required project files are missing: ${missing.join(", ")}`,
|
|
1195
|
+
name: "files",
|
|
1196
|
+
status: "fail"
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
async function checkDependencies(directory) {
|
|
1200
|
+
const packageFiles = REQUIRED_DEPENDENCIES.map((name) => join("node_modules", ...name.split("/"), "package.json"));
|
|
1201
|
+
const missingIndexes = new Set((await missingRegularFiles(directory, packageFiles)).map((path) => packageFiles.indexOf(path)));
|
|
1202
|
+
const missing = REQUIRED_DEPENDENCIES.filter((_, index) => missingIndexes.has(index));
|
|
1203
|
+
return missing.length === 0 ? {
|
|
1204
|
+
message: "Rivus, Pi, Feishu, and Effect dependencies are installed",
|
|
1205
|
+
name: "dependencies",
|
|
1206
|
+
status: "pass"
|
|
1207
|
+
} : {
|
|
1208
|
+
message: `run npm install; missing local dependencies: ${missing.join(", ")}`,
|
|
1209
|
+
name: "dependencies",
|
|
1210
|
+
status: "fail"
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
function checkManifest(directory) {
|
|
1214
|
+
return loadRivusDeploymentManifest(join(directory, "rivus.config.json")).pipe(Effect.flatMap((manifest) => Effect.gen(function* () {
|
|
1215
|
+
validateRivusDeploymentManifest(manifest);
|
|
1216
|
+
const missingModules = [];
|
|
1217
|
+
for (const plugin of manifest.plugins) {
|
|
1218
|
+
const result = yield* resolveNodeRivusPluginModulePath({
|
|
1219
|
+
deploymentRoot: directory,
|
|
1220
|
+
module: plugin.module,
|
|
1221
|
+
pluginId: plugin.id
|
|
1222
|
+
}).pipe(Effect.either);
|
|
1223
|
+
if (Either.isLeft(result)) missingModules.push(plugin.module);
|
|
1224
|
+
}
|
|
1225
|
+
if (missingModules.length > 0) return { check: {
|
|
1226
|
+
message: `manifest Plugin modules are missing: ${missingModules.join(", ")}`,
|
|
1227
|
+
name: "manifest",
|
|
1228
|
+
status: "fail"
|
|
1229
|
+
} };
|
|
1230
|
+
return {
|
|
1231
|
+
check: {
|
|
1232
|
+
message: "deployment manifest is valid",
|
|
1233
|
+
name: "manifest",
|
|
1234
|
+
status: "pass"
|
|
1235
|
+
},
|
|
1236
|
+
manifest
|
|
1237
|
+
};
|
|
1238
|
+
})), Effect.catchAll((error) => Effect.succeed({ check: {
|
|
1239
|
+
message: `deployment manifest is invalid: ${error.message}`,
|
|
1240
|
+
name: "manifest",
|
|
1241
|
+
status: "fail"
|
|
1242
|
+
} })));
|
|
1243
|
+
}
|
|
1244
|
+
async function checkCredentials(manifest, envFilePath, env) {
|
|
1245
|
+
let mergedEnv;
|
|
1246
|
+
try {
|
|
1247
|
+
mergedEnv = await loadMergedLocalEnvFile(envFilePath, env);
|
|
1248
|
+
} catch (error) {
|
|
1249
|
+
return {
|
|
1250
|
+
message: `required env file is unavailable at ${envFilePath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1251
|
+
name: "credentials",
|
|
1252
|
+
status: "fail"
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
if (!manifest) return {
|
|
1256
|
+
message: "enabled Endpoint credentials cannot be checked until the deployment manifest is valid",
|
|
1257
|
+
name: "credentials",
|
|
1258
|
+
status: "fail"
|
|
1259
|
+
};
|
|
1260
|
+
try {
|
|
1261
|
+
for (const endpoint of manifest.endpoints.filter(({ enabled }) => enabled)) resolveFeishuEndpointCredentials(endpoint.credentialRef, mergedEnv);
|
|
1262
|
+
return {
|
|
1263
|
+
message: "enabled Endpoint credential references resolve",
|
|
1264
|
+
name: "credentials",
|
|
1265
|
+
status: "pass"
|
|
1266
|
+
};
|
|
1267
|
+
} catch (error) {
|
|
1268
|
+
return {
|
|
1269
|
+
message: `enabled Endpoint credentials are incomplete: ${error instanceof Error ? error.message : String(error)}`,
|
|
1270
|
+
name: "credentials",
|
|
1271
|
+
status: "fail"
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
async function missingRegularFiles(directory, paths) {
|
|
1276
|
+
const missing = [];
|
|
1277
|
+
for (const path of paths) try {
|
|
1278
|
+
if (!(await stat(resolve(directory, path))).isFile()) missing.push(path);
|
|
1279
|
+
} catch (error) {
|
|
1280
|
+
if (!isMissingPath$1(error)) throw error;
|
|
1281
|
+
missing.push(path);
|
|
1282
|
+
}
|
|
1283
|
+
return missing;
|
|
1284
|
+
}
|
|
1285
|
+
function isMissingPath$1(error) {
|
|
1286
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
1287
|
+
}
|
|
1288
|
+
function toError$1(error) {
|
|
1289
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
1290
|
+
}
|
|
1291
|
+
//#endregion
|
|
1292
|
+
//#region src/platform/project/setup/rivus-project-initializer.ts
|
|
1293
|
+
const TEMPLATE_FILES = Object.freeze({
|
|
1294
|
+
"current-weather.mjs": "current-weather.mjs",
|
|
1295
|
+
"https-response-reader.mjs": "https-response-reader.mjs",
|
|
1296
|
+
"rivus-agents.plugin.mjs": "rivus-starter.plugin.mjs",
|
|
1297
|
+
"rivus.bootstrap.ts": "pi-feishu-deployment.bootstrap.ts"
|
|
1298
|
+
});
|
|
1299
|
+
async function initializeRivusProject(options) {
|
|
1300
|
+
const directory = resolve(options.directory);
|
|
1301
|
+
const descriptor = options.releaseDescriptor ?? RIVUS_RELEASE_DESCRIPTOR;
|
|
1302
|
+
const files = /* @__PURE__ */ new Map([
|
|
1303
|
+
[".env.example", environmentTemplate()],
|
|
1304
|
+
[".gitignore", ".env.local\n.rivus/\nnode_modules/\n"],
|
|
1305
|
+
["deploy/launchd/com.rivus.agent.plist", launchdService(directory, options.nodeExecutable)],
|
|
1306
|
+
["deploy/systemd/rivus.service", systemdService(directory, options.nodeExecutable)],
|
|
1307
|
+
["package.json", projectPackageJson(directory, descriptor)],
|
|
1308
|
+
["rivus.config.json", deploymentManifest()]
|
|
1309
|
+
]);
|
|
1310
|
+
for (const [target, source] of Object.entries(TEMPLATE_FILES)) files.set(target, await readFile(join(options.templateDirectory, source), "utf8"));
|
|
1311
|
+
const paths = [...files.keys()].sort();
|
|
1312
|
+
await assertSafeProjectAncestors(directory, paths);
|
|
1313
|
+
const conflicts = await findConflicts(directory, paths);
|
|
1314
|
+
if (conflicts.length > 0) throw new Error(`Rivus project initialization refused; refusing to overwrite: ${conflicts.join(", ")}`);
|
|
1315
|
+
const createdDirectories = [];
|
|
1316
|
+
const createdFiles = [];
|
|
1317
|
+
const writeProjectFile = options.writeProjectFile ?? writeExclusiveProjectFile;
|
|
1318
|
+
try {
|
|
1319
|
+
for (const path of paths) {
|
|
1320
|
+
const destination = join(directory, path);
|
|
1321
|
+
await ensureDirectory(dirname(destination), directory, createdDirectories);
|
|
1322
|
+
await assertSafeProjectAncestors(directory, [path]);
|
|
1323
|
+
await writeProjectFile(destination, files.get(path));
|
|
1324
|
+
createdFiles.push(destination);
|
|
1325
|
+
}
|
|
1326
|
+
} catch (error) {
|
|
1327
|
+
const rollbackErrors = await rollbackCreatedPaths(createdFiles, createdDirectories);
|
|
1328
|
+
if (rollbackErrors.length > 0) throw new AggregateError([error, ...rollbackErrors], "Rivus project initialization failed and rollback was incomplete");
|
|
1329
|
+
throw error;
|
|
1330
|
+
}
|
|
1331
|
+
return {
|
|
1332
|
+
directory,
|
|
1333
|
+
files: Object.freeze(paths)
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
async function writeExclusiveProjectFile(path, contents) {
|
|
1337
|
+
await writeFile(path, contents, {
|
|
1338
|
+
encoding: "utf8",
|
|
1339
|
+
flag: "wx"
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1342
|
+
async function assertSafeProjectAncestors(directory, paths) {
|
|
1343
|
+
const rootState = await lstatOrUndefined(directory);
|
|
1344
|
+
if (rootState?.isSymbolicLink()) throw new Error("Rivus project initialization refused; symbolic link ancestor: .");
|
|
1345
|
+
if (rootState && !rootState.isDirectory()) throw new Error("Rivus project initialization refused; project path is not a directory");
|
|
1346
|
+
if (!rootState) return;
|
|
1347
|
+
for (const path of paths) {
|
|
1348
|
+
let current = directory;
|
|
1349
|
+
for (const segment of path.split("/").slice(0, -1)) {
|
|
1350
|
+
current = join(current, segment);
|
|
1351
|
+
const state = await lstatOrUndefined(current);
|
|
1352
|
+
if (!state) break;
|
|
1353
|
+
if (state.isSymbolicLink()) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(directory, current)}`);
|
|
1354
|
+
if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${relative(directory, current)}`);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
async function ensureDirectory(path, projectRoot, createdDirectories) {
|
|
1359
|
+
try {
|
|
1360
|
+
await mkdir(path);
|
|
1361
|
+
createdDirectories.push(path);
|
|
1362
|
+
} catch (error) {
|
|
1363
|
+
if (isMissingPath(error)) {
|
|
1364
|
+
const parent = dirname(path);
|
|
1365
|
+
if (parent === path) throw error;
|
|
1366
|
+
await ensureDirectory(parent, projectRoot, createdDirectories);
|
|
1367
|
+
await ensureDirectory(path, projectRoot, createdDirectories);
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
if (!isAlreadyExists(error)) throw error;
|
|
1371
|
+
const state = await lstat(path);
|
|
1372
|
+
if (state.isSymbolicLink()) {
|
|
1373
|
+
if (isPathWithin(projectRoot, path)) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(projectRoot, path) || "."}`);
|
|
1374
|
+
if ((await stat(path)).isDirectory()) return;
|
|
1375
|
+
}
|
|
1376
|
+
if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${path}`);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
async function rollbackCreatedPaths(files, directories) {
|
|
1380
|
+
const errors = [];
|
|
1381
|
+
for (const path of files.reverse()) try {
|
|
1382
|
+
await unlink(path);
|
|
1383
|
+
} catch (error) {
|
|
1384
|
+
if (!isMissingPath(error)) errors.push(asError(error));
|
|
1385
|
+
}
|
|
1386
|
+
for (const path of directories.reverse()) try {
|
|
1387
|
+
await rmdir(path);
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
if (!isMissingPath(error) && !isDirectoryNotEmpty(error)) errors.push(asError(error));
|
|
1390
|
+
}
|
|
1391
|
+
return errors;
|
|
1392
|
+
}
|
|
1393
|
+
async function lstatOrUndefined(path) {
|
|
1394
|
+
try {
|
|
1395
|
+
return await lstat(path);
|
|
1396
|
+
} catch (error) {
|
|
1397
|
+
if (isMissingPath(error)) return;
|
|
1398
|
+
throw error;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
function isAlreadyExists(error) {
|
|
1402
|
+
return error instanceof Error && "code" in error && error.code === "EEXIST";
|
|
1403
|
+
}
|
|
1404
|
+
function isDirectoryNotEmpty(error) {
|
|
1405
|
+
return error instanceof Error && "code" in error && error.code === "ENOTEMPTY";
|
|
1406
|
+
}
|
|
1407
|
+
function asError(error) {
|
|
1408
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
1409
|
+
}
|
|
1410
|
+
async function findConflicts(directory, paths) {
|
|
1411
|
+
const conflicts = [];
|
|
1412
|
+
for (const path of paths) try {
|
|
1413
|
+
await lstat(join(directory, path));
|
|
1414
|
+
conflicts.push(path);
|
|
1415
|
+
} catch (error) {
|
|
1416
|
+
if (!isMissingPath(error)) throw error;
|
|
1417
|
+
}
|
|
1418
|
+
return conflicts;
|
|
1419
|
+
}
|
|
1420
|
+
function isMissingPath(error) {
|
|
1421
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
1422
|
+
}
|
|
1423
|
+
function projectPackageJson(directory, descriptor) {
|
|
1424
|
+
const { dependencies, version } = descriptor;
|
|
1425
|
+
const projectName = sanitizePackageName(basename(directory));
|
|
1426
|
+
return `${JSON.stringify({
|
|
1427
|
+
name: projectName,
|
|
1428
|
+
private: true,
|
|
1429
|
+
type: "module",
|
|
1430
|
+
scripts: {
|
|
1431
|
+
"check-config": "rivus --manifest ./rivus.config.json --check-config",
|
|
1432
|
+
doctor: "rivus doctor .",
|
|
1433
|
+
start: "rivus --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json"
|
|
1434
|
+
},
|
|
1435
|
+
dependencies: {
|
|
1436
|
+
"@earendil-works/pi-coding-agent": dependencies["@earendil-works/pi-coding-agent"],
|
|
1437
|
+
"@larksuiteoapi/node-sdk": dependencies["@larksuiteoapi/node-sdk"],
|
|
1438
|
+
"@rivus/agent": `^${version}`,
|
|
1439
|
+
effect: dependencies.effect
|
|
1440
|
+
}
|
|
1441
|
+
}, null, 2)}\n`;
|
|
1442
|
+
}
|
|
1443
|
+
function sanitizePackageName(value) {
|
|
1444
|
+
return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "") || "rivus-app";
|
|
1445
|
+
}
|
|
1446
|
+
function deploymentManifest() {
|
|
1447
|
+
return `${JSON.stringify({
|
|
1448
|
+
plugins: [{
|
|
1449
|
+
id: "rivus-starter",
|
|
1450
|
+
module: "./rivus-agents.plugin.mjs",
|
|
1451
|
+
required: true
|
|
1452
|
+
}],
|
|
1453
|
+
agents: [{
|
|
1454
|
+
agentId: "agent-a",
|
|
1455
|
+
endpointIds: ["feishu-agent-a"],
|
|
1456
|
+
pluginId: "rivus-starter",
|
|
1457
|
+
profileId: "agent-a",
|
|
1458
|
+
skills: { allow: [] },
|
|
1459
|
+
tools: { allow: ["rivus-starter/current-weather"] }
|
|
1460
|
+
}],
|
|
1461
|
+
defaultAgentId: "agent-a",
|
|
1462
|
+
defaultEndpointId: "feishu-agent-a",
|
|
1463
|
+
endpoints: [{
|
|
1464
|
+
agentId: "agent-a",
|
|
1465
|
+
baseUrl: "https://open.feishu.cn",
|
|
1466
|
+
cardStreamLeaseMs: 51e4,
|
|
1467
|
+
credentialRef: "env:RIVUS_FEISHU",
|
|
1468
|
+
enabled: true,
|
|
1469
|
+
experimental: { cotMessages: false },
|
|
1470
|
+
groupPolicy: "mention-only",
|
|
1471
|
+
id: "feishu-agent-a",
|
|
1472
|
+
progressDisplay: "collapsed",
|
|
1473
|
+
required: true,
|
|
1474
|
+
sessionNamespace: "rivus-starter",
|
|
1475
|
+
streamMinIntervalMs: 200
|
|
1476
|
+
}]
|
|
1477
|
+
}, null, 2)}\n`;
|
|
1478
|
+
}
|
|
1479
|
+
function environmentTemplate() {
|
|
1480
|
+
return [
|
|
1481
|
+
"# Copy this file to .env.local and keep the real values untracked.",
|
|
1482
|
+
"RIVUS_FEISHU_APP_ID=",
|
|
1483
|
+
"RIVUS_FEISHU_APP_SECRET=",
|
|
1484
|
+
"PI_MODEL=",
|
|
1485
|
+
"PI_API_KEY=",
|
|
1486
|
+
"# PI_BASE_URL=",
|
|
1487
|
+
"RIVUS_WEATHER_DEFAULT_LOCATION=上海",
|
|
1488
|
+
"# LANGFUSE_BASE_URL=https://jp.cloud.langfuse.com",
|
|
1489
|
+
"# LANGFUSE_PUBLIC_KEY=",
|
|
1490
|
+
"# LANGFUSE_SECRET_KEY=",
|
|
1491
|
+
"# RIVUS_TELEMETRY_CONTENT=redacted",
|
|
1492
|
+
""
|
|
1493
|
+
].join("\n");
|
|
1494
|
+
}
|
|
1495
|
+
function systemdService(directory, nodeExecutable) {
|
|
1496
|
+
const cli = join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js");
|
|
1497
|
+
return `[Unit]\nDescription=Rivus Agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nWorkingDirectory=${systemdPath(directory)}\nExecStart=${systemdQuote(nodeExecutable)} ${systemdQuote(cli)} --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json\nRestart=on-failure\nRestartSec=5\nEnvironment=NODE_ENV=production\n\n[Install]\nWantedBy=default.target\n`;
|
|
1498
|
+
}
|
|
1499
|
+
function systemdPath(value) {
|
|
1500
|
+
return value.replaceAll("%", "%%");
|
|
1501
|
+
}
|
|
1502
|
+
function systemdQuote(value) {
|
|
1503
|
+
return `"${value.replace(/%/g, "%%").replace(/\$/g, () => "$$").replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
1504
|
+
}
|
|
1505
|
+
function launchdService(directory, nodeExecutable) {
|
|
1506
|
+
return `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n <key>Label</key>\n <string>com.rivus.agent</string>\n <key>ProgramArguments</key>\n <array>\n${[
|
|
1507
|
+
nodeExecutable,
|
|
1508
|
+
join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js"),
|
|
1509
|
+
"--env-file",
|
|
1510
|
+
".env.local",
|
|
1511
|
+
"--bootstrap",
|
|
1512
|
+
"./rivus.bootstrap.ts",
|
|
1513
|
+
"--manifest",
|
|
1514
|
+
"./rivus.config.json"
|
|
1515
|
+
].map((value) => ` <string>${xmlEscape(value)}</string>`).join("\n")}\n </array>\n <key>WorkingDirectory</key>\n <string>${xmlEscape(directory)}</string>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <dict>\n <key>SuccessfulExit</key>\n <false/>\n </dict>\n <key>ThrottleInterval</key>\n <integer>5</integer>\n</dict>\n</plist>\n`;
|
|
1516
|
+
}
|
|
1517
|
+
function xmlEscape(value) {
|
|
1518
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
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",
|
|
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",
|
|
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",
|
|
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/
|
|
3060
|
-
|
|
2858
|
+
//#region src/platform/runtime-pool/runtime-pool.ts
|
|
2859
|
+
var RuntimeResourceBusy = class extends Error {
|
|
2860
|
+
name = "RuntimeResourceBusy";
|
|
2861
|
+
};
|
|
2862
|
+
var RuntimeResourceDisposed = class extends Error {
|
|
2863
|
+
name = "RuntimeResourceDisposed";
|
|
2864
|
+
};
|
|
2865
|
+
var RuntimePoolDisposalTimedOut = class extends Error {
|
|
2866
|
+
name = "RuntimePoolDisposalTimedOut";
|
|
2867
|
+
};
|
|
2868
|
+
const DEFAULT_RUNTIME_DISPOSE_TIMEOUT_MS = 1e4;
|
|
2869
|
+
function createEffectRuntimePool(options) {
|
|
2870
|
+
const runtimes = createRuntimeCache();
|
|
2871
|
+
const active = /* @__PURE__ */ new Map();
|
|
2872
|
+
const lifecycle = Effect.unsafeMakeSemaphore(1);
|
|
2873
|
+
const existingRuntime = (instance) => Effect.gen(function* () {
|
|
2874
|
+
const selected = yield* runtimes.getExisting(instance.instanceId);
|
|
2875
|
+
if (!selected || !(yield* runtimes.isCurrent(instance.instanceId, selected.entry))) return;
|
|
2876
|
+
return selected.runtime;
|
|
2877
|
+
});
|
|
3061
2878
|
return {
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
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
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
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
|
|
3089
|
-
return
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
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
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
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
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
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:
|
|
2979
|
+
catch: (error) => error instanceof AgentInstanceConflict ? error : new AgentInstanceConflict(String(error))
|
|
3124
2980
|
});
|
|
3125
|
-
}
|
|
3126
|
-
function toLifecycleAdapter(adapter) {
|
|
3127
2981
|
return {
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
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
|
|
3140
|
-
|
|
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
|
-
|
|
3145
|
-
digest: createSha256Digest,
|
|
3146
|
-
deepFreeze
|
|
3147
|
-
});
|
|
3148
|
-
function createProcessDeploymentControlPorts(factories, backgroundSessions, runEffect) {
|
|
3059
|
+
function createProcessDeploymentControlPorts(factories, backgroundSessions) {
|
|
3149
3060
|
return {
|
|
3150
|
-
agentCatalog:
|
|
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
|
-
|
|
3077
|
+
runtimeFactory: { create: factories.createRuntime },
|
|
3078
|
+
endpointFactory: { create: factories.createEndpoint },
|
|
3079
|
+
...factories.createAutomation ? { automationFactory: { create: factories.createAutomation } } : {},
|
|
3080
|
+
...factories.createBackgroundSession ? { backgroundSessionFactory: { create: factories.createBackgroundSession } } : {}
|
|
3167
3081
|
};
|
|
3168
3082
|
}
|
|
3169
3083
|
//#endregion
|
|
@@ -3473,7 +3387,8 @@ function prepareDeployment(input) {
|
|
|
3473
3387
|
definitions,
|
|
3474
3388
|
deployment: effectiveDeployment,
|
|
3475
3389
|
endpointSlots,
|
|
3476
|
-
host
|
|
3390
|
+
host,
|
|
3391
|
+
projectSpaces
|
|
3477
3392
|
};
|
|
3478
3393
|
});
|
|
3479
3394
|
}
|
|
@@ -3612,6 +3527,8 @@ function makeDeploymentControl(input) {
|
|
|
3612
3527
|
let degraded = input.deployment.plugins.some(({ status: pluginStatus }) => pluginStatus === "failed");
|
|
3613
3528
|
for (const slot of input.endpointSlots) degraded = (yield* startSlot(slot, slot.agentEnabled, `endpoint ${slot.definition.id}`, () => Effect.gen(function* () {
|
|
3614
3529
|
const instance = yield* input.host.resolveEndpoint(slot.definition.id);
|
|
3530
|
+
const agentDefinition = input.definitions.get(slot.definition.agentId);
|
|
3531
|
+
const projectSpace = agentDefinition?.projectSpaceId ? input.projectSpaces.get(agentDefinition.projectSpaceId) : void 0;
|
|
3615
3532
|
return yield* input.endpointFactory.create({
|
|
3616
3533
|
agentId: slot.definition.agentId,
|
|
3617
3534
|
cancel: (request) => input.host.cancelEndpoint(slot.definition.id, request),
|
|
@@ -3619,7 +3536,9 @@ function makeDeploymentControl(input) {
|
|
|
3619
3536
|
endpointId: slot.definition.id,
|
|
3620
3537
|
handle: (request) => handleEndpoint(slot.definition.id, request),
|
|
3621
3538
|
instanceId: instance.instanceId,
|
|
3622
|
-
...
|
|
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
|
-
|
|
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
|
|
3825
|
+
}, manifest.backgroundSessions?.enabled === true),
|
|
3907
3826
|
deploymentRoot: dirname(context.manifestPath),
|
|
3908
3827
|
...adapters.initialInstanceRecords ? { initialInstanceRecords: adapters.initialInstanceRecords } : {},
|
|
3909
3828
|
manifest,
|
|
@@ -3922,7 +3841,15 @@ async function createRivusDeploymentCliProcess(factory, context) {
|
|
|
3922
3841
|
deployment,
|
|
3923
3842
|
digest: createSha256Digest
|
|
3924
3843
|
})));
|
|
3925
|
-
})))
|
|
3844
|
+
})).pipe(Effect.flatMap((control) => Effect.gen(function* () {
|
|
3845
|
+
const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL(Effect.suspend(() => adapters.createRecoveryControl ? adapters.createRecoveryControl() : Effect.fail(/* @__PURE__ */ new Error("Deployment bootstrap does not expose Recovery Control"))), Infinity);
|
|
3846
|
+
return {
|
|
3847
|
+
control,
|
|
3848
|
+
openRecovery: cached.pipe(Effect.onExit((exit) => Exit.isFailure(exit) && !Cause.isInterruptedOnly(exit.cause) ? invalidate : Effect.void))
|
|
3849
|
+
};
|
|
3850
|
+
})))));
|
|
3851
|
+
daemon = constructed.control;
|
|
3852
|
+
openRecovery = constructed.openRecovery;
|
|
3926
3853
|
} catch (constructionError) {
|
|
3927
3854
|
try {
|
|
3928
3855
|
await disposeAdapters();
|
|
@@ -3931,91 +3858,45 @@ async function createRivusDeploymentCliProcess(factory, context) {
|
|
|
3931
3858
|
}
|
|
3932
3859
|
throw constructionError;
|
|
3933
3860
|
}
|
|
3934
|
-
const
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
if (cleanupErrors.length > 0) throw new AggregateError([startError, ...cleanupErrors], "deployment startup and cleanup failed");
|
|
3951
|
-
throw startError;
|
|
3952
|
-
}
|
|
3953
|
-
};
|
|
3954
|
-
const stop = async () => {
|
|
3955
|
-
const errors = [];
|
|
3956
|
-
try {
|
|
3957
|
-
await runDeploymentProcessEffect(daemon.stop());
|
|
3958
|
-
} catch (error) {
|
|
3959
|
-
errors.push(error);
|
|
3960
|
-
}
|
|
3961
|
-
try {
|
|
3962
|
-
await disposeAdapters();
|
|
3963
|
-
} catch (error) {
|
|
3964
|
-
errors.push(error);
|
|
3965
|
-
}
|
|
3966
|
-
if (errors.length === 1) throw errors[0];
|
|
3967
|
-
if (errors.length > 1) throw new AggregateError(errors, "deployment and adapter cleanup failed");
|
|
3968
|
-
};
|
|
3861
|
+
const cleanupErrors = Effect.all([Effect.exit(Effect.suspend(() => daemon.stop())), Effect.exit(Effect.tryPromise({
|
|
3862
|
+
try: disposeAdapters,
|
|
3863
|
+
catch: (error) => error
|
|
3864
|
+
}))]).pipe(Effect.map((exits) => exits.filter(Exit.isFailure).map((exit) => Cause.squash(exit.cause))));
|
|
3865
|
+
const startDeployment = Effect.uninterruptible(Effect.suspend(() => {
|
|
3866
|
+
if (adaptersDisposed) return Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot restart after its adapters have been disposed"));
|
|
3867
|
+
return Effect.suspend(() => daemon.start()).pipe(Effect.catchAllCause((cause) => {
|
|
3868
|
+
const startError = Cause.squash(cause);
|
|
3869
|
+
return cleanupErrors.pipe(Effect.flatMap((errors) => Effect.fail(errors.length > 0 ? new AggregateError([startError, ...errors], "deployment startup and cleanup failed") : startError)));
|
|
3870
|
+
}));
|
|
3871
|
+
}));
|
|
3872
|
+
const stopDeployment = Effect.uninterruptible(cleanupErrors.pipe(Effect.flatMap((errors) => {
|
|
3873
|
+
if (errors.length === 1) return Effect.fail(errors[0]);
|
|
3874
|
+
if (errors.length > 1) return Effect.fail(new AggregateError(errors, "deployment and adapter cleanup failed"));
|
|
3875
|
+
return Effect.void;
|
|
3876
|
+
})));
|
|
3969
3877
|
const process = {
|
|
3970
3878
|
defaultSessionKey: `local:${daemon.deployment.manifest.defaultAgentId}:cli`,
|
|
3971
|
-
openRecoveryControl: () => Effect.
|
|
3972
|
-
try: async () => {
|
|
3973
|
-
if (adaptersDisposed) throw new Error("Rivus deployment process cannot open Recovery Control after disposal");
|
|
3974
|
-
if (!adapters.createRecoveryControl) throw new Error("Deployment bootstrap does not expose Recovery Control");
|
|
3975
|
-
recoveryControlPromise ??= Promise.resolve().then(() => adapters.createRecoveryControl());
|
|
3976
|
-
try {
|
|
3977
|
-
return await recoveryControlPromise;
|
|
3978
|
-
} catch (error) {
|
|
3979
|
-
recoveryControlPromise = void 0;
|
|
3980
|
-
throw error;
|
|
3981
|
-
}
|
|
3982
|
-
},
|
|
3983
|
-
catch: (error) => error
|
|
3984
|
-
}),
|
|
3879
|
+
openRecoveryControl: () => Effect.suspend(() => adaptersDisposed ? Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot open Recovery Control after disposal")) : openRecovery),
|
|
3985
3880
|
running: () => daemon.running(),
|
|
3986
|
-
start: () =>
|
|
3987
|
-
try: start,
|
|
3988
|
-
catch: (error) => error
|
|
3989
|
-
}),
|
|
3881
|
+
start: () => startDeployment,
|
|
3990
3882
|
status: () => Effect.sync(() => daemon.status()),
|
|
3991
|
-
stop: () =>
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
sessionKey: command.sessionKey,
|
|
4006
|
-
text: command.text
|
|
4007
|
-
})));
|
|
4008
|
-
},
|
|
4009
|
-
catch: (error) => error
|
|
4010
|
-
})
|
|
3883
|
+
stop: () => stopDeployment,
|
|
3884
|
+
promptText: (command) => Effect.suspend(() => {
|
|
3885
|
+
if (adaptersDisposed) return Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot restart after its adapters have been disposed"));
|
|
3886
|
+
const projectSpaceId = daemon.deployment.definitions.find(({ agentId }) => agentId === daemon.deployment.manifest.defaultAgentId)?.projectSpaceId;
|
|
3887
|
+
return daemon.runDefaultAgent({
|
|
3888
|
+
invocation: createLocalCliAgentInvocation({
|
|
3889
|
+
endpointId: daemon.deployment.manifest.defaultEndpointId,
|
|
3890
|
+
env: context.env,
|
|
3891
|
+
...projectSpaceId ? { projectSpaceId } : {}
|
|
3892
|
+
}),
|
|
3893
|
+
sessionKey: command.sessionKey,
|
|
3894
|
+
text: command.text
|
|
3895
|
+
}).pipe(Effect.map(readPromptFinalText));
|
|
3896
|
+
}).pipe(Effect.catchAllCause((cause) => Effect.fail(Cause.squash(cause))))
|
|
4011
3897
|
};
|
|
4012
3898
|
const replayReceiveMessage = adapters.replayReceiveMessage;
|
|
4013
|
-
if (replayReceiveMessage) process.replayReceiveMessage = (payload, options) => Effect.
|
|
4014
|
-
try: async () => {
|
|
4015
|
-
if (!daemon.running()) await start();
|
|
4016
|
-
},
|
|
4017
|
-
catch: (error) => error
|
|
4018
|
-
}).pipe(Effect.flatMap(() => replayReceiveMessage((input) => runDeploymentProcessEffect(daemon.handleDefault(toEffectAgentRuntimeInput(input))), payload, options)));
|
|
3899
|
+
if (replayReceiveMessage) process.replayReceiveMessage = (payload, options) => Effect.suspend(() => daemon.running() ? Effect.void : startDeployment).pipe(Effect.flatMap(() => replayReceiveMessage((input) => daemon.handleDefault(input), payload, options)));
|
|
4019
3900
|
return process;
|
|
4020
3901
|
}
|
|
4021
3902
|
function readPromptFinalText(result) {
|
|
@@ -4063,8 +3944,7 @@ function runRivusDaemonCli(options) {
|
|
|
4063
3944
|
try: () => loadCliEnv(parsed.envFilePath, options.env),
|
|
4064
3945
|
catch: (error) => error
|
|
4065
3946
|
});
|
|
4066
|
-
const
|
|
4067
|
-
const bootstrapSpecifier = configuredBootstrapSpecifier ? resolveRivusBuiltinSpecifier(configuredBootstrapSpecifier) : void 0;
|
|
3947
|
+
const bootstrapSpecifier = parsed.bootstrap ?? env.RIVUS_BOOTSTRAP_MODULE?.trim();
|
|
4068
3948
|
if (!parsed.checkConfig && !bootstrapSpecifier) {
|
|
4069
3949
|
options.stderr.write(formatRivusDaemonUsageError("Missing --bootstrap <module> or RIVUS_BOOTSTRAP_MODULE"));
|
|
4070
3950
|
return 1;
|
|
@@ -4461,4 +4341,5 @@ function toImportSpecifier(specifier) {
|
|
|
4461
4341
|
return specifier;
|
|
4462
4342
|
}
|
|
4463
4343
|
//#endregion
|
|
4464
|
-
export {
|
|
4344
|
+
export { RIVUS_PLUGIN_API_VERSION as i, createRivusPluginCatalog as n, resolveRivusAgentDefinition as r, runRivusNodeEntrypoint as t };
|
|
4345
|
+
|