@sellable/install 0.1.803 → 0.1.804
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/container/Dockerfile +4 -4
- package/container/README.md +1 -1
- package/lib/sellable-agent/fly-admin-image/Dockerfile +3 -1
- package/lib/sellable-agent/fly-admin-image/admin-runtime.mjs +19 -3
- package/lib/sellable-agent/fly-customer-image/Dockerfile +2 -2
- package/lib/sellable-agent/fly-customer-image/claude-code-runs-api.d.mts +23 -3
- package/lib/sellable-agent/fly-customer-image/claude-code-runs-api.mjs +197 -52
- package/lib/sellable-agent/fly-customer-image/customer-runtime.mjs +48 -22
- package/lib/sellable-agent/fly-customer-image/endpoint-model-selection.d.mts +1 -0
- package/lib/sellable-agent/fly-customer-image/endpoint-model-selection.mjs +21 -4
- package/lib/sellable-agent/fly-customer-image/hermes-runs-client.mjs +61 -5
- package/lib/sellable-agent/fly-customer-image/openai-runs-client.d.mts +3 -1
- package/lib/sellable-agent/fly-customer-image/openai-runs-client.mjs +4 -1
- package/lib/sellable-agent/fly-customer-image/public-endpoint-guard.d.mts +28 -0
- package/lib/sellable-agent/fly-customer-image/public-endpoint-guard.mjs +209 -0
- package/lib/sellable-agent/fly-customer-image/runs-api-connections.d.mts +1 -1
- package/lib/sellable-agent/fly-customer-image/runs-api-connections.mjs +97 -24
- package/lib/sellable-agent/fly-customer-image/runs-api-health-check.mjs +11 -42
- package/lib/sellable-agent/fly-customer-image/workspace-connection-client.d.mts +22 -0
- package/lib/sellable-agent/fly-customer-image/workspace-connection-client.mjs +98 -0
- package/lib/sellable-agent/fly-runtime-identity.mjs +8 -0
- package/lib/sellable-agent/host-bootstrap.mjs +1 -1
- package/lib/sellable-agent/host-worker.mjs +1 -1
- package/lib/sellable-agent/profile-materializer.mjs +1 -1
- package/lib/sellable-agent/provisioning-adapter.mjs +1 -1
- package/package.json +1 -1
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
} from "./endpoint-model-selection.mjs";
|
|
6
6
|
import { createHermesRunsClient } from "./hermes-runs-client.mjs";
|
|
7
7
|
import { createOpenAiRunsClient } from "./openai-runs-client.mjs";
|
|
8
|
+
import { createPinnedFetch } from "./public-endpoint-guard.mjs";
|
|
9
|
+
import { createWorkspaceConnectionRunsClient } from "./workspace-connection-client.mjs";
|
|
8
10
|
|
|
9
11
|
export const RUNS_API_CONNECTIONS_ENV =
|
|
10
12
|
"SELLABLE_AGENT_RUNS_API_CONNECTIONS_JSON";
|
|
@@ -202,14 +204,107 @@ export function runsApiConnectionsForRuntime(raw, runtime) {
|
|
|
202
204
|
);
|
|
203
205
|
}
|
|
204
206
|
|
|
207
|
+
// Exactly the members the endpoint-connection-key verb returns. The key follows
|
|
208
|
+
// the saved key's rule (16-1024 characters), never the key-file rule; the
|
|
209
|
+
// remote tool's values are checked where the create body is built.
|
|
210
|
+
const connectionRelease = (value) =>
|
|
211
|
+
record(value) &&
|
|
212
|
+
Object.keys(value).sort().join(",") ===
|
|
213
|
+
"apiKey,keyGeneration,protocol,structuredOutputs,tools" &&
|
|
214
|
+
typeof value.apiKey === "string" &&
|
|
215
|
+
value.apiKey.length >= 16 &&
|
|
216
|
+
value.apiKey.length <= 1024 &&
|
|
217
|
+
!/[\s\x00-\x1f\x7f]/.test(value.apiKey) &&
|
|
218
|
+
Number.isSafeInteger(value.keyGeneration) &&
|
|
219
|
+
["runs-api", "openai-chat", "openai-responses"].includes(value.protocol) &&
|
|
220
|
+
typeof value.structuredOutputs === "boolean" &&
|
|
221
|
+
(value.tools === null ||
|
|
222
|
+
(value.protocol === "runs-api" &&
|
|
223
|
+
record(value.tools) &&
|
|
224
|
+
Object.keys(value.tools).sort().join(",") ===
|
|
225
|
+
"allowedTools,authorization,expiresAt,serverUrl" &&
|
|
226
|
+
typeof value.tools.serverUrl === "string" &&
|
|
227
|
+
typeof value.tools.authorization === "string" &&
|
|
228
|
+
Array.isArray(value.tools.allowedTools) &&
|
|
229
|
+
typeof value.tools.expiresAt === "string"));
|
|
230
|
+
|
|
231
|
+
// Adds the opener output contract (and a granted remote tool) to every submit.
|
|
232
|
+
function customRunsClient(client, claim, remoteTools) {
|
|
233
|
+
return Object.freeze({
|
|
234
|
+
...client,
|
|
235
|
+
submit(compiled, options) {
|
|
236
|
+
const request = remoteTools ? { ...compiled, remoteTools } : compiled;
|
|
237
|
+
// Public semantic endpoints have a published schema but no product tuple.
|
|
238
|
+
// Preserve that existing contract when calling a custom Runs service.
|
|
239
|
+
const schema = claim.revision?.outputSchema;
|
|
240
|
+
if (compiled.outputContract || !schema?.properties?.proposal)
|
|
241
|
+
return client.submit(request, options);
|
|
242
|
+
return client.submit(
|
|
243
|
+
{
|
|
244
|
+
...request,
|
|
245
|
+
outputContract: {
|
|
246
|
+
schemaVersion: "sellable-opener-output-contract/v1",
|
|
247
|
+
schema,
|
|
248
|
+
nativeProposalSchemaDigest: createHash("sha256")
|
|
249
|
+
.update(stable(schema.properties.proposal))
|
|
250
|
+
.digest("hex"),
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
options
|
|
254
|
+
);
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
205
259
|
/** @param {any} options */
|
|
206
|
-
export function createConfiguredRunsClient({
|
|
260
|
+
export async function createConfiguredRunsClient({
|
|
207
261
|
apiKeyFile,
|
|
208
262
|
claim,
|
|
209
263
|
env = process.env,
|
|
210
264
|
clientFactory = createHermesRunsClient,
|
|
265
|
+
fetchConnectionKey,
|
|
266
|
+
chainStep = 0,
|
|
267
|
+
createFetch = createPinnedFetch,
|
|
211
268
|
}) {
|
|
212
269
|
const selection = claim?.run?.modelSelection;
|
|
270
|
+
// A workspace connection never uses the registry, even on a matching URL:
|
|
271
|
+
// its key is fetched for this attempt and lives only in these closures, and
|
|
272
|
+
// every request goes through the address guard. URL and model come from
|
|
273
|
+
// the signed claim, never from the key response.
|
|
274
|
+
if (selection?.modelConnectionId) {
|
|
275
|
+
const step = compileEndpointModelSelection(selection);
|
|
276
|
+
if (!step || step === "invalid") throw new Error("runs_api_model_rejected");
|
|
277
|
+
let release = null;
|
|
278
|
+
try {
|
|
279
|
+
release = await fetchConnectionKey(step.modelConnectionId, chainStep);
|
|
280
|
+
} catch {
|
|
281
|
+
// Every refusal is one fixed code: no server reason, no response field.
|
|
282
|
+
}
|
|
283
|
+
if (!connectionRelease(release))
|
|
284
|
+
throw new Error("runs_api_connection_unavailable");
|
|
285
|
+
const { apiKey, protocol, structuredOutputs, tools } = release;
|
|
286
|
+
const client = createWorkspaceConnectionRunsClient({
|
|
287
|
+
connection: { baseUrl: step.runsApiBaseUrl, protocol, structuredOutputs },
|
|
288
|
+
apiKey,
|
|
289
|
+
// An OpenAI-protocol provider sends its headers only when it is done, so
|
|
290
|
+
// the adapter's 750 s run signal bounds that call, not the guard.
|
|
291
|
+
fetchImpl:
|
|
292
|
+
protocol === "runs-api"
|
|
293
|
+
? createFetch()
|
|
294
|
+
: createFetch({ deadlineMs: 760_000 }),
|
|
295
|
+
modelSelection: step,
|
|
296
|
+
responseSchema: claim.revision?.outputSchema,
|
|
297
|
+
});
|
|
298
|
+
return customRunsClient(
|
|
299
|
+
client,
|
|
300
|
+
claim,
|
|
301
|
+
tools && {
|
|
302
|
+
serverUrl: tools.serverUrl,
|
|
303
|
+
authorization: tools.authorization,
|
|
304
|
+
allowedTools: tools.allowedTools,
|
|
305
|
+
}
|
|
306
|
+
);
|
|
307
|
+
}
|
|
213
308
|
if (!selection?.runsApiBaseUrl) return clientFactory({ apiKeyFile });
|
|
214
309
|
const model = compileEndpointModelSelection(selection);
|
|
215
310
|
if (!model || model === "invalid") throw new Error("runs_api_model_rejected");
|
|
@@ -251,27 +346,5 @@ export function createConfiguredRunsClient({
|
|
|
251
346
|
"x-sellable-agent-id": connection.agentId,
|
|
252
347
|
},
|
|
253
348
|
});
|
|
254
|
-
return
|
|
255
|
-
...client,
|
|
256
|
-
submit(compiled, options) {
|
|
257
|
-
// Public semantic endpoints have a published schema but no product tuple.
|
|
258
|
-
// Preserve that existing contract when calling a custom Runs service.
|
|
259
|
-
const schema = claim.revision?.outputSchema;
|
|
260
|
-
if (compiled.outputContract || !schema?.properties?.proposal)
|
|
261
|
-
return client.submit(compiled, options);
|
|
262
|
-
return client.submit(
|
|
263
|
-
{
|
|
264
|
-
...compiled,
|
|
265
|
-
outputContract: {
|
|
266
|
-
schemaVersion: "sellable-opener-output-contract/v1",
|
|
267
|
-
schema,
|
|
268
|
-
nativeProposalSchemaDigest: createHash("sha256")
|
|
269
|
-
.update(stable(schema.properties.proposal))
|
|
270
|
-
.digest("hex"),
|
|
271
|
-
},
|
|
272
|
-
},
|
|
273
|
-
options
|
|
274
|
-
);
|
|
275
|
-
},
|
|
276
|
-
});
|
|
349
|
+
return customRunsClient(client, claim);
|
|
277
350
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import { readFile } from "node:fs/promises";
|
|
3
2
|
import { pathToFileURL } from "node:url";
|
|
4
3
|
import {
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
runsApiConnectionServesEndpoint,
|
|
15
14
|
runsApiConnectionsForRuntime,
|
|
16
15
|
} from "./runs-api-connections.mjs";
|
|
16
|
+
import { probeRunsClient } from "./workspace-connection-client.mjs";
|
|
17
17
|
|
|
18
18
|
// Fixed read-only machine command. Callers supply identities, never a URL,
|
|
19
19
|
// credential path, shell command, or prompt. The installed registry authorizes
|
|
@@ -142,6 +142,10 @@ export async function verifyRunsApiSelection(
|
|
|
142
142
|
// the primary step's check the whole chain, so a machine whose compiler
|
|
143
143
|
// cannot run a chain refuses it here and no chain is saved for it.
|
|
144
144
|
const selection = endpointModelSelectionChain(compiled)[0] ?? null;
|
|
145
|
+
// A workspace connection's key is fetched per attempt by the run, so the
|
|
146
|
+
// machine holds none to probe with. This is a shape check only; the server
|
|
147
|
+
// performs the connectivity probe (228-05).
|
|
148
|
+
if (selection?.modelConnectionId) return result("REACHABLE");
|
|
145
149
|
let verificationWorkKind = "STANDARD";
|
|
146
150
|
if (selection?.runsApiBaseUrl) {
|
|
147
151
|
const connection = runsApiConnectionsForRuntime(
|
|
@@ -171,10 +175,9 @@ export async function verifyRunsApiSelection(
|
|
|
171
175
|
? "/run/sellable-agent/admin-runtime/api-server-key"
|
|
172
176
|
: `/run/sellable-agent/${request.profileId}/api-server-key`;
|
|
173
177
|
let client;
|
|
174
|
-
let run;
|
|
175
178
|
try {
|
|
176
179
|
client = selection?.runsApiBaseUrl
|
|
177
|
-
? makeConfiguredClient({
|
|
180
|
+
? await makeConfiguredClient({
|
|
178
181
|
apiKeyFile,
|
|
179
182
|
env,
|
|
180
183
|
claim: {
|
|
@@ -191,48 +194,14 @@ export async function verifyRunsApiSelection(
|
|
|
191
194
|
},
|
|
192
195
|
})
|
|
193
196
|
: makeDefaultClient({ apiKeyFile });
|
|
194
|
-
// A fresh token per check. Claude Opus 5.5 answers one fixed string
|
|
195
|
-
// ("SELLABLE_CONNECTION_OK") with nothing, so Claude Code fell back to
|
|
196
|
-
// another model and every Claude Code verification failed.
|
|
197
|
-
const token = `ready-${randomUUID().replaceAll("-", "").slice(0, 8)}`;
|
|
198
|
-
const compiled = {
|
|
199
|
-
input: `Connection verification. Reply with ${token}.`,
|
|
200
|
-
instructions: `This is a connection check. Do not use tools or take actions. Return exactly ${token} and nothing else.`,
|
|
201
|
-
conversationHistory: [],
|
|
202
|
-
correlation: `connection-check-${randomUUID()}`,
|
|
203
|
-
...(selection ? { modelSelection: selection } : {}),
|
|
204
|
-
};
|
|
205
|
-
const signal = AbortSignal.timeout(70_000);
|
|
206
|
-
// Default Hermes gets the tool-free verification prefix. A Runs service
|
|
207
|
-
// owns its own tool policy; the Claude and OpenAI adapters are tool-free.
|
|
208
|
-
run = await (
|
|
209
|
-
selection?.runsApiBaseUrl ? client.submit : client.submitVerification
|
|
210
|
-
)(compiled, { signal });
|
|
211
|
-
await client.streamEvents(run.runId, { signal, onEvent: async () => {} });
|
|
212
|
-
const status = await client.status(run.runId, { signal });
|
|
213
|
-
const served = status.servedRuntime;
|
|
214
|
-
if (
|
|
215
|
-
status.status !== "completed" ||
|
|
216
|
-
typeof status.output !== "string" ||
|
|
217
|
-
status.output.trim() !== token ||
|
|
218
|
-
!served
|
|
219
|
-
)
|
|
220
|
-
return result("UNAVAILABLE");
|
|
221
|
-
if (
|
|
222
|
-
selection &&
|
|
223
|
-
(served.provider !== selection.provider ||
|
|
224
|
-
(served.model !== selection.model &&
|
|
225
|
-
!served.model.startsWith(`${selection.model}-`)))
|
|
226
|
-
)
|
|
227
|
-
return result("UNAVAILABLE");
|
|
228
|
-
return result("READY", served);
|
|
229
197
|
} catch {
|
|
230
|
-
if (client && run)
|
|
231
|
-
await client
|
|
232
|
-
.stop(run.runId, { signal: AbortSignal.timeout(3_000) })
|
|
233
|
-
.catch(() => {});
|
|
234
198
|
return result("UNAVAILABLE");
|
|
235
199
|
}
|
|
200
|
+
const probe = await probeRunsClient(client, selection, {
|
|
201
|
+
signal: AbortSignal.timeout(70_000),
|
|
202
|
+
submitVerification: !selection?.runsApiBaseUrl,
|
|
203
|
+
});
|
|
204
|
+
return result(probe.state, probe.servedRuntime);
|
|
236
205
|
}
|
|
237
206
|
|
|
238
207
|
if (
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { EndpointModelStep } from "./endpoint-model-selection.mjs";
|
|
2
|
+
export type WorkspaceConnection = Readonly<{
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
protocol: "runs-api" | "openai-chat" | "openai-responses";
|
|
5
|
+
structuredOutputs?: boolean;
|
|
6
|
+
}>;
|
|
7
|
+
/** Every request goes through `fetchImpl`; the key is held in memory only. */
|
|
8
|
+
export function createWorkspaceConnectionRunsClient(options: {
|
|
9
|
+
connection: WorkspaceConnection;
|
|
10
|
+
apiKey: string;
|
|
11
|
+
fetchImpl: typeof fetch;
|
|
12
|
+
modelSelection: EndpointModelStep;
|
|
13
|
+
responseSchema?: unknown;
|
|
14
|
+
}): any;
|
|
15
|
+
export function probeRunsClient(
|
|
16
|
+
client: any,
|
|
17
|
+
selection: EndpointModelStep | null,
|
|
18
|
+
options?: { signal?: AbortSignal; submitVerification?: boolean }
|
|
19
|
+
): Promise<
|
|
20
|
+
| { state: "READY"; servedRuntime: { provider: string; model: string } }
|
|
21
|
+
| { state: "UNAVAILABLE" }
|
|
22
|
+
>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Builds the Runs client for a workspace's own model connection. The Next
|
|
2
|
+
// server and the agent runtime both import only this module for workspace
|
|
3
|
+
// connections, so it has no top-level code beyond imports and declarations.
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { createHermesRunsClient } from "./hermes-runs-client.mjs";
|
|
6
|
+
import { createOpenAiRunsClient } from "./openai-runs-client.mjs";
|
|
7
|
+
|
|
8
|
+
/** @param {any} options */
|
|
9
|
+
export function createWorkspaceConnectionRunsClient({
|
|
10
|
+
connection,
|
|
11
|
+
apiKey,
|
|
12
|
+
fetchImpl,
|
|
13
|
+
modelSelection,
|
|
14
|
+
responseSchema,
|
|
15
|
+
}) {
|
|
16
|
+
// The caller's fetchImpl is the address guard (createPinnedFetch). Without it
|
|
17
|
+
// both clients would fall back to the global fetch and dial unguarded.
|
|
18
|
+
if (typeof fetchImpl !== "function")
|
|
19
|
+
throw new Error("workspace_connection_fetch_required");
|
|
20
|
+
const { baseUrl, protocol, structuredOutputs } = connection;
|
|
21
|
+
// No registry entry and no scope headers: the key belongs to the workspace's
|
|
22
|
+
// connection, and every request goes through the caller's fetchImpl.
|
|
23
|
+
if (protocol === "runs-api")
|
|
24
|
+
return createHermesRunsClient({
|
|
25
|
+
baseUrl,
|
|
26
|
+
apiKey,
|
|
27
|
+
fetchImpl,
|
|
28
|
+
scopeHeaders: {},
|
|
29
|
+
});
|
|
30
|
+
if (protocol !== "openai-chat" && protocol !== "openai-responses")
|
|
31
|
+
throw new Error("workspace_connection_protocol_rejected");
|
|
32
|
+
const { provider, model, reasoningEffort } = modelSelection;
|
|
33
|
+
return createOpenAiRunsClient({
|
|
34
|
+
connection: {
|
|
35
|
+
baseUrl,
|
|
36
|
+
protocol,
|
|
37
|
+
structuredOutputs,
|
|
38
|
+
models: [{ provider, model, reasoningEfforts: [reasoningEffort] }],
|
|
39
|
+
},
|
|
40
|
+
apiKey,
|
|
41
|
+
fetchImpl,
|
|
42
|
+
modelSelection,
|
|
43
|
+
responseSchema,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// One ready-token probe for the machine verify and the server's connection
|
|
48
|
+
// check. It never reads a key: the caller hands it a built client.
|
|
49
|
+
/** @param {any} client @param {any} selection @param {any} [options] */
|
|
50
|
+
export async function probeRunsClient(
|
|
51
|
+
client,
|
|
52
|
+
selection,
|
|
53
|
+
{ signal, submitVerification = false } = {}
|
|
54
|
+
) {
|
|
55
|
+
let run;
|
|
56
|
+
try {
|
|
57
|
+
// A fresh token per check. Claude Opus 5.5 answers one fixed string
|
|
58
|
+
// ("SELLABLE_CONNECTION_OK") with nothing, so Claude Code fell back to
|
|
59
|
+
// another model and every Claude Code verification failed.
|
|
60
|
+
const token = `ready-${randomUUID().replaceAll("-", "").slice(0, 8)}`;
|
|
61
|
+
const compiled = {
|
|
62
|
+
input: `Connection verification. Reply with ${token}.`,
|
|
63
|
+
instructions: `This is a connection check. Do not use tools or take actions. Return exactly ${token} and nothing else.`,
|
|
64
|
+
conversationHistory: [],
|
|
65
|
+
correlation: `connection-check-${randomUUID()}`,
|
|
66
|
+
...(selection ? { modelSelection: selection } : {}),
|
|
67
|
+
};
|
|
68
|
+
// Default Hermes gets the tool-free verification prefix. A Runs service
|
|
69
|
+
// owns its own tool policy; the Claude and OpenAI adapters are tool-free.
|
|
70
|
+
run = await (
|
|
71
|
+
submitVerification ? client.submitVerification : client.submit
|
|
72
|
+
)(compiled, { signal });
|
|
73
|
+
await client.streamEvents(run.runId, { signal, onEvent: async () => {} });
|
|
74
|
+
const status = await client.status(run.runId, { signal });
|
|
75
|
+
const served = status.servedRuntime;
|
|
76
|
+
if (
|
|
77
|
+
status.status !== "completed" ||
|
|
78
|
+
typeof status.output !== "string" ||
|
|
79
|
+
status.output.trim() !== token ||
|
|
80
|
+
!served
|
|
81
|
+
)
|
|
82
|
+
return { state: "UNAVAILABLE" };
|
|
83
|
+
if (
|
|
84
|
+
selection &&
|
|
85
|
+
(served.provider !== selection.provider ||
|
|
86
|
+
(served.model !== selection.model &&
|
|
87
|
+
!served.model.startsWith(`${selection.model}-`)))
|
|
88
|
+
)
|
|
89
|
+
return { state: "UNAVAILABLE" };
|
|
90
|
+
return { state: "READY", servedRuntime: served };
|
|
91
|
+
} catch {
|
|
92
|
+
if (run)
|
|
93
|
+
await client
|
|
94
|
+
.stop(run.runId, { signal: AbortSignal.timeout(3_000) })
|
|
95
|
+
.catch(() => {});
|
|
96
|
+
return { state: "UNAVAILABLE" };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -1305,6 +1305,14 @@ export function createFlyCustomerControlClient({
|
|
|
1305
1305
|
{ replaySafe: true }
|
|
1306
1306
|
);
|
|
1307
1307
|
},
|
|
1308
|
+
async fetchEndpointConnectionKey(identityBody) {
|
|
1309
|
+
return post(
|
|
1310
|
+
"endpoint-connection-key",
|
|
1311
|
+
"/api/v3/sellable-agent/worker/endpoint-connection-key",
|
|
1312
|
+
identityBody,
|
|
1313
|
+
{ replaySafe: true }
|
|
1314
|
+
);
|
|
1315
|
+
},
|
|
1308
1316
|
async consumeSecret(identityBody) {
|
|
1309
1317
|
// The broker makes only this verb replay-safe for the exact claim ID.
|
|
1310
1318
|
return post(
|
|
@@ -38,7 +38,7 @@ import { installAgentHostServices } from "./service-installer.mjs";
|
|
|
38
38
|
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
39
39
|
const VERSION = "sellable-agent-host-bootstrap/v1";
|
|
40
40
|
const RECEIPT_VERSION = "sellable-agent-host-registration/v1";
|
|
41
|
-
const INSTALLER_PACKAGE = "@sellable/install@0.1.
|
|
41
|
+
const INSTALLER_PACKAGE = "@sellable/install@0.1.804";
|
|
42
42
|
const MCP_PACKAGE = "@sellable/mcp@0.1.957";
|
|
43
43
|
const HERMES_VERSION = "0.18.0";
|
|
44
44
|
const SHA256 = /^[a-f0-9]{64}$/;
|
|
@@ -1546,7 +1546,7 @@ export function compileClaimToProfileDesired(activeClaim, config) {
|
|
|
1546
1546
|
]) ||
|
|
1547
1547
|
pinned.hermesCli !== "hermes" ||
|
|
1548
1548
|
pinned.hermesVersion !== "0.18.0" ||
|
|
1549
|
-
pinned.installerPackage !== "@sellable/install@0.1.
|
|
1549
|
+
pinned.installerPackage !== "@sellable/install@0.1.804" ||
|
|
1550
1550
|
pinned.mcpPackage !== "@sellable/mcp@0.1.957" ||
|
|
1551
1551
|
!Array.isArray(policy.toolInclude) ||
|
|
1552
1552
|
policy.toolInclude.length === 0 ||
|
|
@@ -312,7 +312,7 @@ function validateDesired(desired) {
|
|
|
312
312
|
desired.serviceCredentialGeneration < 1 ||
|
|
313
313
|
desired.hermesCli !== "hermes" ||
|
|
314
314
|
desired.hermesVersion !== "0.18.0" ||
|
|
315
|
-
desired.installerPackage !== "@sellable/install@0.1.
|
|
315
|
+
desired.installerPackage !== "@sellable/install@0.1.804" ||
|
|
316
316
|
desired.mcpPackage !== "@sellable/mcp@0.1.957" ||
|
|
317
317
|
!Array.isArray(desired.toolInclude) ||
|
|
318
318
|
desired.toolInclude.length === 0 ||
|
|
@@ -25,7 +25,7 @@ import { fileURLToPath } from "node:url";
|
|
|
25
25
|
import { deriveContainedProfileId } from "./profile-materializer.mjs";
|
|
26
26
|
|
|
27
27
|
export const PROVISIONING_ACTION = "PROVISION_HERMES_PROFILE";
|
|
28
|
-
export const PINNED_INSTALL_PACKAGE = "@sellable/install@0.1.
|
|
28
|
+
export const PINNED_INSTALL_PACKAGE = "@sellable/install@0.1.804";
|
|
29
29
|
export const PINNED_MCP_PACKAGE = "@sellable/mcp@0.1.957";
|
|
30
30
|
const PINNED_INSTALL_VERSION = PINNED_INSTALL_PACKAGE.slice(
|
|
31
31
|
PINNED_INSTALL_PACKAGE.lastIndexOf("@") + 1
|