@rivus/gateway 0.16.6 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -21
- package/README.md +25 -0
- package/dist/bootstrap/herdr-feishu.d.ts +37 -0
- package/dist/bootstrap/herdr-feishu.js +853 -0
- package/dist/bootstrap/pi-feishu.d.ts +281 -16
- package/dist/bootstrap/pi-feishu.js +17315 -345
- 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 +735 -847
- package/dist/chunks/{node-rivus-deployment-manifest.js → runtime-cache.js} +1118 -1476
- 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, Deferred, Effect, Exit, Result, Semaphore } from "effect";
|
|
10
|
+
import { lstat, mkdir, open, readFile, readdir, realpath, rmdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
11
|
+
import { randomUUID } from "node:crypto";
|
|
13
12
|
import { assertPathWithin, isPathWithin } from "@rivus/platform/filesystem";
|
|
13
|
+
import { createConnection } from "node:net";
|
|
14
14
|
import { constants as constants$1 } from "node:fs";
|
|
15
|
-
|
|
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
|
-
};
|
|
428
|
+
function createRivusPluginCatalog() {
|
|
429
|
+
return createRivusPluginCatalog$1(runtime);
|
|
678
430
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
encoding: "utf8",
|
|
682
|
-
flag: "wx"
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
async function assertSafeProjectAncestors(directory, paths) {
|
|
686
|
-
const rootState = await lstatOrUndefined(directory);
|
|
687
|
-
if (rootState?.isSymbolicLink()) throw new Error("Rivus project initialization refused; symbolic link ancestor: .");
|
|
688
|
-
if (rootState && !rootState.isDirectory()) throw new Error("Rivus project initialization refused; project path is not a directory");
|
|
689
|
-
if (!rootState) return;
|
|
690
|
-
for (const path of paths) {
|
|
691
|
-
let current = directory;
|
|
692
|
-
for (const segment of path.split("/").slice(0, -1)) {
|
|
693
|
-
current = join(current, segment);
|
|
694
|
-
const state = await lstatOrUndefined(current);
|
|
695
|
-
if (!state) break;
|
|
696
|
-
if (state.isSymbolicLink()) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(directory, current)}`);
|
|
697
|
-
if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${relative(directory, current)}`);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
async function ensureDirectory(path, projectRoot, createdDirectories) {
|
|
702
|
-
try {
|
|
703
|
-
await mkdir(path);
|
|
704
|
-
createdDirectories.push(path);
|
|
705
|
-
} catch (error) {
|
|
706
|
-
if (isMissingPath$1(error)) {
|
|
707
|
-
const parent = dirname(path);
|
|
708
|
-
if (parent === path) throw error;
|
|
709
|
-
await ensureDirectory(parent, projectRoot, createdDirectories);
|
|
710
|
-
await ensureDirectory(path, projectRoot, createdDirectories);
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
|
-
if (!isAlreadyExists(error)) throw error;
|
|
714
|
-
const state = await lstat(path);
|
|
715
|
-
if (state.isSymbolicLink()) {
|
|
716
|
-
if (isPathWithin(projectRoot, path)) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(projectRoot, path) || "."}`);
|
|
717
|
-
if ((await stat(path)).isDirectory()) return;
|
|
718
|
-
}
|
|
719
|
-
if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${path}`);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
async function rollbackCreatedPaths(files, directories) {
|
|
723
|
-
const errors = [];
|
|
724
|
-
for (const path of files.reverse()) try {
|
|
725
|
-
await unlink(path);
|
|
726
|
-
} catch (error) {
|
|
727
|
-
if (!isMissingPath$1(error)) errors.push(asError$1(error));
|
|
728
|
-
}
|
|
729
|
-
for (const path of directories.reverse()) try {
|
|
730
|
-
await rmdir(path);
|
|
731
|
-
} catch (error) {
|
|
732
|
-
if (!isMissingPath$1(error) && !isDirectoryNotEmpty(error)) errors.push(asError$1(error));
|
|
733
|
-
}
|
|
734
|
-
return errors;
|
|
735
|
-
}
|
|
736
|
-
async function lstatOrUndefined(path) {
|
|
737
|
-
try {
|
|
738
|
-
return await lstat(path);
|
|
739
|
-
} catch (error) {
|
|
740
|
-
if (isMissingPath$1(error)) return void 0;
|
|
741
|
-
throw error;
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
function isAlreadyExists(error) {
|
|
745
|
-
return error instanceof Error && "code" in error && error.code === "EEXIST";
|
|
746
|
-
}
|
|
747
|
-
function isDirectoryNotEmpty(error) {
|
|
748
|
-
return error instanceof Error && "code" in error && error.code === "ENOTEMPTY";
|
|
749
|
-
}
|
|
750
|
-
function asError$1(error) {
|
|
751
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
752
|
-
}
|
|
753
|
-
async function findConflicts(directory, paths) {
|
|
754
|
-
const conflicts = [];
|
|
755
|
-
for (const path of paths) try {
|
|
756
|
-
await lstat(join(directory, path));
|
|
757
|
-
conflicts.push(path);
|
|
758
|
-
} catch (error) {
|
|
759
|
-
if (!isMissingPath$1(error)) throw error;
|
|
760
|
-
}
|
|
761
|
-
return conflicts;
|
|
762
|
-
}
|
|
763
|
-
function isMissingPath$1(error) {
|
|
764
|
-
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
765
|
-
}
|
|
766
|
-
function projectPackageJson(directory, descriptor) {
|
|
767
|
-
const { dependencies, version } = descriptor;
|
|
768
|
-
const projectName = sanitizePackageName(basename(directory));
|
|
769
|
-
return `${JSON.stringify({
|
|
770
|
-
name: projectName,
|
|
771
|
-
private: true,
|
|
772
|
-
type: "module",
|
|
773
|
-
scripts: {
|
|
774
|
-
"check-config": "rivus --manifest ./rivus.config.json --check-config",
|
|
775
|
-
doctor: "rivus doctor .",
|
|
776
|
-
start: "rivus --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json"
|
|
777
|
-
},
|
|
778
|
-
dependencies: {
|
|
779
|
-
"@earendil-works/pi-coding-agent": dependencies["@earendil-works/pi-coding-agent"],
|
|
780
|
-
"@larksuiteoapi/node-sdk": dependencies["@larksuiteoapi/node-sdk"],
|
|
781
|
-
"@rivus/agent": `^${version}`,
|
|
782
|
-
effect: dependencies.effect
|
|
783
|
-
}
|
|
784
|
-
}, null, 2)}\n`;
|
|
785
|
-
}
|
|
786
|
-
function sanitizePackageName(value) {
|
|
787
|
-
return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "") || "rivus-app";
|
|
788
|
-
}
|
|
789
|
-
function deploymentManifest$1() {
|
|
790
|
-
return `${JSON.stringify({
|
|
791
|
-
plugins: [{
|
|
792
|
-
id: "rivus-starter",
|
|
793
|
-
module: "./rivus-agents.plugin.mjs",
|
|
794
|
-
required: true
|
|
795
|
-
}],
|
|
796
|
-
agents: [{
|
|
797
|
-
agentId: "agent-a",
|
|
798
|
-
endpointIds: ["feishu-agent-a"],
|
|
799
|
-
pluginId: "rivus-starter",
|
|
800
|
-
profileId: "agent-a",
|
|
801
|
-
skills: { allow: [] },
|
|
802
|
-
tools: { allow: ["rivus-starter/current-weather"] }
|
|
803
|
-
}],
|
|
804
|
-
defaultAgentId: "agent-a",
|
|
805
|
-
defaultEndpointId: "feishu-agent-a",
|
|
806
|
-
endpoints: [{
|
|
807
|
-
agentId: "agent-a",
|
|
808
|
-
baseUrl: "https://open.feishu.cn",
|
|
809
|
-
cardStreamLeaseMs: 51e4,
|
|
810
|
-
credentialRef: "env:RIVUS_FEISHU",
|
|
811
|
-
enabled: true,
|
|
812
|
-
experimental: { cotMessages: false },
|
|
813
|
-
groupPolicy: "mention-only",
|
|
814
|
-
id: "feishu-agent-a",
|
|
815
|
-
progressDisplay: "collapsed",
|
|
816
|
-
required: true,
|
|
817
|
-
sessionNamespace: "rivus-starter",
|
|
818
|
-
streamMinIntervalMs: 200
|
|
819
|
-
}]
|
|
820
|
-
}, null, 2)}\n`;
|
|
821
|
-
}
|
|
822
|
-
function environmentTemplate$1() {
|
|
823
|
-
return [
|
|
824
|
-
"# Copy this file to .env.local and keep the real values untracked.",
|
|
825
|
-
"RIVUS_FEISHU_APP_ID=",
|
|
826
|
-
"RIVUS_FEISHU_APP_SECRET=",
|
|
827
|
-
"PI_MODEL=",
|
|
828
|
-
"PI_API_KEY=",
|
|
829
|
-
"# PI_BASE_URL=",
|
|
830
|
-
"RIVUS_WEATHER_DEFAULT_LOCATION=上海",
|
|
831
|
-
"# LANGFUSE_BASE_URL=https://jp.cloud.langfuse.com",
|
|
832
|
-
"# LANGFUSE_PUBLIC_KEY=",
|
|
833
|
-
"# LANGFUSE_SECRET_KEY=",
|
|
834
|
-
"# RIVUS_TELEMETRY_CONTENT=redacted",
|
|
835
|
-
""
|
|
836
|
-
].join("\n");
|
|
837
|
-
}
|
|
838
|
-
function systemdService(directory, nodeExecutable) {
|
|
839
|
-
const cli = join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js");
|
|
840
|
-
return `[Unit]\nDescription=Rivus Agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nWorkingDirectory=${systemdPath(directory)}\nExecStart=${systemdQuote(nodeExecutable)} ${systemdQuote(cli)} --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json\nRestart=on-failure\nRestartSec=5\nEnvironment=NODE_ENV=production\n\n[Install]\nWantedBy=default.target\n`;
|
|
841
|
-
}
|
|
842
|
-
function systemdPath(value) {
|
|
843
|
-
return value.replaceAll("%", "%%");
|
|
844
|
-
}
|
|
845
|
-
function systemdQuote(value) {
|
|
846
|
-
return `"${value.replace(/%/g, "%%").replace(/\$/g, () => "$$").replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
847
|
-
}
|
|
848
|
-
function launchdService(directory, nodeExecutable) {
|
|
849
|
-
return `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n <key>Label</key>\n <string>com.rivus.agent</string>\n <key>ProgramArguments</key>\n <array>\n${[
|
|
850
|
-
nodeExecutable,
|
|
851
|
-
join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js"),
|
|
852
|
-
"--env-file",
|
|
853
|
-
".env.local",
|
|
854
|
-
"--bootstrap",
|
|
855
|
-
"./rivus.bootstrap.ts",
|
|
856
|
-
"--manifest",
|
|
857
|
-
"./rivus.config.json"
|
|
858
|
-
].map((value) => ` <string>${xmlEscape(value)}</string>`).join("\n")}\n </array>\n <key>WorkingDirectory</key>\n <string>${xmlEscape(directory)}</string>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <dict>\n <key>SuccessfulExit</key>\n <false/>\n </dict>\n <key>ThrottleInterval</key>\n <integer>5</integer>\n</dict>\n</plist>\n`;
|
|
431
|
+
function createBootstrapAgentCatalog(backgroundSessions = false) {
|
|
432
|
+
return createRivusAgentCatalog([createRivusHostToolDescriptorProvider({ backgroundSessions })], runtime);
|
|
859
433
|
}
|
|
860
|
-
function
|
|
861
|
-
return
|
|
862
|
-
}
|
|
863
|
-
//#endregion
|
|
864
|
-
//#region src/adapters/deployment/plugin/rivus-builtin-specifiers.ts
|
|
865
|
-
const RIVUS_BUILTIN_SPECIFIERS = /* @__PURE__ */ new Map([["@rivus/agent/bootstrap/pi-feishu", "@rivus/gateway/bootstrap/pi-feishu"], ["@rivus/agent/plugin/starter", "@rivus/gateway/plugin/starter"]]);
|
|
866
|
-
function resolveRivusBuiltinSpecifier(specifier) {
|
|
867
|
-
return RIVUS_BUILTIN_SPECIFIERS.get(specifier) ?? specifier;
|
|
434
|
+
function resolveRivusAgentDefinition(catalog, deployment, options = {}) {
|
|
435
|
+
return createBootstrapAgentCatalog(options.backgroundSessions === true).resolve(catalog, deployment);
|
|
868
436
|
}
|
|
869
437
|
//#endregion
|
|
870
438
|
//#region src/adapters/deployment/plugin/rivus-plugin-module.ts
|
|
@@ -872,13 +440,13 @@ function resolveRivusPluginModule(module) {
|
|
|
872
440
|
const candidate = "default" in module ? module.default : module;
|
|
873
441
|
return (typeof candidate === "function" ? Effect.tryPromise({
|
|
874
442
|
try: () => Promise.resolve(candidate()),
|
|
875
|
-
catch: toError$
|
|
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 {
|
|
@@ -1127,7 +540,7 @@ function checkManifest(home) {
|
|
|
1127
540
|
},
|
|
1128
541
|
manifest
|
|
1129
542
|
};
|
|
1130
|
-
}), Effect.
|
|
543
|
+
}), Effect.catch((error) => Effect.succeed({ check: {
|
|
1131
544
|
message: `deployment manifest is invalid: ${formatError(error)}`,
|
|
1132
545
|
name: "manifest",
|
|
1133
546
|
status: "fail"
|
|
@@ -1139,20 +552,20 @@ function checkModules(home, manifest, resolveModule, resolvePluginModule) {
|
|
|
1139
552
|
name: "modules",
|
|
1140
553
|
status: "fail"
|
|
1141
554
|
});
|
|
1142
|
-
const specifiers = [
|
|
555
|
+
const specifiers = [home.bootstrap, ...home.bootstrap === "@rivus/gateway/bootstrap/pi-feishu" ? DEFAULT_BOOTSTRAP_PEERS : []];
|
|
1143
556
|
return Effect.gen(function* () {
|
|
1144
557
|
const missing = [];
|
|
1145
558
|
for (const specifier of specifiers) {
|
|
1146
|
-
const result = yield* toEffect(() => resolveModule(specifier)).pipe(Effect.
|
|
1147
|
-
if (result._tag === "
|
|
559
|
+
const result = yield* toEffect(() => resolveModule(specifier)).pipe(Effect.result);
|
|
560
|
+
if (result._tag === "Failure") missing.push(`${specifier} (${formatError(result.failure)})`);
|
|
1148
561
|
}
|
|
1149
562
|
for (const plugin of manifest.plugins) {
|
|
1150
563
|
const result = yield* toEffect(() => resolvePluginModule({
|
|
1151
564
|
deploymentRoot: home.directory,
|
|
1152
|
-
module:
|
|
565
|
+
module: plugin.module,
|
|
1153
566
|
pluginId: plugin.id
|
|
1154
|
-
})).pipe(Effect.
|
|
1155
|
-
if (result._tag === "
|
|
567
|
+
})).pipe(Effect.result);
|
|
568
|
+
if (result._tag === "Failure") missing.push(`${plugin.module} (${formatError(result.failure)})`);
|
|
1156
569
|
}
|
|
1157
570
|
return missing.length === 0 ? {
|
|
1158
571
|
message: "Bootstrap, Plugin, Pi, and Feishu modules resolve from the global installation",
|
|
@@ -1179,7 +592,7 @@ function toEffect(read) {
|
|
|
1179
592
|
}
|
|
1180
593
|
});
|
|
1181
594
|
}
|
|
1182
|
-
function checkCredentials(home, manifest, env, envFilePath) {
|
|
595
|
+
function checkCredentials$1(home, manifest, env, envFilePath) {
|
|
1183
596
|
if (!manifest) return Effect.succeed({
|
|
1184
597
|
message: "credentials cannot be checked until manifest is valid",
|
|
1185
598
|
name: "credentials",
|
|
@@ -1196,7 +609,7 @@ function checkCredentials(home, manifest, env, envFilePath) {
|
|
|
1196
609
|
};
|
|
1197
610
|
},
|
|
1198
611
|
catch: toError$2
|
|
1199
|
-
}).pipe(Effect.
|
|
612
|
+
}).pipe(Effect.catch((error) => Effect.succeed({
|
|
1200
613
|
message: `enabled Endpoint credentials are incomplete: ${formatError(error)}`,
|
|
1201
614
|
name: "credentials",
|
|
1202
615
|
status: "fail"
|
|
@@ -1239,7 +652,7 @@ function loadRivusHome(directoryPath) {
|
|
|
1239
652
|
workspaceDirectory: resolveHomePath(directory, config.workspace, "workspace")
|
|
1240
653
|
};
|
|
1241
654
|
},
|
|
1242
|
-
catch: asError
|
|
655
|
+
catch: asError$1
|
|
1243
656
|
});
|
|
1244
657
|
}
|
|
1245
658
|
function parseRivusHomeConfig(value) {
|
|
@@ -1279,24 +692,24 @@ function record(value, owner) {
|
|
|
1279
692
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${owner} must be an object`);
|
|
1280
693
|
return value;
|
|
1281
694
|
}
|
|
1282
|
-
function asError(error) {
|
|
695
|
+
function asError$1(error) {
|
|
1283
696
|
return error instanceof Error ? error : new Error(String(error));
|
|
1284
697
|
}
|
|
1285
698
|
//#endregion
|
|
1286
699
|
//#region src/platform/home/doctor/rivus-home-doctor.ts
|
|
1287
700
|
function diagnoseRivusHome(input, options) {
|
|
1288
701
|
return Effect.gen(function* () {
|
|
1289
|
-
const checks = [checkNode(input.nodeVersion)];
|
|
1290
|
-
const loaded = yield* options.load(input.directory).pipe(Effect.
|
|
1291
|
-
if (
|
|
702
|
+
const checks = [checkNode$1(input.nodeVersion)];
|
|
703
|
+
const loaded = yield* options.load(input.directory).pipe(Effect.result);
|
|
704
|
+
if (Result.isFailure(loaded)) {
|
|
1292
705
|
checks.push({
|
|
1293
|
-
message: `Rivus Home is invalid: ${loaded.
|
|
706
|
+
message: `Rivus Home is invalid: ${loaded.failure.message}`,
|
|
1294
707
|
name: "home",
|
|
1295
708
|
status: "fail"
|
|
1296
709
|
}, blockedCheck("workspace", "Workspace"), blockedCheck("manifest", "manifest"), blockedCheck("modules", "modules"), blockedCheck("credentials", "credentials"));
|
|
1297
710
|
return report(input.directory, checks);
|
|
1298
711
|
}
|
|
1299
|
-
const home = loaded.
|
|
712
|
+
const home = loaded.success;
|
|
1300
713
|
checks.push({
|
|
1301
714
|
message: "config.json is valid and contained in Rivus Home",
|
|
1302
715
|
name: "home",
|
|
@@ -1312,7 +725,7 @@ function diagnoseRivusHome(input, options) {
|
|
|
1312
725
|
return report(input.directory, checks);
|
|
1313
726
|
});
|
|
1314
727
|
}
|
|
1315
|
-
function checkNode(version) {
|
|
728
|
+
function checkNode$1(version) {
|
|
1316
729
|
const [major, minor] = version.split(".").map(Number);
|
|
1317
730
|
return major === 24 && Number.isInteger(minor) && minor >= 11 ? {
|
|
1318
731
|
message: `Node.js ${version} satisfies the supported ^24.11 runtime`,
|
|
@@ -1366,10 +779,10 @@ function createRivusHomeLayout() {
|
|
|
1366
779
|
return {
|
|
1367
780
|
directories: HOME_DIRECTORIES,
|
|
1368
781
|
files: /* @__PURE__ */ new Map([
|
|
1369
|
-
[".env.example", environmentTemplate()],
|
|
782
|
+
[".env.example", environmentTemplate$1()],
|
|
1370
783
|
[".gitignore", ".DS_Store\n.env\nlogs/\nstate/\nworkspace/work/tmp/\n"],
|
|
1371
784
|
["config.json", homeConfig()],
|
|
1372
|
-
["rivus.config.json", deploymentManifest()],
|
|
785
|
+
["rivus.config.json", deploymentManifest$1()],
|
|
1373
786
|
["workspace/AGENTS.md", agentsTemplate()],
|
|
1374
787
|
["workspace/IDENTITY.md", "# Identity\n\nName: Rivus\n\nRole: Personal agent\n"],
|
|
1375
788
|
["workspace/MEMORY.md", "# Curated Memory\n\nStore confirmed, durable facts and decisions here.\n"],
|
|
@@ -1395,7 +808,7 @@ function homeConfig() {
|
|
|
1395
808
|
workspace: "workspace"
|
|
1396
809
|
}, null, 2)}\n`;
|
|
1397
810
|
}
|
|
1398
|
-
function deploymentManifest() {
|
|
811
|
+
function deploymentManifest$1() {
|
|
1399
812
|
return `${JSON.stringify({
|
|
1400
813
|
agents: [{
|
|
1401
814
|
agentId: "personal",
|
|
@@ -1448,7 +861,7 @@ function deploymentManifest() {
|
|
|
1448
861
|
}]
|
|
1449
862
|
}, null, 2)}\n`;
|
|
1450
863
|
}
|
|
1451
|
-
function environmentTemplate() {
|
|
864
|
+
function environmentTemplate$1() {
|
|
1452
865
|
return [
|
|
1453
866
|
"# Copy this file to .env and keep the real values untracked.",
|
|
1454
867
|
"RIVUS_FEISHU_APP_ID=",
|
|
@@ -1632,7 +1045,7 @@ function shellQuote(value) {
|
|
|
1632
1045
|
}
|
|
1633
1046
|
//#endregion
|
|
1634
1047
|
//#region src/adapters/cli/model/rivus-model-management-socket-client.ts
|
|
1635
|
-
const MAX_FRAME_BYTES =
|
|
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.result);
|
|
1223
|
+
if (Result.isFailure(result)) missingModules.push(plugin.module);
|
|
1224
|
+
}
|
|
1225
|
+
if (missingModules.length > 0) return { check: {
|
|
1226
|
+
message: `manifest Plugin modules are missing: ${missingModules.join(", ")}`,
|
|
1227
|
+
name: "manifest",
|
|
1228
|
+
status: "fail"
|
|
1229
|
+
} };
|
|
1230
|
+
return {
|
|
1231
|
+
check: {
|
|
1232
|
+
message: "deployment manifest is valid",
|
|
1233
|
+
name: "manifest",
|
|
1234
|
+
status: "pass"
|
|
1235
|
+
},
|
|
1236
|
+
manifest
|
|
1237
|
+
};
|
|
1238
|
+
})), Effect.catch((error) => Effect.succeed({ check: {
|
|
1239
|
+
message: `deployment manifest is invalid: ${error.message}`,
|
|
1240
|
+
name: "manifest",
|
|
1241
|
+
status: "fail"
|
|
1242
|
+
} })));
|
|
1243
|
+
}
|
|
1244
|
+
async function checkCredentials(manifest, envFilePath, env) {
|
|
1245
|
+
let mergedEnv;
|
|
1246
|
+
try {
|
|
1247
|
+
mergedEnv = await loadMergedLocalEnvFile(envFilePath, env);
|
|
1248
|
+
} catch (error) {
|
|
1249
|
+
return {
|
|
1250
|
+
message: `required env file is unavailable at ${envFilePath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1251
|
+
name: "credentials",
|
|
1252
|
+
status: "fail"
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
if (!manifest) return {
|
|
1256
|
+
message: "enabled Endpoint credentials cannot be checked until the deployment manifest is valid",
|
|
1257
|
+
name: "credentials",
|
|
1258
|
+
status: "fail"
|
|
1259
|
+
};
|
|
1260
|
+
try {
|
|
1261
|
+
for (const endpoint of manifest.endpoints.filter(({ enabled }) => enabled)) resolveFeishuEndpointCredentials(endpoint.credentialRef, mergedEnv);
|
|
1262
|
+
return {
|
|
1263
|
+
message: "enabled Endpoint credential references resolve",
|
|
1264
|
+
name: "credentials",
|
|
1265
|
+
status: "pass"
|
|
1266
|
+
};
|
|
1267
|
+
} catch (error) {
|
|
1268
|
+
return {
|
|
1269
|
+
message: `enabled Endpoint credentials are incomplete: ${error instanceof Error ? error.message : String(error)}`,
|
|
1270
|
+
name: "credentials",
|
|
1271
|
+
status: "fail"
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
async function missingRegularFiles(directory, paths) {
|
|
1276
|
+
const missing = [];
|
|
1277
|
+
for (const path of paths) try {
|
|
1278
|
+
if (!(await stat(resolve(directory, path))).isFile()) missing.push(path);
|
|
1279
|
+
} catch (error) {
|
|
1280
|
+
if (!isMissingPath$1(error)) throw error;
|
|
1281
|
+
missing.push(path);
|
|
1282
|
+
}
|
|
1283
|
+
return missing;
|
|
1284
|
+
}
|
|
1285
|
+
function isMissingPath$1(error) {
|
|
1286
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
1287
|
+
}
|
|
1288
|
+
function toError$1(error) {
|
|
1289
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
1290
|
+
}
|
|
1291
|
+
//#endregion
|
|
1292
|
+
//#region src/platform/project/setup/rivus-project-initializer.ts
|
|
1293
|
+
const TEMPLATE_FILES = Object.freeze({
|
|
1294
|
+
"current-weather.mjs": "current-weather.mjs",
|
|
1295
|
+
"https-response-reader.mjs": "https-response-reader.mjs",
|
|
1296
|
+
"rivus-agents.plugin.mjs": "rivus-starter.plugin.mjs",
|
|
1297
|
+
"rivus.bootstrap.ts": "pi-feishu-deployment.bootstrap.ts"
|
|
1298
|
+
});
|
|
1299
|
+
async function initializeRivusProject(options) {
|
|
1300
|
+
const directory = resolve(options.directory);
|
|
1301
|
+
const descriptor = options.releaseDescriptor ?? RIVUS_RELEASE_DESCRIPTOR;
|
|
1302
|
+
const files = /* @__PURE__ */ new Map([
|
|
1303
|
+
[".env.example", environmentTemplate()],
|
|
1304
|
+
[".gitignore", ".env.local\n.rivus/\nnode_modules/\n"],
|
|
1305
|
+
["deploy/launchd/com.rivus.agent.plist", launchdService(directory, options.nodeExecutable)],
|
|
1306
|
+
["deploy/systemd/rivus.service", systemdService(directory, options.nodeExecutable)],
|
|
1307
|
+
["package.json", projectPackageJson(directory, descriptor)],
|
|
1308
|
+
["rivus.config.json", deploymentManifest()]
|
|
1309
|
+
]);
|
|
1310
|
+
for (const [target, source] of Object.entries(TEMPLATE_FILES)) files.set(target, await readFile(join(options.templateDirectory, source), "utf8"));
|
|
1311
|
+
const paths = [...files.keys()].sort();
|
|
1312
|
+
await assertSafeProjectAncestors(directory, paths);
|
|
1313
|
+
const conflicts = await findConflicts(directory, paths);
|
|
1314
|
+
if (conflicts.length > 0) throw new Error(`Rivus project initialization refused; refusing to overwrite: ${conflicts.join(", ")}`);
|
|
1315
|
+
const createdDirectories = [];
|
|
1316
|
+
const createdFiles = [];
|
|
1317
|
+
const writeProjectFile = options.writeProjectFile ?? writeExclusiveProjectFile;
|
|
1318
|
+
try {
|
|
1319
|
+
for (const path of paths) {
|
|
1320
|
+
const destination = join(directory, path);
|
|
1321
|
+
await ensureDirectory(dirname(destination), directory, createdDirectories);
|
|
1322
|
+
await assertSafeProjectAncestors(directory, [path]);
|
|
1323
|
+
await writeProjectFile(destination, files.get(path));
|
|
1324
|
+
createdFiles.push(destination);
|
|
1325
|
+
}
|
|
1326
|
+
} catch (error) {
|
|
1327
|
+
const rollbackErrors = await rollbackCreatedPaths(createdFiles, createdDirectories);
|
|
1328
|
+
if (rollbackErrors.length > 0) throw new AggregateError([error, ...rollbackErrors], "Rivus project initialization failed and rollback was incomplete");
|
|
1329
|
+
throw error;
|
|
1330
|
+
}
|
|
1331
|
+
return {
|
|
1332
|
+
directory,
|
|
1333
|
+
files: Object.freeze(paths)
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
async function writeExclusiveProjectFile(path, contents) {
|
|
1337
|
+
await writeFile(path, contents, {
|
|
1338
|
+
encoding: "utf8",
|
|
1339
|
+
flag: "wx"
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1342
|
+
async function assertSafeProjectAncestors(directory, paths) {
|
|
1343
|
+
const rootState = await lstatOrUndefined(directory);
|
|
1344
|
+
if (rootState?.isSymbolicLink()) throw new Error("Rivus project initialization refused; symbolic link ancestor: .");
|
|
1345
|
+
if (rootState && !rootState.isDirectory()) throw new Error("Rivus project initialization refused; project path is not a directory");
|
|
1346
|
+
if (!rootState) return;
|
|
1347
|
+
for (const path of paths) {
|
|
1348
|
+
let current = directory;
|
|
1349
|
+
for (const segment of path.split("/").slice(0, -1)) {
|
|
1350
|
+
current = join(current, segment);
|
|
1351
|
+
const state = await lstatOrUndefined(current);
|
|
1352
|
+
if (!state) break;
|
|
1353
|
+
if (state.isSymbolicLink()) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(directory, current)}`);
|
|
1354
|
+
if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${relative(directory, current)}`);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
async function ensureDirectory(path, projectRoot, createdDirectories) {
|
|
1359
|
+
try {
|
|
1360
|
+
await mkdir(path);
|
|
1361
|
+
createdDirectories.push(path);
|
|
1362
|
+
} catch (error) {
|
|
1363
|
+
if (isMissingPath(error)) {
|
|
1364
|
+
const parent = dirname(path);
|
|
1365
|
+
if (parent === path) throw error;
|
|
1366
|
+
await ensureDirectory(parent, projectRoot, createdDirectories);
|
|
1367
|
+
await ensureDirectory(path, projectRoot, createdDirectories);
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
if (!isAlreadyExists(error)) throw error;
|
|
1371
|
+
const state = await lstat(path);
|
|
1372
|
+
if (state.isSymbolicLink()) {
|
|
1373
|
+
if (isPathWithin(projectRoot, path)) throw new Error(`Rivus project initialization refused; symbolic link ancestor: ${relative(projectRoot, path) || "."}`);
|
|
1374
|
+
if ((await stat(path)).isDirectory()) return;
|
|
1375
|
+
}
|
|
1376
|
+
if (!state.isDirectory()) throw new Error(`Rivus project initialization refused; non-directory ancestor: ${path}`);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
async function rollbackCreatedPaths(files, directories) {
|
|
1380
|
+
const errors = [];
|
|
1381
|
+
for (const path of files.reverse()) try {
|
|
1382
|
+
await unlink(path);
|
|
1383
|
+
} catch (error) {
|
|
1384
|
+
if (!isMissingPath(error)) errors.push(asError(error));
|
|
1385
|
+
}
|
|
1386
|
+
for (const path of directories.reverse()) try {
|
|
1387
|
+
await rmdir(path);
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
if (!isMissingPath(error) && !isDirectoryNotEmpty(error)) errors.push(asError(error));
|
|
1390
|
+
}
|
|
1391
|
+
return errors;
|
|
1392
|
+
}
|
|
1393
|
+
async function lstatOrUndefined(path) {
|
|
1394
|
+
try {
|
|
1395
|
+
return await lstat(path);
|
|
1396
|
+
} catch (error) {
|
|
1397
|
+
if (isMissingPath(error)) return;
|
|
1398
|
+
throw error;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
function isAlreadyExists(error) {
|
|
1402
|
+
return error instanceof Error && "code" in error && error.code === "EEXIST";
|
|
1403
|
+
}
|
|
1404
|
+
function isDirectoryNotEmpty(error) {
|
|
1405
|
+
return error instanceof Error && "code" in error && error.code === "ENOTEMPTY";
|
|
1406
|
+
}
|
|
1407
|
+
function asError(error) {
|
|
1408
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
1409
|
+
}
|
|
1410
|
+
async function findConflicts(directory, paths) {
|
|
1411
|
+
const conflicts = [];
|
|
1412
|
+
for (const path of paths) try {
|
|
1413
|
+
await lstat(join(directory, path));
|
|
1414
|
+
conflicts.push(path);
|
|
1415
|
+
} catch (error) {
|
|
1416
|
+
if (!isMissingPath(error)) throw error;
|
|
1417
|
+
}
|
|
1418
|
+
return conflicts;
|
|
1419
|
+
}
|
|
1420
|
+
function isMissingPath(error) {
|
|
1421
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
1422
|
+
}
|
|
1423
|
+
function projectPackageJson(directory, descriptor) {
|
|
1424
|
+
const { dependencies, version } = descriptor;
|
|
1425
|
+
const projectName = sanitizePackageName(basename(directory));
|
|
1426
|
+
return `${JSON.stringify({
|
|
1427
|
+
name: projectName,
|
|
1428
|
+
private: true,
|
|
1429
|
+
type: "module",
|
|
1430
|
+
scripts: {
|
|
1431
|
+
"check-config": "rivus --manifest ./rivus.config.json --check-config",
|
|
1432
|
+
doctor: "rivus doctor .",
|
|
1433
|
+
start: "rivus --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json"
|
|
1434
|
+
},
|
|
1435
|
+
dependencies: {
|
|
1436
|
+
"@earendil-works/pi-coding-agent": dependencies["@earendil-works/pi-coding-agent"],
|
|
1437
|
+
"@larksuiteoapi/node-sdk": dependencies["@larksuiteoapi/node-sdk"],
|
|
1438
|
+
"@rivus/agent": `^${version}`,
|
|
1439
|
+
effect: dependencies.effect
|
|
1440
|
+
}
|
|
1441
|
+
}, null, 2)}\n`;
|
|
1442
|
+
}
|
|
1443
|
+
function sanitizePackageName(value) {
|
|
1444
|
+
return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "") || "rivus-app";
|
|
1445
|
+
}
|
|
1446
|
+
function deploymentManifest() {
|
|
1447
|
+
return `${JSON.stringify({
|
|
1448
|
+
plugins: [{
|
|
1449
|
+
id: "rivus-starter",
|
|
1450
|
+
module: "./rivus-agents.plugin.mjs",
|
|
1451
|
+
required: true
|
|
1452
|
+
}],
|
|
1453
|
+
agents: [{
|
|
1454
|
+
agentId: "agent-a",
|
|
1455
|
+
endpointIds: ["feishu-agent-a"],
|
|
1456
|
+
pluginId: "rivus-starter",
|
|
1457
|
+
profileId: "agent-a",
|
|
1458
|
+
skills: { allow: [] },
|
|
1459
|
+
tools: { allow: ["rivus-starter/current-weather"] }
|
|
1460
|
+
}],
|
|
1461
|
+
defaultAgentId: "agent-a",
|
|
1462
|
+
defaultEndpointId: "feishu-agent-a",
|
|
1463
|
+
endpoints: [{
|
|
1464
|
+
agentId: "agent-a",
|
|
1465
|
+
baseUrl: "https://open.feishu.cn",
|
|
1466
|
+
cardStreamLeaseMs: 51e4,
|
|
1467
|
+
credentialRef: "env:RIVUS_FEISHU",
|
|
1468
|
+
enabled: true,
|
|
1469
|
+
experimental: { cotMessages: false },
|
|
1470
|
+
groupPolicy: "mention-only",
|
|
1471
|
+
id: "feishu-agent-a",
|
|
1472
|
+
progressDisplay: "collapsed",
|
|
1473
|
+
required: true,
|
|
1474
|
+
sessionNamespace: "rivus-starter",
|
|
1475
|
+
streamMinIntervalMs: 200
|
|
1476
|
+
}]
|
|
1477
|
+
}, null, 2)}\n`;
|
|
1478
|
+
}
|
|
1479
|
+
function environmentTemplate() {
|
|
1480
|
+
return [
|
|
1481
|
+
"# Copy this file to .env.local and keep the real values untracked.",
|
|
1482
|
+
"RIVUS_FEISHU_APP_ID=",
|
|
1483
|
+
"RIVUS_FEISHU_APP_SECRET=",
|
|
1484
|
+
"PI_MODEL=",
|
|
1485
|
+
"PI_API_KEY=",
|
|
1486
|
+
"# PI_BASE_URL=",
|
|
1487
|
+
"RIVUS_WEATHER_DEFAULT_LOCATION=上海",
|
|
1488
|
+
"# LANGFUSE_BASE_URL=https://jp.cloud.langfuse.com",
|
|
1489
|
+
"# LANGFUSE_PUBLIC_KEY=",
|
|
1490
|
+
"# LANGFUSE_SECRET_KEY=",
|
|
1491
|
+
"# RIVUS_TELEMETRY_CONTENT=redacted",
|
|
1492
|
+
""
|
|
1493
|
+
].join("\n");
|
|
1494
|
+
}
|
|
1495
|
+
function systemdService(directory, nodeExecutable) {
|
|
1496
|
+
const cli = join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js");
|
|
1497
|
+
return `[Unit]\nDescription=Rivus Agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nWorkingDirectory=${systemdPath(directory)}\nExecStart=${systemdQuote(nodeExecutable)} ${systemdQuote(cli)} --env-file .env.local --bootstrap ./rivus.bootstrap.ts --manifest ./rivus.config.json\nRestart=on-failure\nRestartSec=5\nEnvironment=NODE_ENV=production\n\n[Install]\nWantedBy=default.target\n`;
|
|
1498
|
+
}
|
|
1499
|
+
function systemdPath(value) {
|
|
1500
|
+
return value.replaceAll("%", "%%");
|
|
1501
|
+
}
|
|
1502
|
+
function systemdQuote(value) {
|
|
1503
|
+
return `"${value.replace(/%/g, "%%").replace(/\$/g, () => "$$").replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
1504
|
+
}
|
|
1505
|
+
function launchdService(directory, nodeExecutable) {
|
|
1506
|
+
return `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n <key>Label</key>\n <string>com.rivus.agent</string>\n <key>ProgramArguments</key>\n <array>\n${[
|
|
1507
|
+
nodeExecutable,
|
|
1508
|
+
join(directory, "node_modules", "@rivus", "agent", "dist", "cli.js"),
|
|
1509
|
+
"--env-file",
|
|
1510
|
+
".env.local",
|
|
1511
|
+
"--bootstrap",
|
|
1512
|
+
"./rivus.bootstrap.ts",
|
|
1513
|
+
"--manifest",
|
|
1514
|
+
"./rivus.config.json"
|
|
1515
|
+
].map((value) => ` <string>${xmlEscape(value)}</string>`).join("\n")}\n </array>\n <key>WorkingDirectory</key>\n <string>${xmlEscape(directory)}</string>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <dict>\n <key>SuccessfulExit</key>\n <false/>\n </dict>\n <key>ThrottleInterval</key>\n <integer>5</integer>\n</dict>\n</plist>\n`;
|
|
1516
|
+
}
|
|
1517
|
+
function xmlEscape(value) {
|
|
1518
|
+
return value.replace(/&/g, "&").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 = Semaphore.makeUnsafe(1);
|
|
2873
|
+
const existingRuntime = (instance) => Effect.gen(function* () {
|
|
2874
|
+
const selected = yield* runtimes.getExisting(instance.instanceId);
|
|
2875
|
+
if (!selected || !(yield* runtimes.isCurrent(instance.instanceId, selected.entry))) return;
|
|
2876
|
+
return selected.runtime;
|
|
2877
|
+
});
|
|
3061
2878
|
return {
|
|
3062
|
-
|
|
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
|
|
@@ -3207,10 +3121,10 @@ function resolveRivusDeployment(input) {
|
|
|
3207
3121
|
return plugin;
|
|
3208
3122
|
},
|
|
3209
3123
|
catch: toDeploymentFailure
|
|
3210
|
-
})), Effect.
|
|
3211
|
-
if (
|
|
3212
|
-
const message = formatDeploymentFailure(loaded.
|
|
3213
|
-
if (declaration.required) return yield* Effect.fail(new RivusPluginLoadError(declaration.id, declaration.module, `required plugin ${declaration.id} failed to load: ${message}`, { cause: loaded.
|
|
3124
|
+
})), Effect.result);
|
|
3125
|
+
if (Result.isFailure(loaded)) {
|
|
3126
|
+
const message = formatDeploymentFailure(loaded.failure);
|
|
3127
|
+
if (declaration.required) return yield* Effect.fail(new RivusPluginLoadError(declaration.id, declaration.module, `required plugin ${declaration.id} failed to load: ${message}`, { cause: loaded.failure }));
|
|
3214
3128
|
const status = Object.freeze({
|
|
3215
3129
|
error: message,
|
|
3216
3130
|
id: declaration.id,
|
|
@@ -3227,7 +3141,7 @@ function resolveRivusDeployment(input) {
|
|
|
3227
3141
|
module: declaration.module,
|
|
3228
3142
|
required: declaration.required,
|
|
3229
3143
|
status: "loaded",
|
|
3230
|
-
version: loaded.
|
|
3144
|
+
version: loaded.success.manifest.version
|
|
3231
3145
|
});
|
|
3232
3146
|
pluginStatuses.push(status);
|
|
3233
3147
|
statusByPlugin.set(declaration.id, status);
|
|
@@ -3261,23 +3175,23 @@ function resolveRivusDeployment(input) {
|
|
|
3261
3175
|
}) : baseDefinition;
|
|
3262
3176
|
},
|
|
3263
3177
|
catch: toDeploymentFailure
|
|
3264
|
-
}).pipe(Effect.
|
|
3265
|
-
if (
|
|
3178
|
+
}).pipe(Effect.result);
|
|
3179
|
+
if (Result.isFailure(resolved)) {
|
|
3266
3180
|
const declaration = input.manifest.plugins.find(({ id }) => id === agent.pluginId);
|
|
3267
|
-
if (declaration.required) return yield* Effect.fail(new RivusPluginLoadError(declaration.id, declaration.module, `deployment ${agent.agentId} failed to resolve: ${resolved.
|
|
3181
|
+
if (declaration.required) return yield* Effect.fail(new RivusPluginLoadError(declaration.id, declaration.module, `deployment ${agent.agentId} failed to resolve: ${resolved.failure.message}`, { cause: resolved.failure }));
|
|
3268
3182
|
agentStatuses.push(Object.freeze({
|
|
3269
3183
|
agentId: agent.agentId,
|
|
3270
3184
|
pluginId: agent.pluginId,
|
|
3271
3185
|
profileId: agent.profileId,
|
|
3272
|
-
reason: resolved.
|
|
3186
|
+
reason: resolved.failure.message,
|
|
3273
3187
|
status: "disabled"
|
|
3274
3188
|
}));
|
|
3275
3189
|
continue;
|
|
3276
3190
|
}
|
|
3277
|
-
definitions.push(resolved.
|
|
3191
|
+
definitions.push(resolved.success);
|
|
3278
3192
|
agentStatuses.push(Object.freeze({
|
|
3279
3193
|
agentId: agent.agentId,
|
|
3280
|
-
definition: resolved.
|
|
3194
|
+
definition: resolved.success,
|
|
3281
3195
|
pluginId: agent.pluginId,
|
|
3282
3196
|
profileId: agent.profileId,
|
|
3283
3197
|
status: "enabled"
|
|
@@ -3473,7 +3387,8 @@ function prepareDeployment(input) {
|
|
|
3473
3387
|
definitions,
|
|
3474
3388
|
deployment: effectiveDeployment,
|
|
3475
3389
|
endpointSlots,
|
|
3476
|
-
host
|
|
3390
|
+
host,
|
|
3391
|
+
projectSpaces
|
|
3477
3392
|
};
|
|
3478
3393
|
});
|
|
3479
3394
|
}
|
|
@@ -3612,6 +3527,8 @@ function makeDeploymentControl(input) {
|
|
|
3612
3527
|
let degraded = input.deployment.plugins.some(({ status: pluginStatus }) => pluginStatus === "failed");
|
|
3613
3528
|
for (const slot of input.endpointSlots) degraded = (yield* startSlot(slot, slot.agentEnabled, `endpoint ${slot.definition.id}`, () => Effect.gen(function* () {
|
|
3614
3529
|
const instance = yield* input.host.resolveEndpoint(slot.definition.id);
|
|
3530
|
+
const agentDefinition = input.definitions.get(slot.definition.agentId);
|
|
3531
|
+
const projectSpace = agentDefinition?.projectSpaceId ? input.projectSpaces.get(agentDefinition.projectSpaceId) : void 0;
|
|
3615
3532
|
return yield* input.endpointFactory.create({
|
|
3616
3533
|
agentId: slot.definition.agentId,
|
|
3617
3534
|
cancel: (request) => input.host.cancelEndpoint(slot.definition.id, request),
|
|
@@ -3619,7 +3536,9 @@ function makeDeploymentControl(input) {
|
|
|
3619
3536
|
endpointId: slot.definition.id,
|
|
3620
3537
|
handle: (request) => handleEndpoint(slot.definition.id, request),
|
|
3621
3538
|
instanceId: instance.instanceId,
|
|
3622
|
-
...
|
|
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,22 @@ async function createRivusDeploymentCliProcess(factory, context) {
|
|
|
3922
3841
|
deployment,
|
|
3923
3842
|
digest: createSha256Digest
|
|
3924
3843
|
})));
|
|
3925
|
-
})))
|
|
3844
|
+
})).pipe(Effect.map((control) => {
|
|
3845
|
+
let opening;
|
|
3846
|
+
return {
|
|
3847
|
+
control,
|
|
3848
|
+
openRecovery: Effect.uninterruptible(Effect.suspend(() => {
|
|
3849
|
+
if (opening) return Deferred.await(opening);
|
|
3850
|
+
const current = Deferred.makeUnsafe();
|
|
3851
|
+
opening = current;
|
|
3852
|
+
return Effect.suspend(() => adapters.createRecoveryControl ? adapters.createRecoveryControl() : Effect.fail(/* @__PURE__ */ new Error("Deployment bootstrap does not expose Recovery Control"))).pipe(Effect.onExit((exit) => Effect.sync(() => {
|
|
3853
|
+
if (Exit.isFailure(exit) && opening === current) opening = void 0;
|
|
3854
|
+
}).pipe(Effect.andThen(Deferred.done(current, exit)))));
|
|
3855
|
+
}))
|
|
3856
|
+
};
|
|
3857
|
+
}))));
|
|
3858
|
+
daemon = constructed.control;
|
|
3859
|
+
openRecovery = constructed.openRecovery;
|
|
3926
3860
|
} catch (constructionError) {
|
|
3927
3861
|
try {
|
|
3928
3862
|
await disposeAdapters();
|
|
@@ -3931,91 +3865,45 @@ async function createRivusDeploymentCliProcess(factory, context) {
|
|
|
3931
3865
|
}
|
|
3932
3866
|
throw constructionError;
|
|
3933
3867
|
}
|
|
3934
|
-
const
|
|
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
|
-
};
|
|
3868
|
+
const cleanupErrors = Effect.all([Effect.exit(Effect.suspend(() => daemon.stop())), Effect.exit(Effect.tryPromise({
|
|
3869
|
+
try: disposeAdapters,
|
|
3870
|
+
catch: (error) => error
|
|
3871
|
+
}))]).pipe(Effect.map((exits) => exits.filter(Exit.isFailure).map((exit) => Cause.squash(exit.cause))));
|
|
3872
|
+
const startDeployment = Effect.uninterruptible(Effect.suspend(() => {
|
|
3873
|
+
if (adaptersDisposed) return Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot restart after its adapters have been disposed"));
|
|
3874
|
+
return Effect.suspend(() => daemon.start()).pipe(Effect.catchCause((cause) => {
|
|
3875
|
+
const startError = Cause.squash(cause);
|
|
3876
|
+
return cleanupErrors.pipe(Effect.flatMap((errors) => Effect.fail(errors.length > 0 ? new AggregateError([startError, ...errors], "deployment startup and cleanup failed") : startError)));
|
|
3877
|
+
}));
|
|
3878
|
+
}));
|
|
3879
|
+
const stopDeployment = Effect.uninterruptible(cleanupErrors.pipe(Effect.flatMap((errors) => {
|
|
3880
|
+
if (errors.length === 1) return Effect.fail(errors[0]);
|
|
3881
|
+
if (errors.length > 1) return Effect.fail(new AggregateError(errors, "deployment and adapter cleanup failed"));
|
|
3882
|
+
return Effect.void;
|
|
3883
|
+
})));
|
|
3969
3884
|
const process = {
|
|
3970
3885
|
defaultSessionKey: `local:${daemon.deployment.manifest.defaultAgentId}:cli`,
|
|
3971
|
-
openRecoveryControl: () => Effect.
|
|
3972
|
-
try: async () => {
|
|
3973
|
-
if (adaptersDisposed) throw new Error("Rivus deployment process cannot open Recovery Control after disposal");
|
|
3974
|
-
if (!adapters.createRecoveryControl) throw new Error("Deployment bootstrap does not expose Recovery Control");
|
|
3975
|
-
recoveryControlPromise ??= Promise.resolve().then(() => adapters.createRecoveryControl());
|
|
3976
|
-
try {
|
|
3977
|
-
return await recoveryControlPromise;
|
|
3978
|
-
} catch (error) {
|
|
3979
|
-
recoveryControlPromise = void 0;
|
|
3980
|
-
throw error;
|
|
3981
|
-
}
|
|
3982
|
-
},
|
|
3983
|
-
catch: (error) => error
|
|
3984
|
-
}),
|
|
3886
|
+
openRecoveryControl: () => Effect.suspend(() => adaptersDisposed ? Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot open Recovery Control after disposal")) : openRecovery),
|
|
3985
3887
|
running: () => daemon.running(),
|
|
3986
|
-
start: () =>
|
|
3987
|
-
try: start,
|
|
3988
|
-
catch: (error) => error
|
|
3989
|
-
}),
|
|
3888
|
+
start: () => startDeployment,
|
|
3990
3889
|
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
|
-
})
|
|
3890
|
+
stop: () => stopDeployment,
|
|
3891
|
+
promptText: (command) => Effect.suspend(() => {
|
|
3892
|
+
if (adaptersDisposed) return Effect.fail(/* @__PURE__ */ new Error("Rivus deployment process cannot restart after its adapters have been disposed"));
|
|
3893
|
+
const projectSpaceId = daemon.deployment.definitions.find(({ agentId }) => agentId === daemon.deployment.manifest.defaultAgentId)?.projectSpaceId;
|
|
3894
|
+
return daemon.runDefaultAgent({
|
|
3895
|
+
invocation: createLocalCliAgentInvocation({
|
|
3896
|
+
endpointId: daemon.deployment.manifest.defaultEndpointId,
|
|
3897
|
+
env: context.env,
|
|
3898
|
+
...projectSpaceId ? { projectSpaceId } : {}
|
|
3899
|
+
}),
|
|
3900
|
+
sessionKey: command.sessionKey,
|
|
3901
|
+
text: command.text
|
|
3902
|
+
}).pipe(Effect.map(readPromptFinalText));
|
|
3903
|
+
}).pipe(Effect.catchCause((cause) => Effect.fail(Cause.squash(cause))))
|
|
4011
3904
|
};
|
|
4012
3905
|
const replayReceiveMessage = adapters.replayReceiveMessage;
|
|
4013
|
-
if (replayReceiveMessage) process.replayReceiveMessage = (payload, options) => Effect.
|
|
4014
|
-
try: async () => {
|
|
4015
|
-
if (!daemon.running()) await start();
|
|
4016
|
-
},
|
|
4017
|
-
catch: (error) => error
|
|
4018
|
-
}).pipe(Effect.flatMap(() => replayReceiveMessage((input) => runDeploymentProcessEffect(daemon.handleDefault(toEffectAgentRuntimeInput(input))), payload, options)));
|
|
3906
|
+
if (replayReceiveMessage) process.replayReceiveMessage = (payload, options) => Effect.suspend(() => daemon.running() ? Effect.void : startDeployment).pipe(Effect.flatMap(() => replayReceiveMessage((input) => daemon.handleDefault(input), payload, options)));
|
|
4019
3907
|
return process;
|
|
4020
3908
|
}
|
|
4021
3909
|
function readPromptFinalText(result) {
|
|
@@ -4063,8 +3951,7 @@ function runRivusDaemonCli(options) {
|
|
|
4063
3951
|
try: () => loadCliEnv(parsed.envFilePath, options.env),
|
|
4064
3952
|
catch: (error) => error
|
|
4065
3953
|
});
|
|
4066
|
-
const
|
|
4067
|
-
const bootstrapSpecifier = configuredBootstrapSpecifier ? resolveRivusBuiltinSpecifier(configuredBootstrapSpecifier) : void 0;
|
|
3954
|
+
const bootstrapSpecifier = parsed.bootstrap ?? env.RIVUS_BOOTSTRAP_MODULE?.trim();
|
|
4068
3955
|
if (!parsed.checkConfig && !bootstrapSpecifier) {
|
|
4069
3956
|
options.stderr.write(formatRivusDaemonUsageError("Missing --bootstrap <module> or RIVUS_BOOTSTRAP_MODULE"));
|
|
4070
3957
|
return 1;
|
|
@@ -4189,7 +4076,7 @@ function runRivusDaemonCli(options) {
|
|
|
4189
4076
|
yield* daemon.start();
|
|
4190
4077
|
options.stdout.write(RIVUS_DAEMON_STARTED_MESSAGE);
|
|
4191
4078
|
return 0;
|
|
4192
|
-
}).pipe(Effect.
|
|
4079
|
+
}).pipe(Effect.catch((error) => Effect.sync(() => {
|
|
4193
4080
|
options.stderr.write(formatRivusDaemonLine(formatRivusDaemonError(error)));
|
|
4194
4081
|
return 1;
|
|
4195
4082
|
})));
|
|
@@ -4309,7 +4196,7 @@ function runModelCommand(options) {
|
|
|
4309
4196
|
return Effect.tryPromise({
|
|
4310
4197
|
try: () => client.execute(parsed),
|
|
4311
4198
|
catch: (error) => error
|
|
4312
|
-
}).pipe(Effect.tap((response) => Effect.sync(() => writeModelResponse(options.stdout, response))), Effect.map((response) => modelManagementExitCode(response)), Effect.
|
|
4199
|
+
}).pipe(Effect.tap((response) => Effect.sync(() => writeModelResponse(options.stdout, response))), Effect.map((response) => modelManagementExitCode(response)), Effect.catch((error) => Effect.sync(() => {
|
|
4313
4200
|
writeModelResponse(options.stdout, modelTransportFailure(error));
|
|
4314
4201
|
return 1;
|
|
4315
4202
|
})));
|
|
@@ -4337,7 +4224,7 @@ function modelTransportFailure(error) {
|
|
|
4337
4224
|
};
|
|
4338
4225
|
}
|
|
4339
4226
|
function runSetupCommand(options) {
|
|
4340
|
-
return withOptionalDirectoryArgument(options, "setup", (argument) => resolveHomeDirectoryEffect(options, argument).pipe(Effect.flatMap((directory) => options.homeApi.setup(directory).pipe(Effect.tap(() => Effect.sync(() => options.stdout.write(renderRivusSetupSuccess(directory)))), Effect.as(0))), Effect.
|
|
4227
|
+
return withOptionalDirectoryArgument(options, "setup", (argument) => resolveHomeDirectoryEffect(options, argument).pipe(Effect.flatMap((directory) => options.homeApi.setup(directory).pipe(Effect.tap(() => Effect.sync(() => options.stdout.write(renderRivusSetupSuccess(directory)))), Effect.as(0))), Effect.catch((error) => writeError(options, error))));
|
|
4341
4228
|
}
|
|
4342
4229
|
function runHomeDaemonCommand(options, command, daemonArgs) {
|
|
4343
4230
|
if (hasRivusHomeCommandArguments(options.argv.slice(1))) return Effect.sync(() => {
|
|
@@ -4361,7 +4248,7 @@ function runHomeDaemonCommand(options, command, daemonArgs) {
|
|
|
4361
4248
|
RIVUS_HOME: home.directory
|
|
4362
4249
|
},
|
|
4363
4250
|
pluginPackageManifestPath: options.pluginPackageManifestPath ?? gatewayPackageManifestPath
|
|
4364
|
-
})), Effect.
|
|
4251
|
+
})), Effect.catch((error) => writeError(options, error)));
|
|
4365
4252
|
}
|
|
4366
4253
|
function runInitCommand(options) {
|
|
4367
4254
|
return withOptionalDirectoryArgument(options, "init", (argument) => {
|
|
@@ -4373,7 +4260,7 @@ function runInitCommand(options) {
|
|
|
4373
4260
|
templateDirectory: gatewayTemplateDirectory
|
|
4374
4261
|
}),
|
|
4375
4262
|
catch: (error) => error
|
|
4376
|
-
}).pipe(Effect.tap((result) => Effect.sync(() => options.stdout.write(renderRivusProjectInitializationSuccess(result.directory)))), Effect.as(0), Effect.
|
|
4263
|
+
}).pipe(Effect.tap((result) => Effect.sync(() => options.stdout.write(renderRivusProjectInitializationSuccess(result.directory)))), Effect.as(0), Effect.catch((error) => writeError(options, error)));
|
|
4377
4264
|
});
|
|
4378
4265
|
}
|
|
4379
4266
|
function withOptionalDirectoryArgument(options, command, run) {
|
|
@@ -4406,14 +4293,14 @@ function runDoctorCommand(options) {
|
|
|
4406
4293
|
env: options.env,
|
|
4407
4294
|
...parsed.envFilePath ? { envFilePath: parsed.envFilePath } : {},
|
|
4408
4295
|
nodeVersion: options.nodeVersion
|
|
4409
|
-
})), Effect.map((report) => writeDoctorReport(options.stdout, report, "Home")), Effect.
|
|
4296
|
+
})), Effect.map((report) => writeDoctorReport(options.stdout, report, "Home")), Effect.catch((error) => writeError(options, error)));
|
|
4410
4297
|
const projectDirectory = parsed.directory;
|
|
4411
4298
|
return diagnoseRivusProject({
|
|
4412
4299
|
directory: resolve(options.cwd, projectDirectory),
|
|
4413
4300
|
env: options.env,
|
|
4414
4301
|
...parsed.envFilePath ? { envFilePath: parsed.envFilePath } : {},
|
|
4415
4302
|
nodeVersion: options.nodeVersion
|
|
4416
|
-
}).pipe(Effect.map((report) => writeDoctorReport(options.stdout, report, "project")), Effect.
|
|
4303
|
+
}).pipe(Effect.map((report) => writeDoctorReport(options.stdout, report, "project")), Effect.catch((error) => writeError(options, error)));
|
|
4417
4304
|
}
|
|
4418
4305
|
function resolveHomeDirectoryEffect(options, argument) {
|
|
4419
4306
|
return Effect.try({
|
|
@@ -4461,4 +4348,5 @@ function toImportSpecifier(specifier) {
|
|
|
4461
4348
|
return specifier;
|
|
4462
4349
|
}
|
|
4463
4350
|
//#endregion
|
|
4464
|
-
export {
|
|
4351
|
+
export { RIVUS_PLUGIN_API_VERSION as i, createRivusPluginCatalog as n, resolveRivusAgentDefinition as r, runRivusNodeEntrypoint as t };
|
|
4352
|
+
|