@sellable/install 0.1.652 → 0.1.654-wip.phase189.20260814.2
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 +1 -0
- package/lib/sellable-agent/fly-admin-image/admin-runtime-phase-telemetry.mjs +80 -0
- package/lib/sellable-agent/fly-admin-image/admin-runtime.mjs +284 -229
- package/lib/sellable-agent/fly-customer-image/Dockerfile +2 -1
- package/lib/sellable-agent/fly-customer-image/customer-runtime.mjs +15 -1
- package/lib/sellable-agent/hermes-memory-snapshot.mjs +4 -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 +1 -1
- package/lib/sellable-agent/provisioning-adapter.mjs +1 -1
- 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.654-wip.phase189.20260814.2
|
|
7
7
|
ARG MCP_PACKAGE=@sellable/mcp@0.1.880
|
|
8
8
|
ARG INSTALLER_INTEGRITY
|
|
9
9
|
ARG MCP_INTEGRITY=sha512-+Fo8aQlYduLaQMQff+ZA25LeUhWZ7I7UH5DECpND84LQ+rHSjKeKFj4Zs93bVHXwQCIy2OLbr75y4f4+CyT57w==
|
|
10
10
|
|
|
11
|
-
RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.
|
|
11
|
+
RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.654-wip.phase189.20260814.2" \
|
|
12
12
|
&& test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.880" \
|
|
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.652" \
|
|
|
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.654-wip.phase189.20260814.2' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.880') 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.654-wip.phase189.20260814.2', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.880', 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,7 +3,7 @@
|
|
|
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.654-wip.phase189.20260814.2` is
|
|
7
7
|
published:
|
|
8
8
|
|
|
9
9
|
```sh
|
|
@@ -148,6 +148,7 @@ RUN --mount=type=secret,id=mcp_trust_root,required=true \
|
|
|
148
148
|
test "$(sha256sum /usr/local/share/sellable-agent/mcp-turn-trust-root.pem | cut -d ' ' -f 1)" = "${MCP_TRUST_ROOT_FINGERPRINT}"
|
|
149
149
|
|
|
150
150
|
COPY fly-admin-image/admin-runtime.mjs /usr/local/lib/sellable-agent/admin-runtime/admin-runtime.mjs
|
|
151
|
+
COPY fly-admin-image/admin-runtime-phase-telemetry.mjs /usr/local/lib/sellable-agent/admin-runtime/admin-runtime-phase-telemetry.mjs
|
|
151
152
|
COPY fly-admin-image/admin-state-generation.mjs /usr/local/lib/sellable-agent/admin-runtime/admin-state-generation.mjs
|
|
152
153
|
COPY fly-admin-image/start-admin-runtime /usr/local/lib/sellable-agent/admin-runtime/start-admin-runtime
|
|
153
154
|
COPY admin-native-gateway-supervisor.mjs /usr/local/lib/sellable-agent/admin-native-gateway-supervisor.mjs
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const ADMIN_RUNTIME_PHASES = new Set([
|
|
2
|
+
"runtime_secrets",
|
|
3
|
+
"snapshot_restore",
|
|
4
|
+
"profile_settings_delivery",
|
|
5
|
+
"profile_stage",
|
|
6
|
+
"profile_live_merge_promote",
|
|
7
|
+
"profile_crons",
|
|
8
|
+
"default_profile_bundle",
|
|
9
|
+
"memory_snapshot",
|
|
10
|
+
"slack_serving_proof",
|
|
11
|
+
"native_gateway",
|
|
12
|
+
"serving_observation",
|
|
13
|
+
"operation_completion",
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
function phaseFailureCode(error) {
|
|
17
|
+
const code = error instanceof Error ? error.message : "";
|
|
18
|
+
return /^[A-Za-z0-9_:-]{1,160}$/.test(code)
|
|
19
|
+
? code
|
|
20
|
+
: "admin_runtime_phase_failed";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function createAdminRuntimePhaseTelemetry({
|
|
24
|
+
bootSessionId,
|
|
25
|
+
operationId,
|
|
26
|
+
now = () => Date.now(),
|
|
27
|
+
write = (entry) => process.stderr.write(`${JSON.stringify(entry)}\n`),
|
|
28
|
+
}) {
|
|
29
|
+
if (
|
|
30
|
+
typeof bootSessionId !== "string" ||
|
|
31
|
+
bootSessionId.length < 1 ||
|
|
32
|
+
typeof operationId !== "string" ||
|
|
33
|
+
operationId.length < 1
|
|
34
|
+
) {
|
|
35
|
+
throw new Error("admin_runtime_phase_identity_rejected");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const run = async (phase, work) => {
|
|
39
|
+
if (!ADMIN_RUNTIME_PHASES.has(phase) || typeof work !== "function") {
|
|
40
|
+
throw new Error("admin_runtime_phase_rejected");
|
|
41
|
+
}
|
|
42
|
+
const startedAt = now();
|
|
43
|
+
write({
|
|
44
|
+
ok: true,
|
|
45
|
+
code: "admin_runtime_phase",
|
|
46
|
+
phase,
|
|
47
|
+
status: "started",
|
|
48
|
+
elapsedMs: 0,
|
|
49
|
+
bootSessionId,
|
|
50
|
+
operationId,
|
|
51
|
+
});
|
|
52
|
+
try {
|
|
53
|
+
const result = await work();
|
|
54
|
+
write({
|
|
55
|
+
ok: true,
|
|
56
|
+
code: "admin_runtime_phase",
|
|
57
|
+
phase,
|
|
58
|
+
status: "completed",
|
|
59
|
+
elapsedMs: Math.max(0, now() - startedAt),
|
|
60
|
+
bootSessionId,
|
|
61
|
+
operationId,
|
|
62
|
+
});
|
|
63
|
+
return result;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
write({
|
|
66
|
+
ok: false,
|
|
67
|
+
code: "admin_runtime_phase",
|
|
68
|
+
phase,
|
|
69
|
+
status: "failed",
|
|
70
|
+
elapsedMs: Math.max(0, now() - startedAt),
|
|
71
|
+
bootSessionId,
|
|
72
|
+
operationId,
|
|
73
|
+
errorCode: phaseFailureCode(error),
|
|
74
|
+
});
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return { run };
|
|
80
|
+
}
|
|
@@ -103,6 +103,7 @@ import {
|
|
|
103
103
|
reconcileHermesModelAuth,
|
|
104
104
|
} from "../model-auth-reconciler.mjs";
|
|
105
105
|
import { createModelHealthReporter } from "../model-health-reporter.mjs";
|
|
106
|
+
import { createAdminRuntimePhaseTelemetry } from "./admin-runtime-phase-telemetry.mjs";
|
|
106
107
|
import {
|
|
107
108
|
completeAdminStateReceiptRecovery,
|
|
108
109
|
prepareAdminStateGeneration,
|
|
@@ -1004,6 +1005,7 @@ async function materializeAdminProfile({
|
|
|
1004
1005
|
soul,
|
|
1005
1006
|
slack = null,
|
|
1006
1007
|
agentServiceEnv = {},
|
|
1008
|
+
runPhase = async (_phase, work) => work(),
|
|
1007
1009
|
}) {
|
|
1008
1010
|
const profileHome = profileContract.profileHome;
|
|
1009
1011
|
const profile = basename(profileHome);
|
|
@@ -1030,91 +1032,99 @@ async function materializeAdminProfile({
|
|
|
1030
1032
|
const layout = adminHomeLayout(profileHome);
|
|
1031
1033
|
// stageAdminProfile canonicalizes these two paths before staging, so the
|
|
1032
1034
|
// Admin home working copies must exist before the factory runs.
|
|
1033
|
-
|
|
1035
|
+
await runPhase("profile_settings_delivery", async () => {
|
|
1036
|
+
deliverAdminSettings(settingsRoot, layout);
|
|
1037
|
+
});
|
|
1034
1038
|
const serverProofs = {};
|
|
1035
|
-
const stageWithAuthority = async (stagedAuthority) =>
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1039
|
+
const stageWithAuthority = async (stagedAuthority) =>
|
|
1040
|
+
runPhase("profile_stage", async () => {
|
|
1041
|
+
const stage = await stageAdminProfile({
|
|
1042
|
+
mode: slack ? "direct_soul_native_slack" : "direct_soul",
|
|
1043
|
+
lifecycleAuthorized: slack ? true : undefined,
|
|
1044
|
+
ephemeralProductConfig: Boolean(slack),
|
|
1045
|
+
ephemeralSlackSecrets: Boolean(slack),
|
|
1046
|
+
profile,
|
|
1047
|
+
profilesRoot: PROFILES_ROOT,
|
|
1048
|
+
stageRoot,
|
|
1049
|
+
finalProfileRoot: profileHome,
|
|
1050
|
+
rootAuthPath,
|
|
1051
|
+
canonicalAdminConfigPath: layout.configPath,
|
|
1052
|
+
canonicalAdminStatePath: layout.statePath,
|
|
1053
|
+
productConfigPath,
|
|
1054
|
+
model: "gpt-5.6-sol",
|
|
1055
|
+
reasoningEffort: "high",
|
|
1056
|
+
soul: stagedAuthority,
|
|
1057
|
+
...(slack
|
|
1058
|
+
? {
|
|
1059
|
+
slackSecretFile: slack.secretFile,
|
|
1060
|
+
teamId: slack.teamId,
|
|
1061
|
+
primaryChannel: slack.primaryChannel,
|
|
1062
|
+
secondaryReadChannelIds: slack.secondaryReadChannelIds,
|
|
1063
|
+
allowedSlackUserIds: slack.allowedSlackUserIds,
|
|
1064
|
+
slackApp: slack.slackApp,
|
|
1065
|
+
}
|
|
1066
|
+
: {}),
|
|
1067
|
+
skillsRoot: join(ADMIN_INSTALL_ASSET_ROOT, "mcp", "skills"),
|
|
1068
|
+
installRoot: layout.adminRoot,
|
|
1069
|
+
adminHome: layout.adminHome,
|
|
1070
|
+
installAdmin: async () =>
|
|
1071
|
+
profilePackageReceipt(
|
|
1072
|
+
profileContract,
|
|
1073
|
+
"sellable-admin",
|
|
1074
|
+
"mcp",
|
|
1075
|
+
layout
|
|
1076
|
+
),
|
|
1077
|
+
installProduct: async () =>
|
|
1078
|
+
profilePackageReceipt(
|
|
1079
|
+
profileContract,
|
|
1080
|
+
"sellable",
|
|
1081
|
+
"mcp",
|
|
1082
|
+
layout,
|
|
1083
|
+
agentServiceEnv
|
|
1084
|
+
),
|
|
1085
|
+
verifyMcp: async ({ kind, profileRoot, config }) => {
|
|
1086
|
+
const alias = kind === "admin" ? "sellable-admin" : "sellable";
|
|
1087
|
+
const server = config.mcp_servers[alias];
|
|
1088
|
+
const inventoryProof =
|
|
1089
|
+
alias === "sellable" ? productMcpInventoryProofEnvironment() : null;
|
|
1090
|
+
let proof;
|
|
1091
|
+
try {
|
|
1092
|
+
proof = await inspectMcp({
|
|
1093
|
+
alias,
|
|
1094
|
+
command: server.command,
|
|
1095
|
+
args: server.args,
|
|
1096
|
+
env: {
|
|
1097
|
+
HOME: profileRoot,
|
|
1098
|
+
HERMES_HOME: profileRoot,
|
|
1099
|
+
...adminToolEnv(layout),
|
|
1100
|
+
...agentServiceEnv,
|
|
1101
|
+
SELLABLE_CONFIG_PATH: productConfigPath,
|
|
1102
|
+
...(server.env ?? {}),
|
|
1103
|
+
...(inventoryProof?.env ?? {}),
|
|
1104
|
+
},
|
|
1105
|
+
packageProof: profileContract.packages[alias].mcp,
|
|
1106
|
+
});
|
|
1107
|
+
} finally {
|
|
1108
|
+
if (inventoryProof) {
|
|
1109
|
+
rmSync(inventoryProof.root, { recursive: true, force: true });
|
|
1110
|
+
}
|
|
1060
1111
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
profilePackageReceipt(profileContract, "sellable-admin", "mcp", layout),
|
|
1067
|
-
installProduct: async () =>
|
|
1068
|
-
profilePackageReceipt(
|
|
1069
|
-
profileContract,
|
|
1070
|
-
"sellable",
|
|
1071
|
-
"mcp",
|
|
1072
|
-
layout,
|
|
1073
|
-
agentServiceEnv
|
|
1074
|
-
),
|
|
1075
|
-
verifyMcp: async ({ kind, profileRoot, config }) => {
|
|
1076
|
-
const alias = kind === "admin" ? "sellable-admin" : "sellable";
|
|
1077
|
-
const server = config.mcp_servers[alias];
|
|
1078
|
-
const inventoryProof =
|
|
1079
|
-
alias === "sellable" ? productMcpInventoryProofEnvironment() : null;
|
|
1080
|
-
let proof;
|
|
1081
|
-
try {
|
|
1082
|
-
proof = await inspectMcp({
|
|
1083
|
-
alias,
|
|
1084
|
-
command: server.command,
|
|
1085
|
-
args: server.args,
|
|
1086
|
-
env: {
|
|
1087
|
-
HOME: profileRoot,
|
|
1088
|
-
HERMES_HOME: profileRoot,
|
|
1089
|
-
...adminToolEnv(layout),
|
|
1090
|
-
...agentServiceEnv,
|
|
1091
|
-
SELLABLE_CONFIG_PATH: productConfigPath,
|
|
1092
|
-
...(server.env ?? {}),
|
|
1093
|
-
...(inventoryProof?.env ?? {}),
|
|
1094
|
-
},
|
|
1095
|
-
packageProof: profileContract.packages[alias].mcp,
|
|
1096
|
-
});
|
|
1097
|
-
} finally {
|
|
1098
|
-
if (inventoryProof) {
|
|
1099
|
-
rmSync(inventoryProof.root, { recursive: true, force: true });
|
|
1112
|
+
if (
|
|
1113
|
+
JSON.stringify(proof.tools) !==
|
|
1114
|
+
JSON.stringify(profileContract.tools[alias])
|
|
1115
|
+
) {
|
|
1116
|
+
throw new Error("admin_runtime_tool_inventory_mismatch");
|
|
1100
1117
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
},
|
|
1118
|
+
serverProofs[alias] = proof;
|
|
1119
|
+
return { ok: true, ...proof };
|
|
1120
|
+
},
|
|
1121
|
+
});
|
|
1122
|
+
if (slack) installWritableAdminSlackChannelPolicy(stageRoot, slack);
|
|
1123
|
+
installAdminModelConfig(stageRoot, modelConfig);
|
|
1124
|
+
installAdminHermesMemoryHook(stageRoot);
|
|
1125
|
+
stageAdminRuntimeTree(stageRoot);
|
|
1126
|
+
return stage;
|
|
1111
1127
|
});
|
|
1112
|
-
if (slack) installWritableAdminSlackChannelPolicy(stageRoot, slack);
|
|
1113
|
-
installAdminModelConfig(stageRoot, modelConfig);
|
|
1114
|
-
installAdminHermesMemoryHook(stageRoot);
|
|
1115
|
-
stageAdminRuntimeTree(stageRoot);
|
|
1116
|
-
return stage;
|
|
1117
|
-
};
|
|
1118
1128
|
|
|
1119
1129
|
let stagedAuthority = withProfileSoulLock(profile, readAuthoritativeSoul, {
|
|
1120
1130
|
dataRoot: DATA_ROOT,
|
|
@@ -1123,79 +1133,83 @@ async function materializeAdminProfile({
|
|
|
1123
1133
|
let promoted = null;
|
|
1124
1134
|
for (let attempt = 0; attempt < 2 && !promoted; attempt += 1) {
|
|
1125
1135
|
stage = await stageWithAuthority(stagedAuthority);
|
|
1126
|
-
const committed = await
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
stagedSoul
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
finalSoul
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1136
|
+
const committed = await runPhase("profile_live_merge_promote", async () =>
|
|
1137
|
+
withProfileSoulLock(
|
|
1138
|
+
profile,
|
|
1139
|
+
async () => {
|
|
1140
|
+
const finalAuthority = readAuthoritativeSoul();
|
|
1141
|
+
if (
|
|
1142
|
+
finalAuthority.sha256 !== stagedAuthority.sha256 ||
|
|
1143
|
+
!finalAuthority.bytes.equals(stagedAuthority.bytes)
|
|
1144
|
+
) {
|
|
1145
|
+
rmSync(stageRoot, { recursive: true, force: true });
|
|
1146
|
+
return { status: "RESTAGE", stagedAuthority: finalAuthority };
|
|
1147
|
+
}
|
|
1148
|
+
const liveSkillsIdentity = adminPreservedSkillsIdentity(profileHome);
|
|
1149
|
+
if (liveSkillsIdentity !== null) {
|
|
1150
|
+
replaceHermesState(
|
|
1151
|
+
join(profileHome, "skills"),
|
|
1152
|
+
join(stageRoot, "skills"),
|
|
1153
|
+
{
|
|
1154
|
+
preserveTargetTopLevelNames: [
|
|
1155
|
+
...ADMIN_SEALED_SKILL_DIRECTORIES,
|
|
1156
|
+
],
|
|
1157
|
+
}
|
|
1158
|
+
);
|
|
1159
|
+
}
|
|
1160
|
+
mergeHermesState(profileHome, stageRoot, {
|
|
1161
|
+
skipSourceTopLevelNames:
|
|
1162
|
+
liveSkillsIdentity === null ? [] : ["skills"],
|
|
1163
|
+
});
|
|
1164
|
+
mergeAdminLiveSkillsConfig(profileHome, stageRoot);
|
|
1165
|
+
installAdminBrowserToolsetDefault(profileHome, stageRoot);
|
|
1166
|
+
if (
|
|
1167
|
+
liveSkillsIdentity !== null &&
|
|
1168
|
+
adminPreservedSkillsIdentity(stageRoot) !== liveSkillsIdentity
|
|
1169
|
+
) {
|
|
1170
|
+
rmSync(stageRoot, { recursive: true, force: true });
|
|
1171
|
+
return { status: "RESTAGE", stagedAuthority: finalAuthority };
|
|
1172
|
+
}
|
|
1173
|
+
const stagedSoulPath = join(stageRoot, "SOUL.md");
|
|
1174
|
+
const stagedSoul = lstatSync(stagedSoulPath);
|
|
1175
|
+
const stagedSoulBytes = readFileSync(stagedSoulPath);
|
|
1176
|
+
if (
|
|
1177
|
+
stagedSoul.isSymbolicLink() ||
|
|
1178
|
+
!stagedSoul.isFile() ||
|
|
1179
|
+
!stagedSoulBytes.equals(finalAuthority.bytes)
|
|
1180
|
+
) {
|
|
1181
|
+
throw new Error("admin_runtime_staged_soul_rejected");
|
|
1182
|
+
}
|
|
1183
|
+
const promotion = await promoteAdminProfileAtomically({
|
|
1184
|
+
profile,
|
|
1185
|
+
currentRoot: profileHome,
|
|
1186
|
+
stagedRoot: stageRoot,
|
|
1187
|
+
backupRoot,
|
|
1188
|
+
});
|
|
1189
|
+
const finalSoulPath = join(profileHome, "SOUL.md");
|
|
1190
|
+
const finalSoul = lstatSync(finalSoulPath);
|
|
1191
|
+
const finalSoulBytes = readFileSync(finalSoulPath);
|
|
1192
|
+
if (
|
|
1193
|
+
finalSoul.isSymbolicLink() ||
|
|
1194
|
+
!finalSoul.isFile() ||
|
|
1195
|
+
finalSoul.uid !== (process.getuid?.() ?? finalSoul.uid) ||
|
|
1196
|
+
finalSoul.gid !== (process.getgid?.() ?? finalSoul.gid) ||
|
|
1197
|
+
!finalSoulBytes.equals(finalAuthority.bytes)
|
|
1198
|
+
) {
|
|
1199
|
+
throw new Error("admin_runtime_live_soul_readback_rejected");
|
|
1200
|
+
}
|
|
1201
|
+
chmodSync(finalSoulPath, 0o600);
|
|
1202
|
+
if ((lstatSync(finalSoulPath).mode & 0o777) !== 0o600) {
|
|
1203
|
+
throw new Error("admin_runtime_live_soul_mode_rejected");
|
|
1204
|
+
}
|
|
1205
|
+
return {
|
|
1206
|
+
status: "PROMOTED",
|
|
1207
|
+
promotion,
|
|
1208
|
+
observedSoulRawSha256: sha256(finalSoulBytes),
|
|
1209
|
+
};
|
|
1210
|
+
},
|
|
1211
|
+
{ dataRoot: DATA_ROOT }
|
|
1212
|
+
)
|
|
1199
1213
|
);
|
|
1200
1214
|
if (committed.status === "PROMOTED") {
|
|
1201
1215
|
promoted = committed;
|
|
@@ -1208,20 +1222,27 @@ async function materializeAdminProfile({
|
|
|
1208
1222
|
}
|
|
1209
1223
|
// The installer bakes absolute paths into every generated wrapper, so bin/
|
|
1210
1224
|
// is generated once the promoted Admin home is at its final path.
|
|
1211
|
-
const adminHome
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
+
const { adminHome, memoryCron, opportunitySequencesCron } = await runPhase(
|
|
1226
|
+
"profile_crons",
|
|
1227
|
+
async () => {
|
|
1228
|
+
const adminHome = installAdminHome({ settingsRoot, layout });
|
|
1229
|
+
const memoryCron = await ensureHermesSnapshotCron({
|
|
1230
|
+
profileId: profile,
|
|
1231
|
+
profileRoot: profileHome,
|
|
1232
|
+
hermesRoot: DATA_ROOT,
|
|
1233
|
+
hermesCli: HERMES,
|
|
1234
|
+
});
|
|
1235
|
+
if (!memoryCron.ok) throw new Error(memoryCron.code);
|
|
1236
|
+
const opportunitySequencesCron =
|
|
1237
|
+
await ensureHermesOpportunitySequencesCron({
|
|
1238
|
+
profileId: profile,
|
|
1239
|
+
profileRoot: profileHome,
|
|
1240
|
+
hermesRoot: DATA_ROOT,
|
|
1241
|
+
statePath: layout.statePath,
|
|
1242
|
+
});
|
|
1243
|
+
return { adminHome, memoryCron, opportunitySequencesCron };
|
|
1244
|
+
}
|
|
1245
|
+
);
|
|
1225
1246
|
return {
|
|
1226
1247
|
stage,
|
|
1227
1248
|
promotion: promoted.promotion,
|
|
@@ -3640,6 +3661,10 @@ async function runAdminProduction() {
|
|
|
3640
3661
|
exchange,
|
|
3641
3662
|
client,
|
|
3642
3663
|
});
|
|
3664
|
+
const phaseTelemetry = createAdminRuntimePhaseTelemetry({
|
|
3665
|
+
bootSessionId: BOOT_SESSION_ID,
|
|
3666
|
+
operationId: claim.operation.id,
|
|
3667
|
+
});
|
|
3643
3668
|
await activeModelHealthReporter?.stop();
|
|
3644
3669
|
activeModelHealthReporter = null;
|
|
3645
3670
|
await stopNativeGateway(activeGateway);
|
|
@@ -3713,30 +3738,40 @@ async function runAdminProduction() {
|
|
|
3713
3738
|
// Authority is fully decidable from the claim and durable settings
|
|
3714
3739
|
// metadata. Refuse it before consuming any lease secret so the failure
|
|
3715
3740
|
// can be reported as exact and retryable instead of uncertain.
|
|
3716
|
-
const secrets = await consumeRuntimeSecrets({
|
|
3717
|
-
claim,
|
|
3718
|
-
exchange,
|
|
3719
|
-
client,
|
|
3720
|
-
});
|
|
3721
|
-
claimSecretsConsumed = true;
|
|
3722
3741
|
const desiredLifecycle = desiredLifecycleForClaim(claim);
|
|
3723
|
-
const installed =
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3742
|
+
const { secrets, installed } = await phaseTelemetry.run(
|
|
3743
|
+
"runtime_secrets",
|
|
3744
|
+
async () => {
|
|
3745
|
+
const secrets = await consumeRuntimeSecrets({
|
|
3746
|
+
claim,
|
|
3747
|
+
exchange,
|
|
3748
|
+
client,
|
|
3749
|
+
});
|
|
3750
|
+
claimSecretsConsumed = true;
|
|
3751
|
+
const installed = installRuntimeSecrets({
|
|
3752
|
+
claim,
|
|
3753
|
+
secrets,
|
|
3754
|
+
desiredLifecycle,
|
|
3755
|
+
});
|
|
3756
|
+
return { secrets, installed };
|
|
3757
|
+
}
|
|
3758
|
+
);
|
|
3728
3759
|
const proofOperation = operation ?? {
|
|
3729
3760
|
runtimeGenerationId: claim.adminRuntimeGeneration.id,
|
|
3730
3761
|
generationFence: claim.adminRuntimeGeneration.fence,
|
|
3731
3762
|
profileContract,
|
|
3732
3763
|
};
|
|
3733
|
-
const memoryRestore = await
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3764
|
+
const memoryRestore = await phaseTelemetry.run(
|
|
3765
|
+
"snapshot_restore",
|
|
3766
|
+
async () =>
|
|
3767
|
+
restoreLatestHermesSnapshot({
|
|
3768
|
+
profileId: basename(profileContract.profileHome),
|
|
3769
|
+
profileRoot: profileContract.profileHome,
|
|
3770
|
+
hermesRoot: DATA_ROOT,
|
|
3771
|
+
hermesVersion: "0.20.0",
|
|
3772
|
+
fetchLatest: () => client.getMemorySnapshot(),
|
|
3773
|
+
})
|
|
3774
|
+
);
|
|
3740
3775
|
if (!memoryRestore.ok) throw new Error(memoryRestore.code);
|
|
3741
3776
|
await operationHeartbeat.reattest();
|
|
3742
3777
|
const legacyLightfieldVenv = quarantineLegacyLightfieldVenv({
|
|
@@ -3766,6 +3801,7 @@ async function runAdminProduction() {
|
|
|
3766
3801
|
soul: exactSoul(claim),
|
|
3767
3802
|
slack: nativeSlackProfileInput(claim, installed),
|
|
3768
3803
|
agentServiceEnv: adminAgentServiceEnvironment(claim),
|
|
3804
|
+
runPhase: phaseTelemetry.run,
|
|
3769
3805
|
});
|
|
3770
3806
|
await operationHeartbeat.reattest();
|
|
3771
3807
|
const materializerReceipt = adminMaterializerReceipt(
|
|
@@ -3776,21 +3812,25 @@ async function runAdminProduction() {
|
|
|
3776
3812
|
kind: "ADMIN",
|
|
3777
3813
|
claim,
|
|
3778
3814
|
});
|
|
3779
|
-
const reconciledDefaultProfile = await
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3815
|
+
const reconciledDefaultProfile = await phaseTelemetry.run(
|
|
3816
|
+
"default_profile_bundle",
|
|
3817
|
+
async () =>
|
|
3818
|
+
reconcileDefaultProfileBundle({
|
|
3819
|
+
activeProjection,
|
|
3820
|
+
materializerReceipt,
|
|
3821
|
+
profileRoot: profile.profileHome,
|
|
3822
|
+
bundleRoot: DEFAULT_PROFILE_BUNDLE_ROOT,
|
|
3823
|
+
dataRoot: DATA_ROOT,
|
|
3824
|
+
reattestAuthority: async () => {
|
|
3825
|
+
await operationHeartbeat.reattest();
|
|
3826
|
+
return activeProjection;
|
|
3827
|
+
},
|
|
3828
|
+
cronAdapter: adminDefaultProfileCronAdapter(
|
|
3829
|
+
profile.profile,
|
|
3830
|
+
profile.profileHome
|
|
3831
|
+
),
|
|
3832
|
+
})
|
|
3833
|
+
);
|
|
3794
3834
|
if (!reconciledDefaultProfile.ok)
|
|
3795
3835
|
throw new Error(reconciledDefaultProfile.code);
|
|
3796
3836
|
const defaultProfile = reconciledDefaultProfile;
|
|
@@ -3813,11 +3853,15 @@ async function runAdminProduction() {
|
|
|
3813
3853
|
profile.opportunitySequencesCron.status !== "REUSED";
|
|
3814
3854
|
if (materializerChanged || defaultProfile.changed)
|
|
3815
3855
|
markHermesSnapshotDirty(profile.profileHome);
|
|
3816
|
-
const memorySnapshot = await
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3856
|
+
const memorySnapshot = await phaseTelemetry.run(
|
|
3857
|
+
"memory_snapshot",
|
|
3858
|
+
async () =>
|
|
3859
|
+
flushHermesSnapshot({
|
|
3860
|
+
client,
|
|
3861
|
+
profileId: profile.profile,
|
|
3862
|
+
profileRoot: profile.profileHome,
|
|
3863
|
+
})
|
|
3864
|
+
);
|
|
3821
3865
|
await operationHeartbeat.reattest();
|
|
3822
3866
|
const settings = settingsProof(
|
|
3823
3867
|
imported.receipt.generationRoot,
|
|
@@ -3841,10 +3885,13 @@ async function runAdminProduction() {
|
|
|
3841
3885
|
});
|
|
3842
3886
|
}
|
|
3843
3887
|
operationHeartbeat.assertHealthy();
|
|
3844
|
-
const slackProof =
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3888
|
+
const slackProof = await phaseTelemetry.run(
|
|
3889
|
+
"slack_serving_proof",
|
|
3890
|
+
async () =>
|
|
3891
|
+
desiredLifecycle === "ON"
|
|
3892
|
+
? proveAdminSlackServing(claim, secrets)
|
|
3893
|
+
: false
|
|
3894
|
+
);
|
|
3848
3895
|
await operationHeartbeat.reattest();
|
|
3849
3896
|
const candidateLaunch =
|
|
3850
3897
|
desiredLifecycle === "ON"
|
|
@@ -3853,7 +3900,10 @@ async function runAdminProduction() {
|
|
|
3853
3900
|
let candidateGateway = null;
|
|
3854
3901
|
try {
|
|
3855
3902
|
if (candidateLaunch) {
|
|
3856
|
-
candidateGateway = await
|
|
3903
|
+
candidateGateway = await phaseTelemetry.run(
|
|
3904
|
+
"native_gateway",
|
|
3905
|
+
async () => startNativeGateway(candidateLaunch)
|
|
3906
|
+
);
|
|
3857
3907
|
await operationHeartbeat.reattest();
|
|
3858
3908
|
}
|
|
3859
3909
|
const nativeDefaultProfileProof = candidateGateway
|
|
@@ -3876,26 +3926,31 @@ async function runAdminProduction() {
|
|
|
3876
3926
|
activeProjection,
|
|
3877
3927
|
nativeDefaultProfileProof,
|
|
3878
3928
|
});
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
if (!servingObservation) {
|
|
3886
|
-
throw new Error("admin_serving_observation_unavailable");
|
|
3887
|
-
}
|
|
3888
|
-
const serving = await client.claimTick({
|
|
3889
|
-
leaseSeconds: 60,
|
|
3890
|
-
servingObservation,
|
|
3891
|
-
});
|
|
3892
|
-
if (serving?.servingObservationStatus !== "accepted") {
|
|
3893
|
-
throw new Error(
|
|
3894
|
-
`admin_serving_observation_rejected:${serving?.servingObservationCode ?? serving?.servingObservationStatus ?? "unknown"}`
|
|
3929
|
+
await phaseTelemetry.run("serving_observation", async () => {
|
|
3930
|
+
if (claim.runtimeAuthority && candidateLaunch && candidateGateway) {
|
|
3931
|
+
const servingObservation = adminServingObservation(
|
|
3932
|
+
candidateLaunch,
|
|
3933
|
+
candidateGateway,
|
|
3934
|
+
exchange
|
|
3895
3935
|
);
|
|
3936
|
+
if (!servingObservation) {
|
|
3937
|
+
throw new Error("admin_serving_observation_unavailable");
|
|
3938
|
+
}
|
|
3939
|
+
const serving = await client.claimTick({
|
|
3940
|
+
leaseSeconds: 60,
|
|
3941
|
+
servingObservation,
|
|
3942
|
+
});
|
|
3943
|
+
if (serving?.servingObservationStatus !== "accepted") {
|
|
3944
|
+
throw new Error(
|
|
3945
|
+
`admin_serving_observation_rejected:${serving?.servingObservationCode ?? serving?.servingObservationStatus ?? "unknown"}`
|
|
3946
|
+
);
|
|
3947
|
+
}
|
|
3896
3948
|
}
|
|
3897
|
-
}
|
|
3898
|
-
const completed = await
|
|
3949
|
+
});
|
|
3950
|
+
const completed = await phaseTelemetry.run(
|
|
3951
|
+
"operation_completion",
|
|
3952
|
+
async () => client.complete(receipt)
|
|
3953
|
+
);
|
|
3899
3954
|
if (completed?.accepted !== true) {
|
|
3900
3955
|
throw new Error("admin_runtime_completion_rejected");
|
|
3901
3956
|
}
|
|
@@ -8,7 +8,7 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright
|
|
|
8
8
|
|
|
9
9
|
ARG MCP_PACKAGE=@sellable/mcp@0.1.880
|
|
10
10
|
ARG MCP_INTEGRITY=sha512-+Fo8aQlYduLaQMQff+ZA25LeUhWZ7I7UH5DECpND84LQ+rHSjKeKFj4Zs93bVHXwQCIy2OLbr75y4f4+CyT57w==
|
|
11
|
-
ARG INSTALLER_PACKAGE=@sellable/install@0.1.
|
|
11
|
+
ARG INSTALLER_PACKAGE=@sellable/install@0.1.654-wip.phase189.20260814.2
|
|
12
12
|
ARG ADMIN_MCP_PACKAGE=@sellable/admin-mcp@0.1.186-wip.phase158.20260802034727
|
|
13
13
|
ARG ADMIN_MCP_INTEGRITY=sha512-qYNew5wd2IfgVcp1UYOG9QvpF/8Mx19YJ5HQtMKzvSfUf3evePjtaKsoXLf2C/GUJ5QlLlHJo84VWOI3V01+9A==
|
|
14
14
|
ARG TUS_JS_CLIENT_VERSION=4.3.1
|
|
@@ -81,6 +81,7 @@ RUN --mount=type=secret,id=mcp_trust_root,required=true \
|
|
|
81
81
|
|
|
82
82
|
COPY mcp-context-proxy.mjs mcp-runtime-binding.mjs fly-customer-model.mjs fly-customer-worker.mjs profile-materializer.mjs hermes-bridge.mjs hermes-memory-snapshot.mjs fly-runtime-identity.mjs fly-soul-bridge.mjs fly-soul-bridge-exec.mjs fly-skills-bridge.mjs fly-skills-bridge-exec.mjs fly-capabilities-bridge.mjs fly-capabilities-bridge-exec.mjs soul-artifact-validator.mjs default-profile-bundle.mjs default-profile-reconciler.mjs fly-cron-proof-exec.mjs model-auth-reconciler.mjs model-auth-canary-reseed.mjs model-health-reporter.mjs \
|
|
83
83
|
/usr/local/lib/sellable-agent/
|
|
84
|
+
COPY abandoned-runtime-scratch.mjs /usr/local/lib/sellable-agent/abandoned-runtime-scratch.mjs
|
|
84
85
|
COPY default-profile-bundles/shared/ /usr/local/lib/sellable-agent/default-profile-bundles/shared/
|
|
85
86
|
COPY default-profile-bundles/customer/ /usr/local/lib/sellable-agent/default-profile-bundles/customer/
|
|
86
87
|
COPY default-profile-bundles/fixtures/ /usr/local/lib/sellable-agent/default-profile-bundles/fixtures/
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { loadavg } from "node:os";
|
|
18
18
|
import { dirname, join } from "node:path";
|
|
19
19
|
import { pathToFileURL } from "node:url";
|
|
20
|
+
import { pruneAbandonedRuntimeScratch } from "../abandoned-runtime-scratch.mjs";
|
|
20
21
|
import {
|
|
21
22
|
buildNativeHermesLaunch,
|
|
22
23
|
buildRuntimeServingObservation,
|
|
@@ -105,7 +106,7 @@ const BOOT_SESSION_ID = randomUUID();
|
|
|
105
106
|
const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.20.0";
|
|
106
107
|
const INSTALLER_PACKAGE =
|
|
107
108
|
process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ??
|
|
108
|
-
"@sellable/install@0.1.
|
|
109
|
+
"@sellable/install@0.1.654-wip.phase189.20260814.2";
|
|
109
110
|
const MCP_PACKAGE =
|
|
110
111
|
process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.880";
|
|
111
112
|
const DEFAULT_PROFILE_BUNDLE_ROOT =
|
|
@@ -3093,6 +3094,19 @@ async function main() {
|
|
|
3093
3094
|
) {
|
|
3094
3095
|
throw new Error("customer_configuration_rejected");
|
|
3095
3096
|
}
|
|
3097
|
+
const scratch = pruneAbandonedRuntimeScratch({
|
|
3098
|
+
hermesRoot: DATA_ROOT,
|
|
3099
|
+
profilesRoot: PROFILES_ROOT,
|
|
3100
|
+
});
|
|
3101
|
+
if (scratch.removed.length > 0) {
|
|
3102
|
+
process.stderr.write(
|
|
3103
|
+
`${JSON.stringify({
|
|
3104
|
+
ok: true,
|
|
3105
|
+
code: scratch.code,
|
|
3106
|
+
removed: scratch.removed,
|
|
3107
|
+
})}\n`
|
|
3108
|
+
);
|
|
3109
|
+
}
|
|
3096
3110
|
let oidcToken = await obtainFlyOidcToken({ audience: AUDIENCE });
|
|
3097
3111
|
dropFlyRuntimePrivileges({
|
|
3098
3112
|
user: "hermes",
|
|
@@ -514,7 +514,7 @@ export async function ensureHermesNamedCron({
|
|
|
514
514
|
try {
|
|
515
515
|
const before = cronJobs(profileRoot);
|
|
516
516
|
const named = before.filter((job) => job?.name === name);
|
|
517
|
-
if (named.length > 1
|
|
517
|
+
if (named.length > 1) {
|
|
518
518
|
return failed(`${codePrefix}_inventory_rejected`);
|
|
519
519
|
}
|
|
520
520
|
if (named[0] && isExpected(named[0])) {
|
|
@@ -525,6 +525,9 @@ export async function ensureHermesNamedCron({
|
|
|
525
525
|
job: named[0],
|
|
526
526
|
};
|
|
527
527
|
}
|
|
528
|
+
if (named[0] && !isUpdatable(named[0])) {
|
|
529
|
+
return failed(`${codePrefix}_inventory_rejected`);
|
|
530
|
+
}
|
|
528
531
|
const siblings = before.filter((job) => job?.name !== name);
|
|
529
532
|
const mutation = named[0] ? await update(named[0]) : await create();
|
|
530
533
|
if (childFailed(mutation)) {
|
|
@@ -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.654-wip.phase189.20260814.2";
|
|
42
42
|
const MCP_PACKAGE = "@sellable/mcp@0.1.880";
|
|
43
43
|
const HERMES_VERSION = "0.18.0";
|
|
44
44
|
const SHA256 = /^[a-f0-9]{64}$/;
|
|
@@ -1547,7 +1547,7 @@ export function compileClaimToProfileDesired(activeClaim, config) {
|
|
|
1547
1547
|
pinned.hermesCli !== "hermes" ||
|
|
1548
1548
|
pinned.hermesVersion !== "0.18.0" ||
|
|
1549
1549
|
pinned.installerPackage !==
|
|
1550
|
-
"@sellable/install@0.1.
|
|
1550
|
+
"@sellable/install@0.1.654-wip.phase189.20260814.2" ||
|
|
1551
1551
|
pinned.mcpPackage !== "@sellable/mcp@0.1.880" ||
|
|
1552
1552
|
!Array.isArray(policy.toolInclude) ||
|
|
1553
1553
|
policy.toolInclude.length === 0 ||
|
|
@@ -283,7 +283,7 @@ function validateDesired(desired) {
|
|
|
283
283
|
desired.hermesCli !== "hermes" ||
|
|
284
284
|
desired.hermesVersion !== "0.18.0" ||
|
|
285
285
|
desired.installerPackage !==
|
|
286
|
-
"@sellable/install@0.1.
|
|
286
|
+
"@sellable/install@0.1.654-wip.phase189.20260814.2" ||
|
|
287
287
|
desired.mcpPackage !== "@sellable/mcp@0.1.880" ||
|
|
288
288
|
!Array.isArray(desired.toolInclude) ||
|
|
289
289
|
desired.toolInclude.length === 0 ||
|
|
@@ -26,7 +26,7 @@ import { deriveContainedProfileId } from "./profile-materializer.mjs";
|
|
|
26
26
|
|
|
27
27
|
export const PROVISIONING_ACTION = "PROVISION_HERMES_PROFILE";
|
|
28
28
|
export const PINNED_INSTALL_PACKAGE =
|
|
29
|
-
"@sellable/install@0.1.
|
|
29
|
+
"@sellable/install@0.1.654-wip.phase189.20260814.2";
|
|
30
30
|
export const PINNED_MCP_PACKAGE = "@sellable/mcp@0.1.880";
|
|
31
31
|
const PINNED_INSTALL_VERSION = PINNED_INSTALL_PACKAGE.slice(
|
|
32
32
|
PINNED_INSTALL_PACKAGE.lastIndexOf("@") + 1
|