@schlenkr/ragents 0.1.11 → 0.1.13
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/README.md +1 -1
- package/apps/server/src/access-projection.ts +2 -2
- package/apps/server/src/plugin-build/build.ts +7 -7
- package/apps/server/src/profile/bundle-manifest.ts +11 -11
- package/apps/server/src/profile/plugin-discovery.ts +2 -2
- package/apps/server/src/provider.ts +1 -1
- package/apps/web/dist/assets/{highlighted-body-KPVGNVTW-BfNSGxjB.js → highlighted-body-KPVGNVTW-CpPi6QLr.js} +1 -1
- package/apps/web/dist/assets/{main-D6bsKcIK.js → main-DJmCHGzM.js} +1 -1
- package/apps/web/dist/assets/{mermaid-HWGCJPDP-DROEqEeg.js → mermaid-HWGCJPDP-q-mf1kLN.js} +2 -2
- package/apps/web/dist/assets/{runPanel-Dumuuqry.js → runPanel-nk_aMxSn.js} +1 -1
- package/apps/web/dist/host-web.json +1 -1
- package/apps/web/dist/index.html +2 -2
- package/apps/web/dist/run-panel.html +2 -2
- package/apps/web/src/chat/QuasselHost.tsx +1 -1
- package/bundles/ragents.activity/ragents-bundle.json +3 -3
- package/bundles/ragents.actor-programs/ragents-bundle.json +3 -3
- package/bundles/ragents.ask/ragents-bundle.json +3 -3
- package/bundles/ragents.browser/ragents-bundle.json +3 -3
- package/bundles/ragents.documents/ragents-bundle.json +3 -3
- package/bundles/ragents.lsp-fsharp/ragents-bundle.json +3 -3
- package/bundles/ragents.lsp-roslyn/ragents-bundle.json +3 -3
- package/bundles/ragents.lsp-typescript/ragents-bundle.json +3 -3
- package/bundles/ragents.model-relay/ragents-bundle.json +3 -3
- package/bundles/ragents.orchestration/ragents-bundle.json +3 -3
- package/bundles/ragents.orchestration/web/classes.json +1 -1
- package/bundles/ragents.orchestration/web/index.js +1 -1
- package/bundles/ragents.orchestration/web/index.js.map +2 -2
- package/bundles/ragents.overseer/ragents-bundle.json +3 -3
- package/bundles/ragents.processes/ragents-bundle.json +3 -3
- package/bundles/ragents.product/ragents-bundle.json +3 -3
- package/bundles/ragents.profile-distribution/ragents-bundle.json +3 -3
- package/bundles/ragents.reference/ragents-bundle.json +3 -3
- package/bundles/ragents.todo/ragents-bundle.json +3 -3
- package/bundles/ragents.todo/server/index.js +0 -3
- package/bundles/ragents.todo/server/index.js.map +2 -2
- package/bundles/ragents.todo/web/classes.json +1 -1
- package/bundles/ragents.todo/web/index.js +1 -1
- package/bundles/ragents.todo/web/index.js.map +2 -2
- package/bundles/ragents.transcript/ragents-bundle.json +3 -3
- package/bundles/ragents.watch/ragents-bundle.json +3 -3
- package/bundles/ragents.workspace/ragents-bundle.json +3 -3
- package/bundles/ragents.workspace/server/index.js +4 -4
- package/bundles/ragents.workspace/server/index.js.map +2 -2
- package/bundles/ragents.workspace/web/classes.json +1 -1
- package/bundles/ragents.workspace/web/index.js +1 -1
- package/bundles/ragents.workspace/web/index.js.map +2 -2
- package/package.json +2 -2
- package/packages/ai/src/providers/openrouter.models.ts +2 -2
- package/packages/ragents/src/runtime/journal-storage.ts +1 -1
- package/packages/workspace-executor/src/contributions.ts +10 -10
- package/packages/workspace-executor/src/executor.ts +1 -1
- package/packages/workspace-executor/src/files.ts +1 -1
- package/packages/workspace-executor/src/index.ts +1 -1
- package/packages/workspace-executor/src/language-server/host.ts +1 -1
- package/packages/workspace-executor/src/language-server/workspace-solutions.ts +1 -1
- package/plugins/ragents.orchestration/web/ActorChat.tsx +1 -1
- package/plugins/ragents.orchestration/web/ActorChatControls.tsx +0 -1
- package/plugins/ragents.todo/contract.ts +0 -3
- package/plugins/ragents.workspace/client/workspace-client.ts +9 -9
- package/plugins/ragents.workspace/contract.ts +1 -1
- package/plugins/ragents.workspace/server/clients.ts +9 -9
- package/scripts/package/build-package.ts +3 -3
- package/scripts/package/ragents.mjs +1 -1
- package/scripts/remote/connect.ts +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schlenkr/ragents",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "RAgents host: server, engine, plugins and tools without a source checkout",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -70,6 +70,6 @@
|
|
|
70
70
|
"yaml": "2.9.0"
|
|
71
71
|
},
|
|
72
72
|
"ragents": {
|
|
73
|
-
"hostVersion": "
|
|
73
|
+
"hostVersion": "2fe07b19a1aa4533d20428b040e88960fedc44cb"
|
|
74
74
|
}
|
|
75
75
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// Static model catalog for openrouter. Single source: there is no
|
|
2
|
+
// runtime store and no refresh over the network.
|
|
3
3
|
|
|
4
4
|
import type { Model } from "../types.ts";
|
|
5
5
|
|
|
@@ -8,7 +8,7 @@ import { isRunId } from "../domain/portable-id.ts";
|
|
|
8
8
|
import { syncDirectory } from "./durable-fs.ts";
|
|
9
9
|
import type { CommandRecord, JournalCommand } from "./journal.ts";
|
|
10
10
|
|
|
11
|
-
/** Rises whenever an older
|
|
11
|
+
/** Rises whenever an older version would reject newly written lines; formats 7 and 8 stay readable because they only lack the input origin and the compaction threshold. */
|
|
12
12
|
export const journalStorageVersion = 9;
|
|
13
13
|
const oldestReadableJournalStorageVersion = 7;
|
|
14
14
|
const readableJournalStorageVersions: readonly unknown[] = [oldestReadableJournalStorageVersion, 8, journalStorageVersion];
|
|
@@ -41,18 +41,18 @@ export interface WorkspaceExecutorParts {
|
|
|
41
41
|
export type WorkspaceExecutorContribution = (machine: WorkspaceExecutorMachine) => WorkspaceExecutorParts;
|
|
42
42
|
|
|
43
43
|
/** Whose contribution in which version; server and workspace require the same ones. */
|
|
44
|
-
export interface
|
|
44
|
+
export interface ExecutorContributionRevision {
|
|
45
45
|
readonly plugin: string;
|
|
46
46
|
/** SHA-256 of the file of the contribution. */
|
|
47
|
-
readonly
|
|
47
|
+
readonly revision: string;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
export interface LoadedExecutorContribution extends
|
|
50
|
+
export interface LoadedExecutorContribution extends ExecutorContributionRevision {
|
|
51
51
|
readonly contribution: WorkspaceExecutorContribution;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/** A contribution built for this machine. */
|
|
55
|
-
export interface PreparedExecutorContribution extends
|
|
55
|
+
export interface PreparedExecutorContribution extends ExecutorContributionRevision {
|
|
56
56
|
readonly parts: WorkspaceExecutorParts;
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -91,11 +91,11 @@ export const loadExecutorContribution = async (plugin: string, file: string, exp
|
|
|
91
91
|
const content = await readFile(file).catch((cause: unknown) => {
|
|
92
92
|
throw new Error(`The executor contribution of ${plugin} is missing at ${file}: ${messageOf(cause)}`);
|
|
93
93
|
});
|
|
94
|
-
const
|
|
95
|
-
if (expected !== undefined &&
|
|
96
|
-
throw new Error(`The executor contribution of ${plugin} at ${file} has the version ${
|
|
94
|
+
const revision = createHash("sha256").update(content).digest("hex");
|
|
95
|
+
if (expected !== undefined && revision !== expected) {
|
|
96
|
+
throw new Error(`The executor contribution of ${plugin} at ${file} has the version ${revision.slice(0, 12)}, required is ${expected.slice(0, 12)}`);
|
|
97
97
|
}
|
|
98
|
-
const exported = await import(`${pathToFileURL(file).href}?
|
|
98
|
+
const exported = await import(`${pathToFileURL(file).href}?revision=${revision}`).catch((cause: unknown) => {
|
|
99
99
|
throw new Error(`The executor contribution of ${plugin} (${file}) does not load: ${messageOf(cause)}`, { cause });
|
|
100
100
|
}) as Readonly<Record<string, unknown>>;
|
|
101
101
|
const contribution = exported.executor;
|
|
@@ -103,7 +103,7 @@ export const loadExecutorContribution = async (plugin: string, file: string, exp
|
|
|
103
103
|
throw new Error(`The bundle ${plugin} exports no valid executor contribution in ${file}; expected is `
|
|
104
104
|
+ "\"export const executor: WorkspaceExecutorContribution\" as a function of the machine");
|
|
105
105
|
}
|
|
106
|
-
return { plugin,
|
|
106
|
+
return { plugin, revision, contribution: contribution as WorkspaceExecutorContribution };
|
|
107
107
|
};
|
|
108
108
|
|
|
109
109
|
const isRecord = (value: unknown): value is Readonly<Record<string, unknown>> =>
|
|
@@ -146,5 +146,5 @@ export const prepareExecutorContribution = (loaded: LoadedExecutorContribution,
|
|
|
146
146
|
const problems = adapterProblems(server);
|
|
147
147
|
if (problems.length > 0) throw invalid(`the language server ${index + 1} needs ${problems.join(", ")}`);
|
|
148
148
|
}
|
|
149
|
-
return { plugin: loaded.plugin,
|
|
149
|
+
return { plugin: loaded.plugin, revision: loaded.revision, parts: parts as WorkspaceExecutorParts };
|
|
150
150
|
};
|
|
@@ -4,7 +4,7 @@ import type { WorkspaceExecutorModule, WorkspaceModuleFactory, WorkspaceOperatio
|
|
|
4
4
|
import { NO_ROOTS, type OperationFootprint } from "./paths.js";
|
|
5
5
|
|
|
6
6
|
/** The version of the executor; server and workspace must carry the same one. */
|
|
7
|
-
export const WORKSPACE_EXECUTOR_VERSION = "
|
|
7
|
+
export const WORKSPACE_EXECUTOR_VERSION = "8";
|
|
8
8
|
|
|
9
9
|
export interface WorkspaceExecuteOptions {
|
|
10
10
|
toolCallId?: string;
|
|
@@ -101,7 +101,7 @@ const entryOf = async (directory: string, name: string, isDirectory: boolean): P
|
|
|
101
101
|
|
|
102
102
|
const byKindThenName = (left: FileEntry, right: FileEntry): number =>
|
|
103
103
|
(left.kind === right.kind ? 0 : left.kind === "directory" ? -1 : 1)
|
|
104
|
-
|| left.name.localeCompare(right.name, "
|
|
104
|
+
|| left.name.localeCompare(right.name, "en");
|
|
105
105
|
|
|
106
106
|
const directoryIn = async (base: string, checked: string): Promise<string> => {
|
|
107
107
|
const directory = await inside(base, checked);
|
|
@@ -23,7 +23,7 @@ export {
|
|
|
23
23
|
executorMachine,
|
|
24
24
|
loadExecutorContribution,
|
|
25
25
|
prepareExecutorContribution,
|
|
26
|
-
type
|
|
26
|
+
type ExecutorContributionRevision,
|
|
27
27
|
type LoadedExecutorContribution,
|
|
28
28
|
type PreparedExecutorContribution,
|
|
29
29
|
type WorkspaceExecutorContribution,
|
|
@@ -351,7 +351,7 @@ export class LanguageServerHost {
|
|
|
351
351
|
await this.#exists(path.resolve(context.root, expandWorkspaceAlias(file, context.workspaceAliases ?? {}))) ? { path: file, diagnostics: [...diagnostics] } : null));
|
|
352
352
|
return entries
|
|
353
353
|
.filter((entry): entry is { path: string; diagnostics: LanguageServerDiagnostic[] } => entry !== null)
|
|
354
|
-
.sort((left, right) => left.path.localeCompare(right.path, "
|
|
354
|
+
.sort((left, right) => left.path.localeCompare(right.path, "en"));
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
async #changed(
|
|
@@ -78,7 +78,7 @@ export const workspaceSolutions = async (
|
|
|
78
78
|
const tracked = await gitSolutions(context, extensions);
|
|
79
79
|
const candidates = [...new Set(tracked ?? await directorySolutions(context.root, extensions))]
|
|
80
80
|
.filter((relative) => matches(relative, extensions))
|
|
81
|
-
.sort((left, right) => left.localeCompare(right, "
|
|
81
|
+
.sort((left, right) => left.localeCompare(right, "en"));
|
|
82
82
|
const workspaceRoot = await realpath(context.root);
|
|
83
83
|
const found = await Promise.all(candidates.map(async (relative): Promise<FoundSolution | undefined> => {
|
|
84
84
|
const absolute = path.join(context.root, relative);
|
|
@@ -32,7 +32,7 @@ export function ActorChat({ actor, view, presentation, display = presentation, p
|
|
|
32
32
|
const detailMode = inspect || configuredMode === "off" ? configuredMode : "current";
|
|
33
33
|
const messages = useMemo(() => actorChatMessages(view, actor, primaryMessages, conversation), [view, actor, primaryMessages, conversation]);
|
|
34
34
|
const openLink = useCallback((href: string) => {
|
|
35
|
-
const match = /^
|
|
35
|
+
const match = /^flow:(actor|input|turn|subscription|action|artifact)\/(.+)$/.exec(href);
|
|
36
36
|
if (!match) return false;
|
|
37
37
|
if (!inspect) return true;
|
|
38
38
|
onNavigate({ type: match[1] as FlowSelection["type"], id: match[2] });
|
|
@@ -37,7 +37,6 @@ export function ActorChatControls({ actor, view, composerVisible = true, present
|
|
|
37
37
|
<ChatInputToolbar
|
|
38
38
|
{...attachments}
|
|
39
39
|
disabled={disabledReason !== undefined}
|
|
40
|
-
layout={presentation === "surface" ? "inline" : "card"}
|
|
41
40
|
maxRows={4}
|
|
42
41
|
onSend={(text, files) => sendActorMessage(view.id, actor.id, text, files)}
|
|
43
42
|
onStop={writable && actor.lifecycle?.kind === "running" ? () => {
|
|
@@ -19,18 +19,15 @@ export const todoStatusOf = (value: unknown): TodoStatus | undefined => {
|
|
|
19
19
|
|
|
20
20
|
switch (value.trim().toLowerCase()) {
|
|
21
21
|
case "open":
|
|
22
|
-
case "offen":
|
|
23
22
|
case "pending":
|
|
24
23
|
return "open";
|
|
25
24
|
case "active":
|
|
26
25
|
case "doing":
|
|
27
26
|
case "in_progress":
|
|
28
|
-
case "in arbeit":
|
|
29
27
|
case "running":
|
|
30
28
|
return "active";
|
|
31
29
|
case "completed":
|
|
32
30
|
case "done":
|
|
33
|
-
case "erledigt":
|
|
34
31
|
case "finished":
|
|
35
32
|
return "completed";
|
|
36
33
|
default:
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
workspaceDataDirectory,
|
|
16
16
|
workspaceExecutorModules,
|
|
17
17
|
workspaceProcessContext,
|
|
18
|
-
type
|
|
18
|
+
type ExecutorContributionRevision,
|
|
19
19
|
type PreparedExecutorContribution,
|
|
20
20
|
type WorkspaceProcessContext,
|
|
21
21
|
} from "@ragents/workspace-executor";
|
|
@@ -119,8 +119,8 @@ const contextOf = (runs: ReadonlyMap<string, WorkspaceProcessContext>, runId: st
|
|
|
119
119
|
return Promise.resolve(context);
|
|
120
120
|
};
|
|
121
121
|
|
|
122
|
-
const sameContributions = (left: readonly
|
|
123
|
-
left.length === right.length && left.every((entry) => right.some((other) => other.plugin === entry.plugin && other.
|
|
122
|
+
const sameContributions = (left: readonly ExecutorContributionRevision[], right: readonly ExecutorContributionRevision[]): boolean =>
|
|
123
|
+
left.length === right.length && left.every((entry) => right.some((other) => other.plugin === entry.plugin && other.revision === entry.revision));
|
|
124
124
|
|
|
125
125
|
/** The bundles of a workstation are the built-in ones of its host; it cannot run a plugin that is missing there. */
|
|
126
126
|
const contributionFileOf = (hostRoot: string, plugin: string): string => join(hostRoot, "bundles", plugin, EXECUTOR_CONTRIBUTION_FILE);
|
|
@@ -128,7 +128,7 @@ const contributionFileOf = (hostRoot: string, plugin: string): string => join(ho
|
|
|
128
128
|
/** Loads the contributions the server requires from the bundles of this machine's host; a missing bundle or a different version is an error with a cause. */
|
|
129
129
|
const loadedContributions = async (
|
|
130
130
|
hostRoot: string | undefined,
|
|
131
|
-
wanted: readonly
|
|
131
|
+
wanted: readonly ExecutorContributionRevision[],
|
|
132
132
|
): Promise<readonly PreparedExecutorContribution[]> => {
|
|
133
133
|
if (wanted.length === 0) return [];
|
|
134
134
|
if (!hostRoot) {
|
|
@@ -136,9 +136,9 @@ const loadedContributions = async (
|
|
|
136
136
|
+ "knows no host from whose bundles it could load them. It gets one with the first connection to a distributing "
|
|
137
137
|
+ "server or through the setting ragents.hostPath");
|
|
138
138
|
}
|
|
139
|
-
return Promise.all(wanted.map(async ({ plugin,
|
|
139
|
+
return Promise.all(wanted.map(async ({ plugin, revision }) => {
|
|
140
140
|
if (!PLUGIN_ID_PATTERN.test(plugin)) throw new Error(`The server names ${plugin} as a plugin; that is not a plugin ID`);
|
|
141
|
-
const loaded = await loadExecutorContribution(plugin, contributionFileOf(hostRoot, plugin),
|
|
141
|
+
const loaded = await loadExecutorContribution(plugin, contributionFileOf(hostRoot, plugin), revision).catch((cause: unknown) => {
|
|
142
142
|
throw new VersionMismatch(`${messageOf(cause)}. The host of this workstation (${hostRoot}) must carry the same bundles as the server: `
|
|
143
143
|
+ "the RAgents extension or the package @schlenkr/ragents in the server's version, in a checkout pnpm build:plugins");
|
|
144
144
|
});
|
|
@@ -149,7 +149,7 @@ const loadedContributions = async (
|
|
|
149
149
|
/** An executor from the contributions the server required at sign-in. */
|
|
150
150
|
interface BuiltExecutor {
|
|
151
151
|
readonly executor: WorkspaceOperationExecutor;
|
|
152
|
-
readonly contributions: readonly
|
|
152
|
+
readonly contributions: readonly ExecutorContributionRevision[];
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
/** What a sign-in on this machine holds: its own executor, the tasks of its runs, and its handlers on the message layer. */
|
|
@@ -261,7 +261,7 @@ export class WorkspaceClient {
|
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
/** Keeps the executor as long as the server requires the same contributions; otherwise it builds a new one from the bundles of this machine and ends the old one. */
|
|
264
|
-
async #built(attachment: Attachment, wanted: readonly
|
|
264
|
+
async #built(attachment: Attachment, wanted: readonly ExecutorContributionRevision[]): Promise<BuiltExecutor> {
|
|
265
265
|
const current = attachment.built;
|
|
266
266
|
if (current && sameContributions(current.contributions, wanted)) return current;
|
|
267
267
|
const contributions = await loadedContributions(this.options.hostRoot(), wanted);
|
|
@@ -273,7 +273,7 @@ export class WorkspaceClient {
|
|
|
273
273
|
contributions: contributions.map((contribution) => contribution.parts),
|
|
274
274
|
}),
|
|
275
275
|
}),
|
|
276
|
-
contributions: contributions.map(({ plugin,
|
|
276
|
+
contributions: contributions.map(({ plugin, revision }) => ({ plugin, revision })),
|
|
277
277
|
};
|
|
278
278
|
if (attachment !== this.#attachment) {
|
|
279
279
|
await built.executor.shutdown();
|
|
@@ -102,7 +102,7 @@ export const PLUGIN_ID_PATTERN = /^[a-z0-9]+(?:[.-][a-z0-9]+)*$/;
|
|
|
102
102
|
|
|
103
103
|
const executorContributions = Type.Array(Type.Object({
|
|
104
104
|
plugin: Type.String({ pattern: PLUGIN_ID_PATTERN.source, maxLength: 128, description: "ID of the plugin" }),
|
|
105
|
-
|
|
105
|
+
revision: Type.String({ pattern: "^[0-9a-f]{64}$", description: "SHA-256 of the contribution file" }),
|
|
106
106
|
}, { additionalProperties: false }), { maxItems: 64, description: "The plugins' contributions to the executor, in the order of the server's plugin list" });
|
|
107
107
|
|
|
108
108
|
const clientDescription = {
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
WORKSPACE_EXECUTOR_VERSION,
|
|
14
14
|
sandboxRunEnvironment,
|
|
15
|
-
type
|
|
15
|
+
type ExecutorContributionRevision,
|
|
16
16
|
type WorkspaceExecuteOptions,
|
|
17
17
|
type WorkspaceExecutor,
|
|
18
18
|
} from "@ragents/workspace-executor";
|
|
@@ -92,12 +92,12 @@ const assertExecutor = (label: string, executor: string): void => {
|
|
|
92
92
|
);
|
|
93
93
|
};
|
|
94
94
|
|
|
95
|
-
const described = (contributions: readonly
|
|
96
|
-
contributions.map(({ plugin,
|
|
95
|
+
const described = (contributions: readonly ExecutorContributionRevision[]): string =>
|
|
96
|
+
contributions.map(({ plugin, revision }) => `${plugin} (${revision.slice(0, 12)})`).join(", ") || "none";
|
|
97
97
|
|
|
98
98
|
/** A workstation runs what the server's plugins contribute; with other contributions the same tools would behave differently there than on the server. */
|
|
99
|
-
const assertContributions = (label: string, expected: readonly
|
|
100
|
-
const key = (entry:
|
|
99
|
+
const assertContributions = (label: string, expected: readonly ExecutorContributionRevision[], given: readonly ExecutorContributionRevision[]): void => {
|
|
100
|
+
const key = (entry: ExecutorContributionRevision): string => `${entry.plugin}\0${entry.revision}`;
|
|
101
101
|
const same = expected.length === given.length && expected.every((entry) => given.some((other) => key(other) === key(entry)));
|
|
102
102
|
if (same) return;
|
|
103
103
|
throw new DomainError(
|
|
@@ -122,21 +122,21 @@ export const assertMayRegister = (access: AccessContext, local: boolean): void =
|
|
|
122
122
|
/** Knows the signed-in workstations per owner, holds per client the connection through which the server calls it back, and the stops that have not reached it. */
|
|
123
123
|
export class WorkspaceClientRegistry {
|
|
124
124
|
/** What the server's plugins contribute to the executor; every workstation must carry exactly these contributions. */
|
|
125
|
-
readonly contributions: readonly
|
|
125
|
+
readonly contributions: readonly ExecutorContributionRevision[];
|
|
126
126
|
readonly #clients = new Map<string, ClientEntry>();
|
|
127
127
|
/** Stops that have not reached the workstation yet, per workstation and run with the folder of the binding. */
|
|
128
128
|
readonly #pendingStops = new Map<string, Map<string, string>>();
|
|
129
129
|
readonly #stopRetries = new Map<string, NodeJS.Timeout>();
|
|
130
130
|
|
|
131
|
-
constructor(contributions: readonly
|
|
132
|
-
this.contributions = contributions.map(({ plugin,
|
|
131
|
+
constructor(contributions: readonly ExecutorContributionRevision[]) {
|
|
132
|
+
this.contributions = contributions.map(({ plugin, revision }) => ({ plugin, revision }));
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
async register(
|
|
136
136
|
id: string,
|
|
137
137
|
description: WorkspaceClientDescription,
|
|
138
138
|
executor: string,
|
|
139
|
-
contributions: readonly
|
|
139
|
+
contributions: readonly ExecutorContributionRevision[],
|
|
140
140
|
connection: MethodConnection,
|
|
141
141
|
): Promise<WorkspaceClientInfo> {
|
|
142
142
|
if (connection.streamless) {
|
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
import { readHostVersion, readPackageVersion } from "../../apps/server/src/host-version.ts";
|
|
8
8
|
import { hostWebDirectory, hostWebProblem, isCheckout } from "../../apps/server/src/host-web.ts";
|
|
9
9
|
import { runtimeLibraries } from "../../apps/server/src/plugin-support/actor-programs/runtime-libraries.ts";
|
|
10
|
-
import {
|
|
10
|
+
import { assertBundleRevision, readBundleManifest, sourceRevisionOf } from "../../apps/server/src/profile/bundle-manifest.ts";
|
|
11
11
|
import { builtInPluginFolders } from "../plugin/build-builtin-plugins.ts";
|
|
12
12
|
|
|
13
13
|
export const PACKAGE_NAME = "@schlenkr/ragents";
|
|
@@ -216,7 +216,7 @@ const assertBuiltInBundles = (root: string): void => {
|
|
|
216
216
|
for (const folder of builtInPluginFolders(path.join(root, "plugins"))) {
|
|
217
217
|
const bundle = path.join(root, "bundles", path.basename(folder));
|
|
218
218
|
if (!statSync(bundle, { throwIfNoEntry: false })?.isDirectory()) throw new Error(`The bundle ${bundle} is missing; run pnpm build:plugins first`);
|
|
219
|
-
if (readBundleManifest(bundle).
|
|
219
|
+
if (readBundleManifest(bundle).sourceRevision !== sourceRevisionOf(folder)) throw new Error(`The bundle ${bundle} no longer matches ${folder}; run pnpm build:plugins first`);
|
|
220
220
|
}
|
|
221
221
|
};
|
|
222
222
|
|
|
@@ -249,7 +249,7 @@ export const buildPackage = async (target: string, root = repositoryRoot): Promi
|
|
|
249
249
|
}
|
|
250
250
|
for (const folder of builtInPluginFolders(path.join(root, "plugins"))) {
|
|
251
251
|
const bundle = path.join(target, "bundles", path.basename(folder));
|
|
252
|
-
|
|
252
|
+
assertBundleRevision(bundle, readBundleManifest(bundle));
|
|
253
253
|
}
|
|
254
254
|
for (const file of await copyDeclarations(root, target)) {
|
|
255
255
|
fileCount += 1;
|
|
@@ -27,7 +27,7 @@ const usage = `Usage: ragents <command> [arguments]
|
|
|
27
27
|
stop <run> | stop --host cancel the running turn or stop the remembered host
|
|
28
28
|
connect <server-url> fetch the client profile with its bundles and start the local server with it
|
|
29
29
|
start <profile|path> start a profile of the package, an own profile file or a
|
|
30
|
-
fetched
|
|
30
|
+
fetched revision; the UI comes prebuilt
|
|
31
31
|
provision [<profile>|--workspace] fetch the plugins' tools
|
|
32
32
|
workspace-client <server-url> register this machine as a workspace
|
|
33
33
|
plugin build <folder...> build plugin source folders into bundles (--out, --watch)
|
|
@@ -10,7 +10,7 @@ import { ragentsDataRoot } from "../../apps/server/src/data-directory.ts";
|
|
|
10
10
|
import { filesBelow } from "../../apps/server/src/folder-install.ts";
|
|
11
11
|
import { removeHostRecord, writeHostRecord } from "../../apps/server/src/host-record.ts";
|
|
12
12
|
import { hostRoot, readHostApiVersion, readHostPackage } from "../../apps/server/src/host-version.ts";
|
|
13
|
-
import { BUNDLE_MANIFEST_FILE,
|
|
13
|
+
import { BUNDLE_MANIFEST_FILE, bundleRevision } from "../../apps/server/src/profile/bundle-manifest.ts";
|
|
14
14
|
import { readProfileTarget } from "../../apps/server/src/profile-target.ts";
|
|
15
15
|
import { RpcClient } from "../../apps/web/src/rpc/client.ts";
|
|
16
16
|
import { profileDistributionContracts, type ClientProfileDescription } from "../../plugins/ragents.profile-distribution/contract.ts";
|
|
@@ -135,9 +135,9 @@ const markAsModule = async (directory: string): Promise<void> => {
|
|
|
135
135
|
const assertArchivedBundles = (staging: string): void => {
|
|
136
136
|
for (const manifestFile of filesBelow(staging).filter((file) => path.posix.basename(file) === BUNDLE_MANIFEST_FILE)) {
|
|
137
137
|
const folder = path.join(staging, ...path.posix.dirname(manifestFile).split("/"));
|
|
138
|
-
const manifest = JSON.parse(readFileSync(path.join(folder, BUNDLE_MANIFEST_FILE), "utf8")) as { id?: unknown;
|
|
139
|
-
if (
|
|
140
|
-
throw new Error(`The bundle ${String(manifest.id)} in the server's archive does not have the files it was built with (
|
|
138
|
+
const manifest = JSON.parse(readFileSync(path.join(folder, BUNDLE_MANIFEST_FILE), "utf8")) as { id?: unknown; revision?: unknown };
|
|
139
|
+
if (bundleRevision(folder) !== manifest.revision) {
|
|
140
|
+
throw new Error(`The bundle ${String(manifest.id)} in the server's archive does not have the files it was built with (revision in ${manifestFile}); rebuild it on the server and repeat ragents connect`);
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
};
|