@sellable/install 0.1.612-wip.phase189.20260812.2 → 0.1.612

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.
@@ -3,13 +3,13 @@ FROM ${HERMES_IMAGE}
3
3
 
4
4
  USER root
5
5
 
6
- ARG INSTALLER_PACKAGE=@sellable/install@0.1.612-wip.phase189.20260812.2
7
- ARG MCP_PACKAGE=@sellable/mcp@0.1.865
6
+ ARG INSTALLER_PACKAGE=@sellable/install@0.1.612
7
+ ARG MCP_PACKAGE=@sellable/mcp@0.1.867
8
8
  ARG INSTALLER_INTEGRITY
9
- ARG MCP_INTEGRITY=sha512-282pkYFADFrrIXyQcdUpQwakXiwe/AFUDpDZkTh29CFcGHnN7dvC0MCvaU4LffXA+ZuKCpuf02uxCLGiIEOjbw==
9
+ ARG MCP_INTEGRITY=sha512-8acJ5MfqgXiu9ylK65LlQ7LUBN5GN5fEXOwDTArxYAN7nBvVLhdz0nTGMERc6qCFNBbILTKvo4IErJOnAcJTDA==
10
10
 
11
- RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.612-wip.phase189.20260812.2" \
12
- && test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.865" \
11
+ RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.612" \
12
+ && test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.867" \
13
13
  && test -n "${INSTALLER_INTEGRITY}" \
14
14
  && test "$(npm view "${INSTALLER_PACKAGE}" dist.integrity)" = "${INSTALLER_INTEGRITY}" \
15
15
  && test "$(npm view "${MCP_PACKAGE}" dist.integrity)" = "${MCP_INTEGRITY}" \
@@ -23,9 +23,9 @@ RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.612-wip.phase189.202608
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.612-wip.phase189.20260812.2-wip.hermes-desktop.20260811160530' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.865') throw new Error('package identity rejected');" \
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.609-wip.hermes-desktop.20260811160530' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.867') 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.612-wip.phase189.20260812.2', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.865', 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}" \
28
+ && node --input-type=module -e "import { chmodSync, writeFileSync } from 'node:fs'; const release = { installerPackage: '@sellable/install@0.1.612', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.867', 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
@@ -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.612-wip.phase189.20260812.2` is
6
+ `@sellable/install@0.1.612` 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.612-wip.phase189.20260812.2-wip.hermes-desktop.20260811160530 .
12
+ --tag sellable-agent-host:0.1.609-wip.hermes-desktop.20260811160530 .
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`.
@@ -20,6 +20,7 @@ import { createHash } from "node:crypto";
20
20
 
21
21
  const SHA256 = /^[a-f0-9]{64}$/;
22
22
  const EXACT_VERSION = /^\d+\.\d+\.\d+(?:[-.A-Za-z0-9]+)?$/;
23
+ const PACKAGE_DISPOSITIONS = new Set(["changed", "reused"]);
23
24
  const PUBLIC_ACTIONS = new Set(["INSTANTIATE", "REFRESH"]);
24
25
  const RESTORATION_ACTIONS = new Set([
25
26
  "START",
@@ -64,14 +65,13 @@ export function validateAdminRuntimeTuple(tuple) {
64
65
  }
65
66
  for (const name of ADMIN_RUNTIME_TUPLE_MEMBERS) {
66
67
  const item = tuple.packages[name];
67
- const expectedDisposition = name === "@sellable/mcp" ? "reused" : "changed";
68
68
  if (
69
69
  !item ||
70
70
  item.name !== name ||
71
71
  !EXACT_VERSION.test(item.version ?? "") ||
72
72
  typeof item.integrity !== "string" ||
73
73
  !/^sha512-[A-Za-z0-9+/]{80,}={0,2}$/.test(item.integrity) ||
74
- item.disposition !== expectedDisposition
74
+ !PACKAGE_DISPOSITIONS.has(item.disposition)
75
75
  ) {
76
76
  return {
77
77
  ok: false,
@@ -28,7 +28,7 @@ import {
28
28
 
29
29
  const MANIFEST_VERSION = "sellable-agent-external-runtime-closure/v1";
30
30
  const MCP_PACKAGE = "@sellable/mcp";
31
- const MCP_VERSION = "0.1.865";
31
+ const MCP_VERSION = "0.1.867";
32
32
  const SAFE_COMPONENT = /^[A-Za-z0-9@._+-]+$/;
33
33
  const HERMES_EXCLUDES = new Set([".git", ".playwright", "node_modules"]);
34
34
 
@@ -40,7 +40,6 @@ import {
40
40
  import {
41
41
  buildAdminAgentServiceEnvironment,
42
42
  buildNativeHermesLaunch,
43
- buildRuntimeServingObservation,
44
43
  } from "../admin-artifact/node_modules/@sellable/install/lib/sellable-agent/fly-customer-worker.mjs";
45
44
  import sodium from "../admin-artifact/node_modules/libsodium-wrappers/dist/modules-esm/libsodium-wrappers.mjs";
46
45
  import { SELLABLE_ALLOWED_TOOLSETS } from "../fly-capabilities-bridge.mjs";
@@ -68,11 +67,11 @@ import {
68
67
  HERMES_SNAPSHOT_HOOKS,
69
68
  HERMES_SNAPSHOT_HOOK_ALLOWLIST_BYTES,
70
69
  applyHermesHostedBackgroundReviewPolicy,
70
+ ensureHermesOpportunitySequencesCron,
71
71
  ensureHermesSnapshotCron,
72
72
  markHermesSnapshotDirty,
73
73
  mergeHermesState,
74
74
  migrateLegacyHermesUserState,
75
- quarantineLegacyLightfieldVenv,
76
75
  reconcileHermesSnapshot,
77
76
  restoreLatestHermesSnapshot,
78
77
  } from "../hermes-memory-snapshot.mjs";
@@ -695,6 +694,10 @@ const ADMIN_LIVE_SKILLS_CONFIG_KEYS = Object.freeze([
695
694
  "disabled",
696
695
  "platform_disabled",
697
696
  ]);
697
+ const ADMIN_SEALED_SKILL_DIRECTORIES = new Set([
698
+ "sellable",
699
+ "opportunity-sequences",
700
+ ]);
698
701
 
699
702
  function adminPreservedSlackToolsets(config) {
700
703
  const platformToolsets = config?.platform_toolsets;
@@ -724,7 +727,7 @@ function adminPreservedSkillsIdentity(profileRoot) {
724
727
  const walk = (directory, relativePath = "") => {
725
728
  for (const name of readdirSync(directory).sort()) {
726
729
  const nextRelative = relativePath ? `${relativePath}/${name}` : name;
727
- if (nextRelative === "sellable") continue;
730
+ if (ADMIN_SEALED_SKILL_DIRECTORIES.has(nextRelative)) continue;
728
731
  const path = join(directory, name);
729
732
  const stat = lstatSync(path);
730
733
  if (stat.isSymbolicLink()) {
@@ -1031,12 +1034,22 @@ async function materializeAdminProfile({
1031
1034
  hermesCli: HERMES,
1032
1035
  });
1033
1036
  if (!memoryCron.ok) throw new Error(memoryCron.code);
1037
+ const opportunitySequencesCron = await ensureHermesOpportunitySequencesCron({
1038
+ profileId: profile,
1039
+ profileRoot: profileHome,
1040
+ hermesRoot: DATA_ROOT,
1041
+ statePath: layout.statePath,
1042
+ });
1043
+ if (!opportunitySequencesCron.ok) {
1044
+ throw new Error(opportunitySequencesCron.code);
1045
+ }
1034
1046
  return {
1035
1047
  stage,
1036
1048
  promotion: promoted.promotion,
1037
1049
  profile,
1038
1050
  profileHome,
1039
1051
  adminHome,
1052
+ opportunitySequencesCron,
1040
1053
  observedSoulRawSha256: promoted.observedSoulRawSha256,
1041
1054
  servers: [serverProofs.sellable, serverProofs["sellable-admin"]].map(
1042
1055
  ({ tools: _tools, ...proof }) => proof
@@ -1187,70 +1200,6 @@ function operationIdentity(claim, exchange) {
1187
1200
  };
1188
1201
  }
1189
1202
 
1190
- function operationSnapshotIdentity(claim, exchange) {
1191
- const authority = claim?.runtimeAuthority;
1192
- if (!authority) return undefined;
1193
- return {
1194
- operationId: claim.operation.id,
1195
- authorityGeneration: authority.authorityGeneration,
1196
- runtimeArtifactId: authority.assignedRuntimeArtifactId,
1197
- sourceMachineId: exchange.workerId,
1198
- sourceMachineVersion: authority.machineVersion,
1199
- sourceBootSessionId: BOOT_SESSION_ID,
1200
- profileSchemaVersion: "admin-native-profile/v2",
1201
- };
1202
- }
1203
-
1204
- function adminServingObservation(activeLaunch, activeGateway, exchange) {
1205
- try {
1206
- const authority = activeLaunch?.claim?.runtimeAuthority;
1207
- const running =
1208
- activeGateway?.child?.exitCode === null && !activeGateway.child.killed;
1209
- const productMcp = activeLaunch?.profile?.servers?.find(
1210
- (server) => server.alias === "sellable"
1211
- );
1212
- const adminMcp = activeLaunch?.profile?.servers?.find(
1213
- (server) => server.alias === "sellable-admin"
1214
- );
1215
- if (!authority || !running || !activeLaunch.slackProof) return null;
1216
- const observedAt = new Date();
1217
- return buildRuntimeServingObservation({
1218
- scope: authority.scope,
1219
- kind: "ADMIN",
1220
- operationId: activeLaunch.claim.operation.id,
1221
- workspaceId: activeLaunch.claim.operation.workspaceId,
1222
- agentId: activeLaunch.claim.operation.agentId,
1223
- runtimeId: authority.runtimeId,
1224
- authorityGeneration: authority.authorityGeneration,
1225
- runtimeArtifactId: authority.runtimeArtifactId,
1226
- machineId: exchange.workerId,
1227
- machineVersion: authority.machineVersion,
1228
- bootSessionId: BOOT_SESSION_ID,
1229
- profileIdentity: activeLaunch.profile.profile,
1230
- processIdentity: `gateway-${activeGateway.child.pid}-${activeLaunch.claim.operation.fence}`,
1231
- observedAt: observedAt.toISOString(),
1232
- expiresAt: new Date(observedAt.getTime() + 120_000).toISOString(),
1233
- slack: {
1234
- authenticated: true,
1235
- socketModeConnected: true,
1236
- apiReachable: true,
1237
- },
1238
- productMcp: {
1239
- serverInfoName: productMcp?.serverInfoName,
1240
- toolCount: productMcp?.toolCount,
1241
- },
1242
- adminMcp: {
1243
- serverInfoName: adminMcp?.serverInfoName,
1244
- toolCount: adminMcp?.toolCount,
1245
- },
1246
- nativeGateway: true,
1247
- customerRouting: false,
1248
- });
1249
- } catch {
1250
- return null;
1251
- }
1252
- }
1253
-
1254
1203
  function startOperationHeartbeat({ claim, exchange, client }) {
1255
1204
  const identity = operationIdentity(claim, exchange);
1256
1205
  let stopped = false;
@@ -1759,42 +1708,6 @@ function nativeSlackProfileInput(claim, installed) {
1759
1708
  };
1760
1709
  }
1761
1710
 
1762
- async function proveAdminSlackServing(claim, secrets) {
1763
- const slack = claim.runtimeContract?.slack;
1764
- if (!slack) throw new Error("admin_runtime_slack_contract_rejected");
1765
- const post = (method, token) =>
1766
- fetch(`https://slack.com/api/${method}`, {
1767
- method: "POST",
1768
- headers: {
1769
- authorization: `Bearer ${token}`,
1770
- "content-type": "application/x-www-form-urlencoded",
1771
- },
1772
- body: "",
1773
- signal: AbortSignal.timeout(15_000),
1774
- });
1775
- const [authResponse, socketResponse] = await Promise.all([
1776
- post("auth.test", secrets.slackBot),
1777
- post("apps.connections.open", secrets.slackApp),
1778
- ]);
1779
- const [auth, socket] = await Promise.all([
1780
- authResponse.json(),
1781
- socketResponse.json(),
1782
- ]);
1783
- if (
1784
- !authResponse.ok ||
1785
- auth?.ok !== true ||
1786
- auth.team_id !== slack.teamId ||
1787
- auth.user_id !== slack.botUserId ||
1788
- !socketResponse.ok ||
1789
- socket?.ok !== true ||
1790
- typeof socket.url !== "string" ||
1791
- !/^wss:\/\//.test(socket.url)
1792
- ) {
1793
- throw new Error("admin_runtime_slack_serving_rejected");
1794
- }
1795
- return true;
1796
- }
1797
-
1798
1711
  async function fetchDeliveryCiphertext({
1799
1712
  operation,
1800
1713
  identity,
@@ -2351,12 +2264,7 @@ function completionReceipt({
2351
2264
  };
2352
2265
  }
2353
2266
 
2354
- async function flushHermesSnapshot({
2355
- client,
2356
- profileId,
2357
- profileRoot,
2358
- operationIdentity,
2359
- }) {
2267
+ async function flushHermesSnapshot({ client, profileId, profileRoot }) {
2360
2268
  try {
2361
2269
  markHermesSnapshotDirty(profileRoot);
2362
2270
  return await reconcileHermesSnapshot({
@@ -2365,24 +2273,13 @@ async function flushHermesSnapshot({
2365
2273
  hermesRoot: DATA_ROOT,
2366
2274
  hermesVersion: "0.20.0",
2367
2275
  debounceMs: 0,
2368
- operationIdentity,
2369
- upload: ({
2370
- archiveDigest,
2371
- archiveBytes,
2372
- sourceProfileId,
2373
- bytes,
2374
- ok: _ok,
2375
- status: _status,
2376
- hermesVersion: _hermesVersion,
2377
- ...v2
2378
- }) =>
2276
+ upload: ({ archiveDigest, archiveBytes, sourceProfileId, bytes }) =>
2379
2277
  client.putMemorySnapshot(
2380
2278
  {
2381
2279
  archiveDigest,
2382
2280
  archiveBytes,
2383
2281
  hermesVersion: "0.20.0",
2384
2282
  sourceProfileId,
2385
- ...v2,
2386
2283
  },
2387
2284
  bytes
2388
2285
  ),
@@ -3095,11 +2992,6 @@ async function runAdminProduction() {
3095
2992
  callerProfileId: activeLaunch.profile.profile,
3096
2993
  }),
3097
2994
  leaseSeconds: 60,
3098
- servingObservation: adminServingObservation(
3099
- activeLaunch,
3100
- activeGateway,
3101
- exchange
3102
- ),
3103
2995
  })
3104
2996
  : await client.claim(60);
3105
2997
  } catch (error) {
@@ -3169,6 +3061,16 @@ async function runAdminProduction() {
3169
3061
  ),
3170
3062
  });
3171
3063
  }
3064
+ if (
3065
+ activeLaunch &&
3066
+ (!activeGateway ||
3067
+ activeGateway.child.exitCode !== null ||
3068
+ activeGateway.child.killed)
3069
+ ) {
3070
+ await sleep(Math.min(30_000, 500 * 2 ** Math.min(failures, 6)));
3071
+ activeGateway = await startNativeGateway(activeLaunch);
3072
+ failures = 0;
3073
+ }
3172
3074
  await sleep(1_000);
3173
3075
  continue;
3174
3076
  }
@@ -3280,14 +3182,6 @@ async function runAdminProduction() {
3280
3182
  fetchLatest: () => client.getMemorySnapshot(),
3281
3183
  });
3282
3184
  if (!memoryRestore.ok) throw new Error(memoryRestore.code);
3283
- const legacyLightfieldVenv = quarantineLegacyLightfieldVenv({
3284
- profileId: basename(profileContract.profileHome),
3285
- profileRoot: profileContract.profileHome,
3286
- hermesRoot: DATA_ROOT,
3287
- });
3288
- if (!legacyLightfieldVenv.ok) {
3289
- throw new Error(legacyLightfieldVenv.code);
3290
- }
3291
3185
  const legacyUserState = migrateLegacyHermesUserState({
3292
3186
  profileId: basename(profileContract.profileHome),
3293
3187
  profileRoot: profileContract.profileHome,
@@ -3320,7 +3214,6 @@ async function runAdminProduction() {
3320
3214
  client,
3321
3215
  profileId: profile.profile,
3322
3216
  profileRoot: profile.profileHome,
3323
- operationIdentity: operationSnapshotIdentity(claim, exchange),
3324
3217
  });
3325
3218
  const settings = settingsProof(
3326
3219
  imported.receipt.generationRoot,
@@ -3355,14 +3248,8 @@ async function runAdminProduction() {
3355
3248
  modelAuth,
3356
3249
  });
3357
3250
  operationHeartbeat.assertHealthy();
3358
- const slackProof =
3359
- desiredLifecycle === "ON"
3360
- ? await proveAdminSlackServing(claim, secrets)
3361
- : false;
3362
3251
  const candidateLaunch =
3363
- desiredLifecycle === "ON"
3364
- ? { profile, claim, installed, slackProof }
3365
- : null;
3252
+ desiredLifecycle === "ON" ? { profile, claim, installed } : null;
3366
3253
  let candidateGateway = null;
3367
3254
  try {
3368
3255
  if (candidateLaunch) {
@@ -4,9 +4,9 @@ FROM ${HERMES_IMAGE}
4
4
 
5
5
  USER root
6
6
 
7
- ARG MCP_PACKAGE=@sellable/mcp@0.1.865
8
- ARG MCP_INTEGRITY=sha512-282pkYFADFrrIXyQcdUpQwakXiwe/AFUDpDZkTh29CFcGHnN7dvC0MCvaU4LffXA+ZuKCpuf02uxCLGiIEOjbw==
9
- ARG INSTALLER_PACKAGE=@sellable/install@0.1.612-wip.phase189.20260812.2
7
+ ARG MCP_PACKAGE=@sellable/mcp@0.1.867
8
+ ARG MCP_INTEGRITY=sha512-8acJ5MfqgXiu9ylK65LlQ7LUBN5GN5fEXOwDTArxYAN7nBvVLhdz0nTGMERc6qCFNBbILTKvo4IErJOnAcJTDA==
9
+ ARG INSTALLER_PACKAGE=@sellable/install@0.1.612
10
10
  ARG ADMIN_MCP_PACKAGE=@sellable/admin-mcp@0.1.186-wip.phase158.20260802034727
11
11
  ARG ADMIN_MCP_INTEGRITY=sha512-qYNew5wd2IfgVcp1UYOG9QvpF/8Mx19YJ5HQtMKzvSfUf3evePjtaKsoXLf2C/GUJ5QlLlHJo84VWOI3V01+9A==
12
12
  ARG TUS_JS_CLIENT_VERSION=4.3.1
@@ -96,9 +96,9 @@ const RUNTIME_GENERATION = Number(
96
96
  const BOOT_SESSION_ID = randomUUID();
97
97
  const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.20.0";
98
98
  const INSTALLER_PACKAGE =
99
- process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.612-wip.phase189.20260812.2";
99
+ process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.612";
100
100
  const MCP_PACKAGE =
101
- process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.865";
101
+ process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.867";
102
102
 
103
103
  const sha256 = (value) => createHash("sha256").update(value).digest("hex");
104
104
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -32,77 +32,6 @@ function stableJson(value) {
32
32
  return JSON.stringify(value);
33
33
  }
34
34
 
35
- // CUSTOMER and ADMIN runtimes share this one serving-observation builder.
36
- export function buildRuntimeServingObservation(input = {}) {
37
- const keys = [
38
- "scope",
39
- "kind",
40
- "operationId",
41
- "workspaceId",
42
- "agentId",
43
- "runtimeId",
44
- "authorityGeneration",
45
- "runtimeArtifactId",
46
- "machineId",
47
- "machineVersion",
48
- "bootSessionId",
49
- "profileIdentity",
50
- "processIdentity",
51
- "observedAt",
52
- "expiresAt",
53
- "slack",
54
- "productMcp",
55
- "adminMcp",
56
- "nativeGateway",
57
- "customerRouting",
58
- ];
59
- const identity = (value) =>
60
- typeof value === "string" && SAFE_ID.test(value);
61
- const mcp = (value, name, tools) =>
62
- exactKeys(value, ["serverInfoName", "toolCount"]) &&
63
- value.serverInfoName === name &&
64
- value.toolCount === tools;
65
- const observedAt = Date.parse(input.observedAt ?? "");
66
- const expiresAt = Date.parse(input.expiresAt ?? "");
67
- const kindExact =
68
- input.kind === "CUSTOMER"
69
- ? input.adminMcp === null && input.customerRouting === true
70
- : input.kind === "ADMIN" &&
71
- mcp(input.adminMcp, "sellable-admin-mcp", 46) &&
72
- input.customerRouting === false;
73
- if (
74
- !exactKeys(input, keys) ||
75
- !["ASSIGNED", "CANDIDATE"].includes(input.scope) ||
76
- !keys
77
- .slice(2, 13)
78
- .filter((key) => key !== "authorityGeneration")
79
- .every((key) => identity(input[key])) ||
80
- !Number.isSafeInteger(input.authorityGeneration) ||
81
- input.authorityGeneration < 1 ||
82
- !Number.isFinite(observedAt) ||
83
- !Number.isFinite(expiresAt) ||
84
- expiresAt <= observedAt ||
85
- expiresAt - observedAt > 5 * 60_000 ||
86
- !exactKeys(input.slack, [
87
- "authenticated",
88
- "socketModeConnected",
89
- "apiReachable",
90
- ]) ||
91
- input.slack.authenticated !== true ||
92
- input.slack.socketModeConnected !== true ||
93
- input.slack.apiReachable !== true ||
94
- !mcp(input.productMcp, "sellable-mcp", 193) ||
95
- input.nativeGateway !== true ||
96
- !kindExact
97
- ) {
98
- throw new Error("runtime_serving_observation_rejected");
99
- }
100
- return Object.freeze({
101
- schemaVersion: "sellable-agent-serving-observation/v2",
102
- ...input,
103
- });
104
- }
105
-
106
35
  export function buildAgentServiceEnvironment({
107
36
  workspaceId,
108
37
  agentId,
@@ -541,7 +541,7 @@ function tusUploadAccepted(value) {
541
541
  value.signedUploadToken.length <= 16_384 &&
542
542
  !/\s/.test(value.signedUploadToken) &&
543
543
  value.bucketName === "agent-hermes-backups-v1" &&
544
- /^workspaces\/[A-Za-z0-9_-]{1,128}\/(?:(?:customer|admin)\/archives|agents\/[A-Za-z0-9_-]{1,128}\/operations\/[A-Za-z0-9_-]{1,128})\/[a-f0-9]{64}\.zip$/.test(
544
+ /^workspaces\/[A-Za-z0-9_-]{1,128}\/(?:customer|admin)\/archives\/[a-f0-9]{64}\.zip$/.test(
545
545
  value?.objectName ?? ""
546
546
  )
547
547
  );
@@ -784,7 +784,6 @@ export async function claimWithSoulObservation({
784
784
  tracker,
785
785
  readSoul,
786
786
  leaseSeconds = 60,
787
- servingObservation = /** @type {any} */ (null),
788
787
  }) {
789
788
  // Deliver lifecycle work before any potentially slow local loader proof.
790
789
  // Reconciliation uses the same cadence only after the server confirms that
@@ -792,7 +791,6 @@ export async function claimWithSoulObservation({
792
791
  const tick = await client.claimTick({
793
792
  leaseSeconds,
794
793
  soulObservation: tracker.pending(),
795
- ...(servingObservation ? { servingObservation } : {}),
796
794
  });
797
795
  if (tick?.claim) return tick.claim;
798
796
 
@@ -960,9 +958,9 @@ export function createFlyCustomerControlClient({
960
958
  }
961
959
  }
962
960
  };
963
- const memorySnapshotControl = async (method, body, verb, search = "") => {
961
+ const memorySnapshotControl = async (method, body, verb) => {
964
962
  const response = await fetchImpl(
965
- `${endpoint}/api/v3/sellable-agent/worker/memory-snapshot${search}`,
963
+ `${endpoint}/api/v3/sellable-agent/worker/memory-snapshot`,
966
964
  {
967
965
  method,
968
966
  headers: {
@@ -990,37 +988,6 @@ export function createFlyCustomerControlClient({
990
988
  value.archiveBytes <= 128 * 1024 * 1024 &&
991
989
  value.hermesVersion === "0.20.0" &&
992
990
  /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(value?.sourceProfileId ?? "");
993
- const boundedSnapshotIdentity = (value) =>
994
- /^[A-Za-z0-9][A-Za-z0-9_./:-]{0,255}$/.test(value ?? "");
995
- const metadataV2Accepted = (value) =>
996
- metadataAccepted(value) &&
997
- Object.keys(value).sort().join(",") ===
998
- "archiveBytes,archiveDigest,authorityGeneration,hermesVersion,operationId,profileSchemaVersion,runtimeArtifactId,sourceBootSessionId,sourceMachineId,sourceMachineVersion,sourceProfileId" &&
999
- boundedSnapshotIdentity(value.operationId) &&
1000
- Number.isSafeInteger(value.authorityGeneration) &&
1001
- value.authorityGeneration > 0 &&
1002
- boundedSnapshotIdentity(value.runtimeArtifactId) &&
1003
- boundedSnapshotIdentity(value.profileSchemaVersion) &&
1004
- [
1005
- value.sourceMachineId,
1006
- value.sourceMachineVersion,
1007
- value.sourceBootSessionId,
1008
- ].every(
1009
- (identityValue) =>
1010
- identityValue === null || boundedSnapshotIdentity(identityValue)
1011
- );
1012
- const snapshotReadbackExpected = (value) =>
1013
- value &&
1014
- typeof value === "object" &&
1015
- !Array.isArray(value) &&
1016
- Object.keys(value).sort().join(",") ===
1017
- "authorityGeneration,operationId,profileSchemaVersion,runtimeArtifactId,sourceProfileId" &&
1018
- boundedSnapshotIdentity(value.operationId) &&
1019
- Number.isSafeInteger(value.authorityGeneration) &&
1020
- value.authorityGeneration > 0 &&
1021
- boundedSnapshotIdentity(value.runtimeArtifactId) &&
1022
- /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(value.sourceProfileId ?? "") &&
1023
- boundedSnapshotIdentity(value.profileSchemaVersion);
1024
991
  const signedUrlAccepted = (value) => {
1025
992
  try {
1026
993
  return new URL(value).protocol === "https:";
@@ -1029,9 +996,8 @@ export function createFlyCustomerControlClient({
1029
996
  }
1030
997
  };
1031
998
  const putMemorySnapshot = async (metadata, archive) => {
1032
- const isV2 = Object.hasOwn(metadata ?? {}, "operationId");
1033
999
  if (
1034
- !(isV2 ? metadataV2Accepted(metadata) : metadataAccepted(metadata)) ||
1000
+ !metadataAccepted(metadata) ||
1035
1001
  !Buffer.isBuffer(archive) ||
1036
1002
  metadata.archiveBytes !== archive.byteLength ||
1037
1003
  createHash("sha256").update(archive).digest("hex") !==
@@ -1043,20 +1009,14 @@ export function createFlyCustomerControlClient({
1043
1009
  const value = await memorySnapshotControl(
1044
1010
  "PUT",
1045
1011
  {
1046
- schemaVersion: isV2
1047
- ? "sellable-hermes-snapshot-upload/v2"
1048
- : "sellable-hermes-snapshot-upload/v1",
1012
+ schemaVersion: "sellable-hermes-snapshot-upload/v1",
1049
1013
  ...metadata,
1050
1014
  },
1051
1015
  "memory-snapshot-put"
1052
1016
  );
1053
1017
  if (
1054
1018
  !tusUploadAccepted(value) ||
1055
- !value.objectName.endsWith(
1056
- isV2
1057
- ? `/operations/${metadata.operationId}/${metadata.archiveDigest}.zip`
1058
- : `/${metadata.archiveDigest}.zip`
1059
- )
1019
+ !value.objectName.endsWith(`/${metadata.archiveDigest}.zip`)
1060
1020
  ) {
1061
1021
  throw new WorkerControlResponseError(
1062
1022
  "memory_snapshot_upload_url_rejected"
@@ -1074,9 +1034,7 @@ export function createFlyCustomerControlClient({
1074
1034
  const committed = await memorySnapshotControl(
1075
1035
  "POST",
1076
1036
  {
1077
- schemaVersion: isV2
1078
- ? "sellable-hermes-snapshot-commit/v2"
1079
- : "sellable-hermes-snapshot-commit/v1",
1037
+ schemaVersion: "sellable-hermes-snapshot-commit/v1",
1080
1038
  ...metadata,
1081
1039
  },
1082
1040
  "memory-snapshot-put"
@@ -1089,42 +1047,14 @@ export function createFlyCustomerControlClient({
1089
1047
  }
1090
1048
  return committed;
1091
1049
  };
1092
- const getMemorySnapshot = async (expected) => {
1093
- const isV2 = expected !== undefined;
1094
- if (isV2 && !snapshotReadbackExpected(expected)) {
1095
- throw new WorkerControlResponseError("memory_snapshot_download_rejected");
1096
- }
1097
- const body = isV2
1098
- ? {
1099
- schemaVersion: "sellable-hermes-snapshot-get/v2",
1100
- operationId: expected.operationId,
1101
- }
1102
- : { schemaVersion: "sellable-hermes-snapshot-get/v1" };
1103
- const search = isV2
1104
- ? `?${new URLSearchParams(body).toString()}`
1105
- : "";
1050
+ const getMemorySnapshot = async () => {
1106
1051
  const result = await memorySnapshotControl(
1107
1052
  "GET",
1108
- body,
1109
- "memory-snapshot-get",
1110
- search
1053
+ { schemaVersion: "sellable-hermes-snapshot-get/v1" },
1054
+ "memory-snapshot-get"
1111
1055
  );
1112
1056
  if (!result) return null;
1113
- const identityReadbackAccepted =
1114
- !isV2 ||
1115
- (result.operationId === expected.operationId &&
1116
- result.authorityGeneration === expected.authorityGeneration &&
1117
- result.runtimeArtifactId === expected.runtimeArtifactId &&
1118
- result.sourceProfileId === expected.sourceProfileId &&
1119
- result.profileSchemaVersion === expected.profileSchemaVersion &&
1120
- /^[a-f0-9]{64}$/.test(result.archiveDigest ?? "") &&
1121
- Number.isSafeInteger(result.archiveBytes) &&
1122
- result.archiveBytes > 0 &&
1123
- result.archiveBytes <= 128 * 1024 * 1024);
1124
- if (
1125
- !(isV2 ? identityReadbackAccepted : metadataAccepted(result)) ||
1126
- !signedUrlAccepted(result.signedUrl)
1127
- ) {
1057
+ if (!metadataAccepted(result) || !signedUrlAccepted(result.signedUrl)) {
1128
1058
  throw new WorkerControlResponseError(
1129
1059
  "memory_snapshot_download_url_rejected"
1130
1060
  );
@@ -1144,15 +1074,10 @@ export function createFlyCustomerControlClient({
1144
1074
  }
1145
1075
  return { ...result, signedUrl: undefined, bytes };
1146
1076
  };
1147
- const claimTick = async ({
1148
- leaseSeconds = 60,
1149
- soulObservation,
1150
- servingObservation,
1151
- } = {}) =>
1077
+ const claimTick = async ({ leaseSeconds = 60, soulObservation } = {}) =>
1152
1078
  post("claim", "/api/v3/sellable-agent/worker/claim", {
1153
1079
  leaseSeconds,
1154
1080
  ...(soulObservation ? { soulObservation } : {}),
1155
- ...(servingObservation ? { servingObservation } : {}),
1156
1081
  });
1157
1082
  return Object.freeze({
1158
1083
  claimTick,
@@ -1228,8 +1153,8 @@ export function createFlyCustomerControlClient({
1228
1153
  async putMemorySnapshot(metadata, archive) {
1229
1154
  return putMemorySnapshot(metadata, archive);
1230
1155
  },
1231
- async getMemorySnapshot(expected) {
1232
- return getMemorySnapshot(expected);
1156
+ async getMemorySnapshot() {
1157
+ return getMemorySnapshot();
1233
1158
  },
1234
1159
  });
1235
1160
  }