@sellable/install 0.1.584 → 0.1.586
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 +2 -2
- package/lib/sellable-agent/fly-admin-image/Dockerfile +19 -0
- package/lib/sellable-agent/fly-admin-image/admin-runtime.mjs +63 -8
- package/lib/sellable-agent/fly-customer-image/Dockerfile +1 -1
- package/lib/sellable-agent/fly-customer-image/customer-runtime.mjs +1 -1
- 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 +23 -5
- package/lib/sellable-agent/provisioning-adapter.mjs +4 -4
- package/package.json +1 -1
package/container/Dockerfile
CHANGED
|
@@ -3,12 +3,12 @@ FROM ${HERMES_IMAGE}
|
|
|
3
3
|
|
|
4
4
|
USER root
|
|
5
5
|
|
|
6
|
-
ARG INSTALLER_PACKAGE=@sellable/install@0.1.
|
|
6
|
+
ARG INSTALLER_PACKAGE=@sellable/install@0.1.586
|
|
7
7
|
ARG MCP_PACKAGE=@sellable/mcp@0.1.860
|
|
8
8
|
ARG INSTALLER_INTEGRITY
|
|
9
9
|
ARG MCP_INTEGRITY=sha512-jRA1KsCV2d4Zcuo5/UmJiP8P0NaoC3ZDvUFRQOc2AMSNDVmUR6gWvtkyAiqb1lukbFWKzfVlz2/4EWzxvb7hkQ==
|
|
10
10
|
|
|
11
|
-
RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.
|
|
11
|
+
RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.586" \
|
|
12
12
|
&& test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.860" \
|
|
13
13
|
&& test -n "${INSTALLER_INTEGRITY}" \
|
|
14
14
|
&& test "$(npm view "${INSTALLER_PACKAGE}" dist.integrity)" = "${INSTALLER_INTEGRITY}" \
|
|
@@ -23,9 +23,9 @@ RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.582" \
|
|
|
23
23
|
&& mkdir -p /opt/sellable-agent/install-root /opt/sellable-agent/mcp-root \
|
|
24
24
|
&& npm install --prefix /opt/sellable-agent/install-root --omit=dev --ignore-scripts --no-audit --no-fund "${INSTALLER_PACKAGE}" \
|
|
25
25
|
&& npm install --prefix /opt/sellable-agent/mcp-root --omit=dev --ignore-scripts --no-audit --no-fund "${MCP_PACKAGE}" \
|
|
26
|
-
&& node --input-type=module -e "import { readFileSync } from 'node:fs'; const install = JSON.parse(readFileSync('/opt/sellable-agent/install-root/node_modules/@sellable/install/package.json')); const mcp = JSON.parse(readFileSync('/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp/package.json')); if (install.name !== '@sellable/install' || install.version !== '0.1.
|
|
26
|
+
&& node --input-type=module -e "import { readFileSync } from 'node:fs'; const install = JSON.parse(readFileSync('/opt/sellable-agent/install-root/node_modules/@sellable/install/package.json')); const mcp = JSON.parse(readFileSync('/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp/package.json')); if (install.name !== '@sellable/install' || install.version !== '0.1.586' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.860') throw new Error('package identity rejected');" \
|
|
27
27
|
&& node --input-type=module -e "import { buildExternalRuntimeClosure } from '/opt/sellable-agent/install-root/node_modules/@sellable/install/lib/sellable-agent/external-runtime-builder.mjs'; const built = buildExternalRuntimeClosure({ mcpPackageRoot: '/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp', mcpNodeModulesRoot: '/opt/sellable-agent/mcp-root/node_modules', hermesSourceRoot: '/opt/hermes', ownerUid: 0, ownerGid: 0 }); if (!built.closureDigest) throw new Error('runtime closure rejected');" \
|
|
28
|
-
&& node --input-type=module -e "import { chmodSync, writeFileSync } from 'node:fs'; const release = { installerPackage: '@sellable/install@0.1.
|
|
28
|
+
&& node --input-type=module -e "import { chmodSync, writeFileSync } from 'node:fs'; const release = { installerPackage: '@sellable/install@0.1.586', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.860', mcpIntegrity: process.argv[2] }; writeFileSync('/opt/sellable-agent/release.json', JSON.stringify(release) + '\\n', { mode: 0o444 }); chmodSync('/opt/sellable-agent/release.json', 0o444);" "${INSTALLER_INTEGRITY}" "${MCP_INTEGRITY}" \
|
|
29
29
|
&& npm cache clean --force
|
|
30
30
|
|
|
31
31
|
COPY entrypoint.sh /usr/local/bin/sellable-agent-container-entrypoint
|
package/container/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
This image is a dedicated Agent worker/runtime boundary beside an existing Hermes dashboard. It never replaces or reconfigures the dashboard container.
|
|
4
4
|
|
|
5
5
|
Build from this directory after
|
|
6
|
-
`@sellable/install@0.1.
|
|
6
|
+
`@sellable/install@0.1.586` is
|
|
7
7
|
published:
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
10
|
docker build --platform linux/amd64 \
|
|
11
11
|
--build-arg INSTALLER_INTEGRITY='sha512-…' \
|
|
12
|
-
--tag sellable-agent-host:0.1.
|
|
12
|
+
--tag sellable-agent-host:0.1.586 .
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Create a private `bootstrap/` directory owned by root with mode `0700`. It must contain `bootstrap.json`, `provider-auth`, and `slack-app`, each owned by root with mode `0600`. `bootstrap.json` contains only non-secret identities, hashes, package integrities, and the control-plane URL. The other two files contain the provider JSON and global Slack app token whose hashes are pinned by `bootstrap.json`.
|
|
@@ -15,6 +15,7 @@ ARG ADMIN_LOCKED_TREE_DIGEST
|
|
|
15
15
|
ARG ADMIN_ARTIFACT_DIGEST
|
|
16
16
|
ARG ADMIN_PACKAGE_LOCK_B64
|
|
17
17
|
ARG ADMIN_PROFILE_CONTRACT_TEMPLATE_B64
|
|
18
|
+
ARG MCP_TRUST_ROOT_FINGERPRINT
|
|
18
19
|
ARG TUS_JS_CLIENT_VERSION=4.3.1
|
|
19
20
|
ARG STRIPE_CLI_PACKAGE=@stripe/cli-linux-x64@1.45.0
|
|
20
21
|
ARG STRIPE_CLI_INTEGRITY=sha512-1ZhoPpoweYfynqsvhCLlTjZ7lPz5IKtxqAMT5MBy6zrwLRTP9x0T6r8h/jLYL8lRH1c7zC/6X6/XUu2V+r9Bog==
|
|
@@ -76,8 +77,22 @@ RUN set -eux; \
|
|
|
76
77
|
/etc/cont-init.d/02-reconcile-profiles; \
|
|
77
78
|
npm cache clean --force
|
|
78
79
|
|
|
80
|
+
# The MCP turn trust root is the same build secret the customer image bakes.
|
|
81
|
+
# The Admin runtime hands the Product MCP context proxy this exact file plus
|
|
82
|
+
# its fingerprint, so the baked bytes must match the pinned signing contract.
|
|
83
|
+
RUN --mount=type=secret,id=mcp_trust_root,required=true \
|
|
84
|
+
set -eux; \
|
|
85
|
+
test -s /run/secrets/mcp_trust_root; \
|
|
86
|
+
test -n "${MCP_TRUST_ROOT_FINGERPRINT}"; \
|
|
87
|
+
install -d -m 0755 /usr/local/share/sellable-agent; \
|
|
88
|
+
install -o root -g root -m 0444 /run/secrets/mcp_trust_root \
|
|
89
|
+
/usr/local/share/sellable-agent/mcp-turn-trust-root.pem; \
|
|
90
|
+
test "$(sha256sum /usr/local/share/sellable-agent/mcp-turn-trust-root.pem | cut -d ' ' -f 1)" = "${MCP_TRUST_ROOT_FINGERPRINT}"
|
|
91
|
+
|
|
79
92
|
COPY fly-admin-image/admin-runtime.mjs /usr/local/lib/sellable-agent/admin-runtime/admin-runtime.mjs
|
|
80
93
|
COPY fly-admin-image/start-admin-runtime /usr/local/lib/sellable-agent/admin-runtime/start-admin-runtime
|
|
94
|
+
COPY mcp-context-proxy.mjs /usr/local/lib/sellable-agent/mcp-context-proxy.mjs
|
|
95
|
+
COPY mcp-runtime-binding.mjs /usr/local/lib/sellable-agent/mcp-runtime-binding.mjs
|
|
81
96
|
COPY fly-runtime-identity.mjs /usr/local/lib/sellable-agent/fly-runtime-identity.mjs
|
|
82
97
|
COPY model-auth-reconciler.mjs /usr/local/lib/sellable-agent/model-auth-reconciler.mjs
|
|
83
98
|
COPY model-auth-canary-reseed.mjs /usr/local/lib/sellable-agent/model-auth-canary-reseed.mjs
|
|
@@ -98,6 +113,8 @@ RUN node --input-type=module -e \
|
|
|
98
113
|
'import { installHermesAgentBridge, HERMES_AGENT_BRIDGE_DEDICATED_V020_CONTRACT } from "/usr/local/lib/sellable-agent/hermes-bridge.mjs"; installHermesAgentBridge({ sourceRoot: "/opt/hermes", contract: HERMES_AGENT_BRIDGE_DEDICATED_V020_CONTRACT });' \
|
|
99
114
|
&& node --input-type=module -e \
|
|
100
115
|
'await import("/usr/local/lib/sellable-agent/fly-runtime-identity.mjs");' \
|
|
116
|
+
&& node --input-type=module -e \
|
|
117
|
+
'await import("/usr/local/lib/sellable-agent/mcp-context-proxy.mjs");' \
|
|
101
118
|
&& install -d -m 0755 /usr/local/share/sellable-agent \
|
|
102
119
|
&& printf '%s\n' \
|
|
103
120
|
'#!/usr/bin/env node' \
|
|
@@ -125,6 +142,8 @@ RUN node --input-type=module -e \
|
|
|
125
142
|
&& chmod 0555 \
|
|
126
143
|
/usr/local/lib/sellable-agent/admin-runtime/admin-runtime.mjs \
|
|
127
144
|
/usr/local/lib/sellable-agent/admin-runtime/start-admin-runtime \
|
|
145
|
+
/usr/local/lib/sellable-agent/mcp-context-proxy.mjs \
|
|
146
|
+
/usr/local/lib/sellable-agent/mcp-runtime-binding.mjs \
|
|
128
147
|
/usr/local/lib/sellable-agent/fly-runtime-identity.mjs \
|
|
129
148
|
/usr/local/lib/sellable-agent/model-auth-reconciler.mjs \
|
|
130
149
|
/usr/local/lib/sellable-agent/model-auth-canary-reseed.mjs \
|
|
@@ -102,9 +102,19 @@ const PROFILES_ROOT = join(DATA_ROOT, "profiles");
|
|
|
102
102
|
const RUNTIME_ROOT = join(DATA_ROOT, ".sellable-agent", "admin-runtime");
|
|
103
103
|
const DELIVERY_ROOT = join(RUNTIME_ROOT, "delivery");
|
|
104
104
|
const SECRET_ROOT = "/run/sellable-agent/admin-runtime";
|
|
105
|
+
// Turn descriptor + consumed roots for the Product MCP context proxy. No
|
|
106
|
+
// descriptor is ever installed on the Slack-only Admin runtime today, but the
|
|
107
|
+
// proxy requires both private roots to exist at startup or it fails closed.
|
|
108
|
+
const MCP_TURN_CONTEXT_ROOT = join(SECRET_ROOT, "mcp-turn-context");
|
|
105
109
|
const HERMES = "/opt/hermes/.venv/bin/hermes";
|
|
106
110
|
const HERMES_PYTHON = "/opt/hermes/.venv/bin/python";
|
|
107
111
|
const NODE = "/usr/local/bin/node";
|
|
112
|
+
// The Product MCP runs behind the same context proxy the customer runtime
|
|
113
|
+
// uses, from the same stable image path. The Admin MCP stays a direct dist
|
|
114
|
+
// entrypoint — two distinct servers on one profile.
|
|
115
|
+
const MCP_CONTEXT_PROXY = "/usr/local/lib/sellable-agent/mcp-context-proxy.mjs";
|
|
116
|
+
const MCP_TURN_TRUST_ROOT =
|
|
117
|
+
"/usr/local/share/sellable-agent/mcp-turn-trust-root.pem";
|
|
108
118
|
const ADMIN_INSTALL_PACKAGE_ROOT = join(
|
|
109
119
|
ARTIFACT_ROOT,
|
|
110
120
|
"node_modules",
|
|
@@ -561,6 +571,48 @@ function exactSoul(claim) {
|
|
|
561
571
|
return { bytes: soul, sha256: sha256(soul), byteLength: soul.byteLength };
|
|
562
572
|
}
|
|
563
573
|
|
|
574
|
+
// The context proxy fails closed at startup unless its descriptor roots
|
|
575
|
+
// exist as private directories, its trust root file matches the fingerprint
|
|
576
|
+
// it is handed, and its downstream command is absolute. The materializer owns
|
|
577
|
+
// every one of those inputs so the `sellable` server can never enter a
|
|
578
|
+
// fail-closed respawn loop from missing environment.
|
|
579
|
+
function productMcpContextProxyEnvironment(layout) {
|
|
580
|
+
let trustRootPem;
|
|
581
|
+
try {
|
|
582
|
+
const entry = lstatSync(MCP_TURN_TRUST_ROOT);
|
|
583
|
+
if (
|
|
584
|
+
entry.isSymbolicLink() ||
|
|
585
|
+
!entry.isFile() ||
|
|
586
|
+
(entry.mode & 0o022) !== 0
|
|
587
|
+
) {
|
|
588
|
+
throw new Error("admin_runtime_trust_root_rejected");
|
|
589
|
+
}
|
|
590
|
+
trustRootPem = readFileSync(MCP_TURN_TRUST_ROOT, "utf8");
|
|
591
|
+
} catch {
|
|
592
|
+
throw new Error("admin_runtime_trust_root_rejected");
|
|
593
|
+
}
|
|
594
|
+
privateDirectory(MCP_TURN_CONTEXT_ROOT);
|
|
595
|
+
privateDirectory(join(MCP_TURN_CONTEXT_ROOT, "consumed"));
|
|
596
|
+
return {
|
|
597
|
+
SELLABLE_AGENT_TURN_DESCRIPTOR_PATH: join(
|
|
598
|
+
MCP_TURN_CONTEXT_ROOT,
|
|
599
|
+
"turn-context.json"
|
|
600
|
+
),
|
|
601
|
+
SELLABLE_AGENT_TURN_CONSUMED_ROOT: join(MCP_TURN_CONTEXT_ROOT, "consumed"),
|
|
602
|
+
SELLABLE_AGENT_MCP_RUNTIME_BINDING_PATH: join(
|
|
603
|
+
layout.profileHome,
|
|
604
|
+
"sellable",
|
|
605
|
+
"runtime-binding.json"
|
|
606
|
+
),
|
|
607
|
+
SELLABLE_AGENT_MCP_TRUST_ROOT_PATH: MCP_TURN_TRUST_ROOT,
|
|
608
|
+
SELLABLE_AGENT_MCP_TRUST_ROOT_FINGERPRINT: sha256(trustRootPem),
|
|
609
|
+
SELLABLE_AGENT_MCP_DOWNSTREAM_COMMAND: NODE,
|
|
610
|
+
SELLABLE_AGENT_MCP_DOWNSTREAM_ARGS_JSON: JSON.stringify([
|
|
611
|
+
`${ARTIFACT_ROOT}/node_modules/@sellable/mcp/dist/index.js`,
|
|
612
|
+
]),
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
|
|
564
616
|
function profilePackageReceipt(
|
|
565
617
|
profileContract,
|
|
566
618
|
alias,
|
|
@@ -569,21 +621,24 @@ function profilePackageReceipt(
|
|
|
569
621
|
agentServiceEnv = {}
|
|
570
622
|
) {
|
|
571
623
|
const entry = profileContract.packages[alias][role];
|
|
572
|
-
const packageName = entry.name;
|
|
573
|
-
const entrypoint =
|
|
574
|
-
alias === "sellable"
|
|
575
|
-
? `${ARTIFACT_ROOT}/node_modules/@sellable/mcp/dist/index.js`
|
|
576
|
-
: `${ARTIFACT_ROOT}/node_modules/@sellable/admin-mcp/dist/index.js`;
|
|
577
624
|
return {
|
|
578
625
|
...entry,
|
|
579
626
|
command: "/usr/local/bin/node",
|
|
580
|
-
args:
|
|
627
|
+
args:
|
|
628
|
+
alias === "sellable"
|
|
629
|
+
? [MCP_CONTEXT_PROXY]
|
|
630
|
+
: [`${ARTIFACT_ROOT}/node_modules/@sellable/admin-mcp/dist/index.js`],
|
|
581
631
|
// The Admin MCP resolves its packaged gateway scripts through
|
|
582
632
|
// SELLABLE_ADMIN_ROOT and its CLI shell-outs through PATH, so the server
|
|
583
633
|
// entry carries them instead of relying on gateway inheritance.
|
|
584
634
|
...(alias === "sellable-admin" ? { env: adminToolEnv(layout) } : {}),
|
|
585
|
-
...(alias === "sellable"
|
|
586
|
-
? {
|
|
635
|
+
...(alias === "sellable"
|
|
636
|
+
? {
|
|
637
|
+
env: {
|
|
638
|
+
...agentServiceEnv,
|
|
639
|
+
...productMcpContextProxyEnvironment(layout),
|
|
640
|
+
},
|
|
641
|
+
}
|
|
587
642
|
: {}),
|
|
588
643
|
};
|
|
589
644
|
}
|
|
@@ -6,7 +6,7 @@ USER root
|
|
|
6
6
|
|
|
7
7
|
ARG MCP_PACKAGE=@sellable/mcp@0.1.860
|
|
8
8
|
ARG MCP_INTEGRITY=sha512-jRA1KsCV2d4Zcuo5/UmJiP8P0NaoC3ZDvUFRQOc2AMSNDVmUR6gWvtkyAiqb1lukbFWKzfVlz2/4EWzxvb7hkQ==
|
|
9
|
-
ARG INSTALLER_PACKAGE=@sellable/install@0.1.
|
|
9
|
+
ARG INSTALLER_PACKAGE=@sellable/install@0.1.586
|
|
10
10
|
ARG TUS_JS_CLIENT_VERSION=4.3.1
|
|
11
11
|
ARG HERMES_VERSION=0.20.0
|
|
12
12
|
ARG TIRITH_VERSION=0.3.3
|
|
@@ -93,7 +93,7 @@ const RUNTIME_GENERATION = Number(
|
|
|
93
93
|
const BOOT_SESSION_ID = randomUUID();
|
|
94
94
|
const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.20.0";
|
|
95
95
|
const INSTALLER_PACKAGE =
|
|
96
|
-
process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.
|
|
96
|
+
process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.586";
|
|
97
97
|
const MCP_PACKAGE =
|
|
98
98
|
process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.860";
|
|
99
99
|
|
|
@@ -39,7 +39,7 @@ 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
41
|
const INSTALLER_PACKAGE =
|
|
42
|
-
"@sellable/install@0.1.
|
|
42
|
+
"@sellable/install@0.1.586";
|
|
43
43
|
const MCP_PACKAGE = "@sellable/mcp@0.1.860";
|
|
44
44
|
const HERMES_VERSION = "0.18.0";
|
|
45
45
|
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.586" ||
|
|
1550
1550
|
pinned.mcpPackage !== "@sellable/mcp@0.1.860" ||
|
|
1551
1551
|
!Array.isArray(policy.toolInclude) ||
|
|
1552
1552
|
policy.toolInclude.length === 0 ||
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
relative,
|
|
24
24
|
resolve,
|
|
25
25
|
} from "node:path";
|
|
26
|
+
import { parseDocument } from "yaml";
|
|
26
27
|
import {
|
|
27
28
|
FLY_CUSTOMER_MODEL_ID,
|
|
28
29
|
FLY_CUSTOMER_MODEL_PROVIDER,
|
|
@@ -201,7 +202,7 @@ function validateDesired(desired) {
|
|
|
201
202
|
desired.serviceCredentialGeneration < 1 ||
|
|
202
203
|
desired.hermesCli !== "hermes" ||
|
|
203
204
|
desired.hermesVersion !== "0.18.0" ||
|
|
204
|
-
desired.installerPackage !== "@sellable/install@0.1.
|
|
205
|
+
desired.installerPackage !== "@sellable/install@0.1.586" ||
|
|
205
206
|
desired.mcpPackage !== "@sellable/mcp@0.1.860" ||
|
|
206
207
|
!Array.isArray(desired.toolInclude) ||
|
|
207
208
|
desired.toolInclude.length === 0 ||
|
|
@@ -424,8 +425,22 @@ function profileConfigWithoutLiveSkills(value) {
|
|
|
424
425
|
return normalized;
|
|
425
426
|
}
|
|
426
427
|
|
|
428
|
+
function readProfileConfig(pathValue) {
|
|
429
|
+
const document = parseDocument(readFileSync(pathValue, "utf8"));
|
|
430
|
+
const value = document.toJS();
|
|
431
|
+
if (
|
|
432
|
+
document.errors.length > 0 ||
|
|
433
|
+
!value ||
|
|
434
|
+
typeof value !== "object" ||
|
|
435
|
+
Array.isArray(value)
|
|
436
|
+
) {
|
|
437
|
+
throw new Error("profile config rejected");
|
|
438
|
+
}
|
|
439
|
+
return value;
|
|
440
|
+
}
|
|
441
|
+
|
|
427
442
|
function normalizedProfileConfigBytes(pathValue) {
|
|
428
|
-
const value =
|
|
443
|
+
const value = readProfileConfig(pathValue);
|
|
429
444
|
return Buffer.from(
|
|
430
445
|
`${JSON.stringify(profileConfigWithoutLiveSkills(value), null, 2)}\n`,
|
|
431
446
|
"utf8"
|
|
@@ -436,8 +451,11 @@ function mergeLiveSkillsConfig(sourceRoot, targetRoot) {
|
|
|
436
451
|
const sourcePath = join(sourceRoot, "config.yaml");
|
|
437
452
|
const targetPath = join(targetRoot, "config.yaml");
|
|
438
453
|
if (!existsSync(sourcePath) || !existsSync(targetPath)) return;
|
|
439
|
-
|
|
440
|
-
|
|
454
|
+
// Hermes owns this live file and normalizes it from the seed JSON into
|
|
455
|
+
// YAML. Parse both representations so a routine image refresh does not
|
|
456
|
+
// strand a healthy customer runtime before it can acknowledge its secrets.
|
|
457
|
+
const source = readProfileConfig(sourcePath);
|
|
458
|
+
const target = readProfileConfig(targetPath);
|
|
441
459
|
const sourceSkills = source?.skills;
|
|
442
460
|
if (
|
|
443
461
|
!sourceSkills ||
|
|
@@ -500,7 +518,7 @@ function preservedSkillsConfigIdentity(profileRoot) {
|
|
|
500
518
|
const configPath = join(profileRoot, "config.yaml");
|
|
501
519
|
let disabled = {};
|
|
502
520
|
if (existsSync(configPath)) {
|
|
503
|
-
const config =
|
|
521
|
+
const config = readProfileConfig(configPath);
|
|
504
522
|
const skills = config?.skills;
|
|
505
523
|
if (skills && typeof skills === "object" && !Array.isArray(skills)) {
|
|
506
524
|
disabled = Object.fromEntries(
|
|
@@ -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.586";
|
|
29
29
|
export const PINNED_MCP_PACKAGE = "@sellable/mcp@0.1.860";
|
|
30
30
|
|
|
31
31
|
export function deriveAgentProfileId(workspaceId, agentId, hostId) {
|
|
@@ -611,7 +611,7 @@ function inspectProvisionedProfile({
|
|
|
611
611
|
!matchesReadback(manifest, request) ||
|
|
612
612
|
manifest.serviceCredentialReference !== serviceCredentialReference ||
|
|
613
613
|
manifest.installerPackage !== PINNED_INSTALL_PACKAGE ||
|
|
614
|
-
manifest.installerVersion !== "0.1.
|
|
614
|
+
manifest.installerVersion !== "0.1.586" ||
|
|
615
615
|
manifest.mcpPackage !== PINNED_MCP_PACKAGE ||
|
|
616
616
|
manifest.credentialKeyVersion !== credentialKeyVersion ||
|
|
617
617
|
!/^[a-f0-9]{16}$/.test(manifest.credentialFingerprint) ||
|
|
@@ -825,7 +825,7 @@ function successReceipt({
|
|
|
825
825
|
subject: `agent-profile:${observed.profileId}`,
|
|
826
826
|
cli: {
|
|
827
827
|
installPackage: PINNED_INSTALL_PACKAGE,
|
|
828
|
-
installVersion: "0.1.
|
|
828
|
+
installVersion: "0.1.586",
|
|
829
829
|
mcpPackage: PINNED_MCP_PACKAGE,
|
|
830
830
|
command: "hermes profile bootstrap",
|
|
831
831
|
},
|
|
@@ -873,7 +873,7 @@ function failure(code, stages, extra = {}, request = null) {
|
|
|
873
873
|
: "agent-profile:unbound",
|
|
874
874
|
cli: {
|
|
875
875
|
installPackage: PINNED_INSTALL_PACKAGE,
|
|
876
|
-
installVersion: "0.1.
|
|
876
|
+
installVersion: "0.1.586",
|
|
877
877
|
mcpPackage: PINNED_MCP_PACKAGE,
|
|
878
878
|
command: "hermes profile bootstrap",
|
|
879
879
|
},
|