@sellable/install 0.1.766 → 0.1.768-wip.hermes-20260925.4

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,12 +3,12 @@ FROM ${HERMES_IMAGE}
3
3
 
4
4
  USER root
5
5
 
6
- ARG INSTALLER_PACKAGE=@sellable/install@0.1.766
6
+ ARG INSTALLER_PACKAGE=@sellable/install@0.1.768-wip.hermes-20260925.4
7
7
  ARG MCP_PACKAGE=@sellable/mcp@0.1.941
8
8
  ARG INSTALLER_INTEGRITY
9
9
  ARG MCP_INTEGRITY=sha512-Dhi+r50kwZa0E6iskB7dmDM/kCe9woEExLXxfLg8jf9LSKj86V5AiC0jhpS7euoo/lvY5e9m2a0BlTV9wqFxRQ==
10
10
 
11
- RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.766" \
11
+ RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.768-wip.hermes-20260925.4" \
12
12
  && test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.941" \
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.766" \
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.766' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.941') 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.768-wip.hermes-20260925.4' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.941') 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.766', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.941', 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.768-wip.hermes-20260925.4', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.941', 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,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.766` is
6
+ `@sellable/install@0.1.768-wip.hermes-20260925.4` is
7
7
  published:
8
8
 
9
9
  ```sh
@@ -1,5 +1,5 @@
1
1
  # syntax=docker/dockerfile:1.7
2
- ARG HERMES_IMAGE=nousresearch/hermes-agent@sha256:1f983df4d778d46b3c3892d7598c9d57291430a6e35936ebc371ae1e5766699a
2
+ ARG HERMES_IMAGE=nousresearch/hermes-agent@sha256:fca358f12efd65bfaaca05884166f15c0e2788375ca30d77061ac1ebc96452b7
3
3
  ARG SLACK_PP_GO_IMAGE=golang@sha256:386d475a660466863d9f8c766fec64d7fdad3edac2c6a05020c09534d71edb4b
4
4
 
5
5
  FROM ${SLACK_PP_GO_IMAGE} AS slack-pp-cli-builder
@@ -37,8 +37,8 @@ ARG MCP_TRUST_ROOT_FINGERPRINT
37
37
  ARG TUS_JS_CLIENT_VERSION=4.3.1
38
38
  ARG YAML_VERSION=2.9.0
39
39
  ARG AGENT_BROWSER_VERSION=0.26.0
40
- ARG PLAYWRIGHT_VERSION=1.62.1
41
- ARG PLAYWRIGHT_BROWSER_REVISION=1234
40
+ ARG PLAYWRIGHT_VERSION=1.63.0
41
+ ARG PLAYWRIGHT_BROWSER_REVISION=1243
42
42
  ARG STRIPE_CLI_PACKAGE=@stripe/cli-linux-x64@1.45.0
43
43
  ARG STRIPE_CLI_INTEGRITY=sha512-1ZhoPpoweYfynqsvhCLlTjZ7lPz5IKtxqAMT5MBy6zrwLRTP9x0T6r8h/jLYL8lRH1c7zC/6X6/XUu2V+r9Bog==
44
44
  ARG DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION=1
@@ -217,7 +217,7 @@ RUN set -eux; \
217
217
  'const fs=require("fs"); const manifest=JSON.parse(fs.readFileSync("/usr/local/share/sellable-agent/default-profile-bundle/manifest.json")); if(String(manifest.bundleVersion)!==process.argv[1] || manifest.bundleDigest!==process.argv[2]) process.exit(1);' \
218
218
  "${DEFAULT_PROFILE_BUNDLE_VERSION}" "${DEFAULT_PROFILE_BUNDLE_DIGEST}" \
219
219
  && node --input-type=module -e \
220
- 'import { installHermesAgentBridge, HERMES_AGENT_BRIDGE_DEDICATED_V0213_CONTRACT } from "/usr/local/lib/sellable-agent/hermes-bridge.mjs"; installHermesAgentBridge({ sourceRoot: "/opt/hermes", contract: HERMES_AGENT_BRIDGE_DEDICATED_V0213_CONTRACT });' \
220
+ 'import { installHermesAgentBridge, HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT } from "/usr/local/lib/sellable-agent/hermes-bridge.mjs"; installHermesAgentBridge({ sourceRoot: "/opt/hermes", contract: HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT });' \
221
221
  && node --input-type=module -e \
222
222
  'await import("/usr/local/lib/sellable-agent/fly-runtime-identity.mjs");' \
223
223
  && node --input-type=module -e \
@@ -92,7 +92,7 @@ import {
92
92
  ensureHermesOpportunitySequencesCron,
93
93
  ensureHermesSnapshotCron,
94
94
  markHermesSnapshotDirty,
95
- mergeHermesState,
95
+ linkHermesState,
96
96
  migrateLegacyHermesUserState,
97
97
  quarantineLegacyLightfieldVenv,
98
98
  reconcileHermesSnapshot,
@@ -1326,7 +1326,10 @@ async function materializeAdminProfile({
1326
1326
  }
1327
1327
  );
1328
1328
  }
1329
- mergeHermesState(profileHome, stageRoot, {
1329
+ // The gateway and endpoint relay are stopped before materialization.
1330
+ // Reuse durable inodes on this volume, as Customer profiles do, so a
1331
+ // large conversation DB cannot exhaust disk during an upgrade.
1332
+ linkHermesState(profileHome, stageRoot, {
1330
1333
  skipSourceTopLevelNames:
1331
1334
  liveSkillsIdentity === null ? [] : ["skills"],
1332
1335
  });
@@ -2943,7 +2946,7 @@ async function flushHermesSnapshot({
2943
2946
  profileId,
2944
2947
  profileRoot,
2945
2948
  hermesRoot: DATA_ROOT,
2946
- hermesVersion: "0.21.3",
2949
+ hermesVersion: "0.21.5",
2947
2950
  debounceMs: 0,
2948
2951
  operationIdentity,
2949
2952
  upload: ({
@@ -2960,7 +2963,7 @@ async function flushHermesSnapshot({
2960
2963
  {
2961
2964
  archiveDigest,
2962
2965
  archiveBytes,
2963
- hermesVersion: "0.21.3",
2966
+ hermesVersion: "0.21.5",
2964
2967
  sourceProfileId,
2965
2968
  ...v2,
2966
2969
  },
@@ -3939,13 +3942,13 @@ async function runAdminProduction() {
3939
3942
  profileId: activeLaunch.profile.profile,
3940
3943
  profileRoot: activeLaunch.profile.profileHome,
3941
3944
  hermesRoot: DATA_ROOT,
3942
- hermesVersion: "0.21.3",
3945
+ hermesVersion: "0.21.5",
3943
3946
  upload: ({ archiveDigest, archiveBytes, sourceProfileId, bytes }) =>
3944
3947
  client.putMemorySnapshot(
3945
3948
  {
3946
3949
  archiveDigest,
3947
3950
  archiveBytes,
3948
- hermesVersion: "0.21.3",
3951
+ hermesVersion: "0.21.5",
3949
3952
  sourceProfileId,
3950
3953
  },
3951
3954
  bytes
@@ -4115,7 +4118,7 @@ async function runAdminProduction() {
4115
4118
  profileId: basename(profileContract.profileHome),
4116
4119
  profileRoot: profileContract.profileHome,
4117
4120
  hermesRoot: DATA_ROOT,
4118
- hermesVersion: "0.21.3",
4121
+ hermesVersion: "0.21.5",
4119
4122
  fetchLatest: () => client.getMemorySnapshot(),
4120
4123
  })
4121
4124
  );
@@ -1,5 +1,5 @@
1
1
  # syntax=docker/dockerfile:1.7
2
- ARG HERMES_IMAGE=nousresearch/hermes-agent@sha256:1f983df4d778d46b3c3892d7598c9d57291430a6e35936ebc371ae1e5766699a
2
+ ARG HERMES_IMAGE=nousresearch/hermes-agent@sha256:fca358f12efd65bfaaca05884166f15c0e2788375ca30d77061ac1ebc96452b7
3
3
  FROM ${HERMES_IMAGE}
4
4
 
5
5
  USER root
@@ -8,16 +8,16 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright
8
8
 
9
9
  ARG MCP_PACKAGE=@sellable/mcp@0.1.941
10
10
  ARG MCP_INTEGRITY=sha512-Dhi+r50kwZa0E6iskB7dmDM/kCe9woEExLXxfLg8jf9LSKj86V5AiC0jhpS7euoo/lvY5e9m2a0BlTV9wqFxRQ==
11
- ARG INSTALLER_PACKAGE=@sellable/install@0.1.766
11
+ ARG INSTALLER_PACKAGE=@sellable/install@0.1.768-wip.hermes-20260925.4
12
12
  ARG ADMIN_MCP_PACKAGE=@sellable/admin-mcp@0.1.202
13
13
  ARG ADMIN_MCP_INTEGRITY=sha512-ym3aye/0vQ8tfULJlKz9JFOxvIQsl1G+n3np+TTgK/tecwNblBo/j3AkTnRqH9iomKzPbZzP+n4tEQsvsU8ByA==
14
14
  ARG TUS_JS_CLIENT_VERSION=4.3.1
15
15
  ARG YAML_VERSION=2.9.0
16
- ARG HERMES_VERSION=0.21.3
16
+ ARG HERMES_VERSION=0.21.5
17
17
  ARG AGENT_BROWSER_VERSION=0.26.0
18
18
  ARG TIRITH_VERSION=0.3.3
19
- ARG PLAYWRIGHT_VERSION=1.62.1
20
- ARG PLAYWRIGHT_BROWSER_REVISION=1234
19
+ ARG PLAYWRIGHT_VERSION=1.63.0
20
+ ARG PLAYWRIGHT_BROWSER_REVISION=1243
21
21
  ARG TIRITH_ARCHIVE_SHA256=6cdbe35e8f9ccf42e70ad95b501c93cd218ac18201c3df958d54f6ba0d995ce2
22
22
  ARG DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION=1
23
23
  ARG DEFAULT_PROFILE_BUNDLE_VERSION=4
@@ -114,7 +114,7 @@ RUN set -eux; \
114
114
  'const fs=require("fs"); const manifest=JSON.parse(fs.readFileSync("/usr/local/share/sellable-agent/default-profile-bundle/manifest.json")); if(String(manifest.bundleVersion)!==process.argv[1] || manifest.bundleDigest!==process.argv[2]) process.exit(1);' \
115
115
  "${DEFAULT_PROFILE_BUNDLE_VERSION}" "${DEFAULT_PROFILE_BUNDLE_DIGEST}" \
116
116
  && node --input-type=module -e \
117
- 'import { installHermesAgentBridge, HERMES_AGENT_BRIDGE_DEDICATED_V0213_CONTRACT } from "/usr/local/lib/sellable-agent/hermes-bridge.mjs"; installHermesAgentBridge({ sourceRoot: "/opt/hermes", contract: HERMES_AGENT_BRIDGE_DEDICATED_V0213_CONTRACT });' \
117
+ 'import { installHermesAgentBridge, HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT } from "/usr/local/lib/sellable-agent/hermes-bridge.mjs"; installHermesAgentBridge({ sourceRoot: "/opt/hermes", contract: HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT });' \
118
118
  && node --input-type=module -e \
119
119
  'await import("/usr/local/lib/sellable-agent/fly-runtime-identity.mjs");' \
120
120
  && node --input-type=module -e \
@@ -120,9 +120,9 @@ const RUNTIME_GENERATION = Number(
120
120
  "0"
121
121
  );
122
122
  const BOOT_SESSION_ID = randomUUID();
123
- const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.21.3";
123
+ const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.21.5";
124
124
  const INSTALLER_PACKAGE =
125
- process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.766";
125
+ process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.768-wip.hermes-20260925.4";
126
126
  const MCP_PACKAGE =
127
127
  process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.941";
128
128
  export const ENDPOINT_MAX_CONCURRENT_RUNS = 10;
@@ -331,12 +331,18 @@ export function customerRuntimeDoctorFailureCode(
331
331
 
332
332
  /**
333
333
  * @param {string} action
334
- * @param {{ runtimeAuthorityScope?: "ASSIGNED" | "CANDIDATE" | null }} [options]
334
+ * @param {{ runtimeAuthorityScope?: "ASSIGNED" | "CANDIDATE" | null, directReadinessProven?: boolean }} [options]
335
335
  */
336
336
  export function customerRuntimeDoctorRequired(
337
337
  action,
338
- { runtimeAuthorityScope = null } = {}
338
+ { runtimeAuthorityScope = null, directReadinessProven = false } = {}
339
339
  ) {
340
+ // A successful provisioned proof checks the pinned binaries, MCP and model
341
+ // credentials; proveApplication then requires Slack identity/socket and the
342
+ // authenticated native API. Interactive doctor additionally requires a
343
+ // default-profile .env and a ~/.local/bin shim that these containers do not
344
+ // use. Those workstation checks must not reject an otherwise proven restart.
345
+ if (directReadinessProven) return false;
340
346
  // START and candidate promotion already prove the binaries, model auth,
341
347
  // Slack identities, gateway, private API, and native skills directly below.
342
348
  // Keep the broad interactive diagnostic on assigned-runtime REFRESH only;
@@ -3436,6 +3442,7 @@ async function proveApplication({
3436
3442
  const runtimeEnv = applicationRuntimeEnv({ desired, runtimeConfig, secrets });
3437
3443
  const doctor = customerRuntimeDoctorRequired(action, {
3438
3444
  runtimeAuthorityScope,
3445
+ directReadinessProven: true,
3439
3446
  })
3440
3447
  ? await run(HERMES, ["doctor"], {
3441
3448
  env: runtimeEnv,
@@ -14,13 +14,13 @@ const MAX_HISTORY_ITEMS = 64;
14
14
  const MAX_EVENT_BYTES = 128 * 1024;
15
15
  const MAX_CANONICAL_OUTPUT_BYTES = 48 * 1024;
16
16
  const EXACT_FIXTURE_DIGEST =
17
- "22e6371bb6cb13c38cb0fcd5b07c20d6e62fe327141d3420513e5935dede5e97";
17
+ "dc91130958d2d0181843d12b5073aa0df3b36c7d96718e149750aa5f692640ef";
18
18
 
19
19
  export const HERMES_RUNS_FIXTURE_IDENTITY = Object.freeze({
20
20
  schemaVersion: "sellable-hermes-api-capabilities/v1",
21
21
  image:
22
- "nousresearch/hermes-agent@sha256:1f983df4d778d46b3c3892d7598c9d57291430a6e35936ebc371ae1e5766699a",
23
- hermesVersion: "0.21.3",
22
+ "nousresearch/hermes-agent@sha256:fca358f12efd65bfaaca05884166f15c0e2788375ca30d77061ac1ebc96452b7",
23
+ hermesVersion: "0.21.5",
24
24
  fixtureDigest: EXACT_FIXTURE_DIGEST,
25
25
  origin: LOOPBACK_ORIGIN,
26
26
  auth: "bearer",
@@ -80,7 +80,7 @@ function normalizedTimestamp(value) {
80
80
  ) {
81
81
  return value;
82
82
  }
83
- // Hermes 0.21.3's live /v1/runs implementation emits time.time() seconds,
83
+ // Hermes 0.21.5's live /v1/runs implementation emits time.time() seconds,
84
84
  // even though the captured fixture examples use ISO strings. Normalize that
85
85
  // observed wire shape so known tool events do not collapse to UNKNOWN.
86
86
  if (
@@ -559,7 +559,7 @@ export function createHermesRunsClient(options = {}) {
559
559
  throw transportFailure("SUBMIT_AMBIGUOUS", error);
560
560
  }
561
561
  const value = await readBounded(response);
562
- // Hermes 0.21.3 emits 429 for its concurrency limiter and 503 while the
562
+ // Hermes 0.21.5 emits 429 for its concurrency limiter and 503 while the
563
563
  // gateway is draining. Both responses occur before it allocates a run,
564
564
  // so retrying the identical request cannot duplicate a native attempt.
565
565
  if (response.status === 429 || response.status === 503) {
@@ -476,6 +476,12 @@ export function buildNativeHermesLaunch({
476
476
  "gateway",
477
477
  "run",
478
478
  "--replace",
479
+ // Each Fly Machine owns exactly one profile. Sellable supervises this
480
+ // foreground child and its credential descriptors; Hermes 0.21.5 must
481
+ // neither attach it to a host multiplexer nor redirect it to stock s6.
482
+ "--force",
483
+ "--no-supervise",
484
+ "--external-supervisor",
479
485
  ]),
480
486
  cwd: resolvedProfileRoot,
481
487
  env: Object.freeze({
@@ -1086,7 +1086,7 @@ export function createFlyCustomerControlClient({
1086
1086
  Number.isSafeInteger(value?.archiveBytes) &&
1087
1087
  value.archiveBytes > 0 &&
1088
1088
  value.archiveBytes <= 512 * 1024 * 1024 &&
1089
- value.hermesVersion === "0.21.3" &&
1089
+ value.hermesVersion === "0.21.5" &&
1090
1090
  /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(value?.sourceProfileId ?? "");
1091
1091
  const boundedSnapshotIdentity = (value) =>
1092
1092
  /^[A-Za-z0-9][A-Za-z0-9_./:-]{0,255}$/.test(value ?? "");
@@ -751,6 +751,7 @@ def _sellable_agent_call_meta():
751
751
  "HERMES_SESSION_CHAT_ID",
752
752
  "HERMES_SESSION_USER_ID",
753
753
  "HERMES_SESSION_MESSAGE_ID",
754
+ "HERMES_CRON_SESSION",
754
755
  )
755
756
  if any(os.getenv(name) for name in legacy_names):
756
757
  raise RuntimeError("Sellable MCP identity must not come from process-global session variables")
@@ -760,11 +761,9 @@ def _sellable_agent_call_meta():
760
761
  if not session_id:
761
762
  raise RuntimeError("Sellable endpoint MCP calls require a bound Hermes session")
762
763
  return {"sellableEndpoint": {"sessionId": session_id}}
763
- if platform == "cron":
764
- if not session_id:
765
- raise RuntimeError("Sellable cron MCP calls require a bound Hermes session")
766
- # Native scheduled work uses the existing service credential without a
767
- # Slack actor. The serving API still enforces workspace and actor gates.
764
+ if not platform and get_session_env("HERMES_CRON_SESSION", "").strip() == "1":
765
+ # Native _CronRunScope clears human routing and sets this task-local flag
766
+ # (Phase207 ADMIN766 smoke). The API still enforces service/workspace gates.
768
767
  return None
769
768
  if platform != "slack":
770
769
  descriptor_path = os.getenv("SELLABLE_AGENT_TURN_DESCRIPTOR_PATH", "")
@@ -2179,7 +2178,8 @@ def getenv(name, default=""):
2179
2178
 
2180
2179
  if (
2181
2180
  patchKind === "skills-prompt-freshness-v020" ||
2182
- patchKind === "skills-prompt-freshness-v021"
2181
+ patchKind === "skills-prompt-freshness-v021" ||
2182
+ patchKind === "skills-prompt-freshness-v0215"
2183
2183
  ) {
2184
2184
  let patched = replaceExactlyOnce(
2185
2185
  source,
@@ -2226,6 +2226,28 @@ def getenv(name, default=""):
2226
2226
  ].join("\n"),
2227
2227
  "v0.20 prompt live signature"
2228
2228
  );
2229
+ if (patchKind === "skills-prompt-freshness-v0215") {
2230
+ patched = replaceExactlyOnce(
2231
+ patched,
2232
+ " _oneshot_prompt_variant(),\n )\n snapshot = _load_skills_snapshot(skills_dir)",
2233
+ " _oneshot_prompt_variant(),\n live_signature,\n )\n snapshot = _load_skills_snapshot(skills_dir)",
2234
+ "v0.21.5 prompt signature cache key"
2235
+ );
2236
+ // Keep upstream oneshot partitions and app-gated cache bypass intact.
2237
+ return replaceExactlyOnce(
2238
+ patched,
2239
+ " with _SKILLS_PROMPT_CACHE_LOCK:\n cached = _SKILLS_PROMPT_CACHE.get(cache_key)",
2240
+ [
2241
+ " global _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE",
2242
+ " with _SKILLS_PROMPT_CACHE_LOCK:",
2243
+ " if _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE != live_signature:",
2244
+ " _SKILLS_PROMPT_CACHE.clear()",
2245
+ " _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE = live_signature",
2246
+ " cached = _SKILLS_PROMPT_CACHE.get(cache_key)",
2247
+ ].join("\n"),
2248
+ "v0.21.5 prompt cache invalidation"
2249
+ );
2250
+ }
2229
2251
  patched = replaceExactlyOnce(
2230
2252
  patched,
2231
2253
  (patchKind === "skills-prompt-freshness-v021"
@@ -2474,7 +2496,7 @@ export const HERMES_AGENT_BRIDGE_DEDICATED_V020_CONTRACT = normalizeContract({
2474
2496
  sourceSha256:
2475
2497
  "8ce75e7f2d999edf6554a8f5a037289c885bc9427263da1cd6e3448e608fe20f",
2476
2498
  patchedSha256:
2477
- "d220e900e65aba7ec76dad9f9220b0f88e6947d24953384572254f141d91e5f7",
2499
+ "e4bf77633c8333d1f79310768c0824e8eaed87938ec7ffd2478050f12f5d36a6",
2478
2500
  },
2479
2501
  {
2480
2502
  path: "gateway/run.py",
@@ -2549,7 +2571,7 @@ export const HERMES_AGENT_BRIDGE_DEDICATED_V021_CONTRACT = normalizeContract({
2549
2571
  "path": "tools/mcp_tool_handlers.py",
2550
2572
  "patchKind": "mcp-tool-endpoint-v021",
2551
2573
  "sourceSha256": "e6af250f0fbfeb12a936c340a46f40f8d40332ed8bbc4eb63fded66e37aaa7bf",
2552
- "patchedSha256": "9b559cc00a26a546167e9c03aad6827949c10089b0a4127e8d74367a2062dee4"
2574
+ "patchedSha256": "6c4765aad3074b6f8ad6951299edafa36cf536c9a9f0b57a48bdd541e3209790"
2553
2575
  },
2554
2576
  {
2555
2577
  "path": "gateway/run.py",
@@ -2615,7 +2637,7 @@ export const HERMES_AGENT_BRIDGE_DEDICATED_V0213_CONTRACT = normalizeContract({
2615
2637
  "path": "tools/mcp_tool_handlers.py",
2616
2638
  "patchKind": "mcp-tool-endpoint-v021",
2617
2639
  "sourceSha256": "c4713aa289c7ca17b53c0ae53ceb6a276321f6d36e259084974e8b5738b6a4dd",
2618
- "patchedSha256": "e390f44c92d7d3890fd983d93c8e311016519aa65e1c5da419406e10887c6bc1"
2640
+ "patchedSha256": "1bd801ebf1c6e17a0d81899b2ee0401f038ae4d1a493552f021a1b66fccf0e98"
2619
2641
  },
2620
2642
  {
2621
2643
  "path": "gateway/run.py",
@@ -2669,6 +2691,84 @@ export const HERMES_AGENT_BRIDGE_DEDICATED_V0213_CONTRACT = normalizeContract({
2669
2691
  "contractDigest": "75b5d16081dd2fdc5795d3b86d341f2ff341bf3c599e4c57de5ec14b3dd63ce0"
2670
2692
  });
2671
2693
 
2694
+ export const HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT = normalizeContract({
2695
+ "bridgeId": "sellable-agent-hermes-bridge/v1",
2696
+ "hermesVersion": "0.21.5",
2697
+ "versionFile": {
2698
+ "path": "hermes_cli/__init__.py",
2699
+ "sha256": "d05c98cd44e22781497a20cd968af0d9b8962406b909f1889168c624545b229e"
2700
+ },
2701
+ "files": [
2702
+ {
2703
+ "path": "gateway/config_env.py",
2704
+ "patchKind": "gateway-config-dedicated-v021",
2705
+ "sourceSha256": "5661d9cfb7d798d6c995b03727bdd4018669ae12c96d1e7a8f3c99a3ea85acc7",
2706
+ "patchedSha256": "cd8efa414e0313bca77d0d8093acc505d9f345b8fb48d734821e66027545bf57"
2707
+ },
2708
+ {
2709
+ "path": "plugins/platforms/slack/adapter.py",
2710
+ "patchKind": "slack-adapter-dedicated-v0213",
2711
+ "sourceSha256": "3f2ec0cef97964bf4cb1e9791c0917a03cd1e73bb0bc3293768680cd6302f613",
2712
+ "patchedSha256": "26cedfad352e8dadae82bebcedf8813ef948622a350b392ce99097a8ede2f056"
2713
+ },
2714
+ {
2715
+ "path": "tools/mcp_tool_handlers.py",
2716
+ "patchKind": "mcp-tool-endpoint-v021",
2717
+ "sourceSha256": "d1b4463309a2de351aaf6c7cd8f7a2a1e83f5e26dbe058371c9eeb9d0c567903",
2718
+ "patchedSha256": "61ceab8c24aef50e88d6c1dad1bbf80daed66f8950b05fb642525a62a0bb789c"
2719
+ },
2720
+ {
2721
+ "path": "gateway/run.py",
2722
+ "patchKind": "gateway-session-v021",
2723
+ "sourceSha256": "324f7095223816b865dd68a75dc83bfd1c3d101ac8c1c38dba69026dab2b6af1",
2724
+ "patchedSha256": "4b398b8c033e5aaba90b6ba312baf01e7d88d46a91843e64949ade0b65f2ade8"
2725
+ },
2726
+ {
2727
+ "path": "gateway/run_turn.py",
2728
+ "patchKind": "gateway-first-contact-v0213",
2729
+ "sourceSha256": "5bdee5c82c00e02f664516f9da0af99674e23493ec2a30eff06cb03afc6718a0",
2730
+ "patchedSha256": "0729145f27559df970c16d5be11e01ebce657874e4be1d9e151562042f5208c0"
2731
+ },
2732
+ {
2733
+ "path": "gateway/run_turn_runner.py",
2734
+ "patchKind": "gateway-provider-preflight-v021",
2735
+ "sourceSha256": "216bdca083b7d2bfae481d07bd0791a76834674b3614fd4ee0aafac5c58f30db",
2736
+ "patchedSha256": "7b6beabeed7b78781d142dcdb0eff4c0110263ee173f7696737c4c965e1c72ab"
2737
+ },
2738
+ {
2739
+ "path": "agent/turn_context.py",
2740
+ "patchKind": "turn-context-v021",
2741
+ "sourceSha256": "85f857dc3c317366d918516bc8b37a022f1020b34da0c3966a31bd289b2942e1",
2742
+ "patchedSha256": "a6487c43bc2d21f40e3a86fe31a9a0c2e4e603fff813f7c8429bbf5c22591648"
2743
+ },
2744
+ {
2745
+ "path": "cron/scheduler.py",
2746
+ "patchKind": "cron-scheduler-v020",
2747
+ "sourceSha256": "dcf0e6794a220e478584a21f786b8451b915fc7397d38eda357af1363249fa2a",
2748
+ "patchedSha256": "e98d197ce3d0b414184e3c746fe3814c213407da68ce0a46a8b4dd63a9054a11"
2749
+ },
2750
+ {
2751
+ "path": "tools/skills_tool.py",
2752
+ "patchKind": "skills-cache-freshness-v021",
2753
+ "sourceSha256": "0d47bda41ed9d1ec84856df3d336a42bb94161e89bd9a8b857e76ec76be9f7b7",
2754
+ "patchedSha256": "1bdc17603f3bb9fb34c5d04099dee2ca7d631eedc58b523bcd74d6e946dc9eb7"
2755
+ },
2756
+ {
2757
+ "path": "agent/prompt_builder.py",
2758
+ "patchKind": "skills-prompt-freshness-v0215",
2759
+ "sourceSha256": "64bc77a26641754b8c5ca76fc876687d3c9e81aad7816c2e76ce251a41121526",
2760
+ "patchedSha256": "56edefd92c50f38a3fed8d56b6fc02352f8e5892b43553ab277e3113606d25fb"
2761
+ },
2762
+ {
2763
+ "path": "gateway/platforms/api_server.py",
2764
+ "patchKind": "api-opener-stage-v021",
2765
+ "sourceSha256": "fa83a20bd4f9f3a90a3ac010db0a68f548259587946ea80b81b2f3253bafd5ec",
2766
+ "patchedSha256": "5289cc21e1804d0aaa49b117f32ea1a506375fa76459cdac8f5013f0566d05e1"
2767
+ }
2768
+ ],
2769
+ "contractDigest": "d8b2ee47591435091a81a3e9913ba5acace2f9c1418cf75c0e23b4d0632e4024"
2770
+ });
2771
+
2672
2772
  function assertRelativeContractPath(path) {
2673
2773
  if (
2674
2774
  !path ||
@@ -182,7 +182,7 @@ const LEGACY_HERMES_SNAPSHOT_SCRIPT = "scripts/hermes-memory-reconcile.sh";
182
182
 
183
183
  const HERMES = "/opt/hermes/.venv/bin/hermes";
184
184
  const HERMES_PYTHON = "/opt/hermes/.venv/bin/python";
185
- const VERSION = "0.21.3";
185
+ const VERSION = "0.21.5";
186
186
  const ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
187
187
  const BOUNDED_ID = /^[A-Za-z0-9][A-Za-z0-9_./:-]{0,255}$/;
188
188
  const SHA256 = /^[a-f0-9]{64}$/;
@@ -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.766";
41
+ const INSTALLER_PACKAGE = "@sellable/install@0.1.768-wip.hermes-20260925.4";
42
42
  const MCP_PACKAGE = "@sellable/mcp@0.1.941";
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.766" ||
1549
+ pinned.installerPackage !== "@sellable/install@0.1.768-wip.hermes-20260925.4" ||
1550
1550
  pinned.mcpPackage !== "@sellable/mcp@0.1.941" ||
1551
1551
  !Array.isArray(policy.toolInclude) ||
1552
1552
  policy.toolInclude.length === 0 ||
@@ -211,9 +211,15 @@ function parseMarker(path) {
211
211
  marker.models.length < 1 ||
212
212
  (marker.version === MARKER_VERSION &&
213
213
  (marker.models.length !== CURRENT_OPENROUTER_MODELS.length ||
214
- marker.models.some((model, index) =>
215
- stableJson(model) !== stableJson(CURRENT_OPENROUTER_MODELS[index])
216
- )))
214
+ marker.models.some((model, index) => {
215
+ const expected = CURRENT_OPENROUTER_MODELS[index];
216
+ // Preserve the activated effort during a rolling max -> high update.
217
+ return index === 0
218
+ ? !exactKeys(model, MODEL_REASONING_KEYS) ||
219
+ model.id !== expected.id ||
220
+ !["max", "high"].includes(model.reasoningEffort)
221
+ : stableJson(model) !== stableJson(expected);
222
+ })))
217
223
  ) {
218
224
  return null;
219
225
  }
@@ -410,7 +416,7 @@ export function parseModelAuthRuntimeCredential(secret, options = {}) {
410
416
  if (
411
417
  !exactKeys(model, withReasoning ? MODEL_REASONING_KEYS : MODEL_KEYS) ||
412
418
  model.id !== expected.id ||
413
- (withReasoning && model.reasoningEffort !== "max")
419
+ (withReasoning && !["max", "high"].includes(model.reasoningEffort))
414
420
  ) {
415
421
  fail("model_auth_projection_incomplete");
416
422
  }
@@ -450,7 +456,7 @@ export function modelAuthConfigOverlay(credential) {
450
456
  ...(credential.value.schemaVersion === MODEL_AUTH_RUNTIME_SCHEMA
451
457
  ? {
452
458
  reasoning_overrides: Object.freeze({
453
- "openai/gpt-5.6-luna": "max",
459
+ "openai/gpt-5.6-luna": credential.value.openrouter.models[0].reasoningEffort,
454
460
  }),
455
461
  }
456
462
  : {}),
@@ -663,7 +669,7 @@ export function readModelAuthMaterialization({ authStorePath, markerPath }) {
663
669
  ? {
664
670
  models: Object.freeze(marker.models.map((model) => Object.freeze({ ...model }))),
665
671
  reasoningOverrides: Object.freeze({
666
- "openai/gpt-5.6-luna": "max",
672
+ "openai/gpt-5.6-luna": marker.models[0].reasoningEffort,
667
673
  }),
668
674
  }
669
675
  : {}),
@@ -726,6 +732,6 @@ export function modelAuthSelectionObservation(readback) {
726
732
  provider,
727
733
  modelId,
728
734
  reasoningEffort:
729
- modelId === "openai/gpt-5.6-luna" ? "max" : MODEL_AUTH_REASONING_EFFORT,
735
+ readback.reasoningOverrides?.[modelId] ?? MODEL_AUTH_REASONING_EFFORT,
730
736
  });
731
737
  }
@@ -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.766" ||
315
+ desired.installerPackage !== "@sellable/install@0.1.768-wip.hermes-20260925.4" ||
316
316
  desired.mcpPackage !== "@sellable/mcp@0.1.941" ||
317
317
  !Array.isArray(desired.toolInclude) ||
318
318
  desired.toolInclude.length === 0 ||
@@ -2566,7 +2566,7 @@ function validateNativeSlackDesired(desired) {
2566
2566
  !SHA256.test(desired.accessPolicyHash ?? "") ||
2567
2567
  !SHA256.test(desired.runtimeDesiredHash ?? "") ||
2568
2568
  !FINGERPRINT.test(desired.apiServerKeyFingerprint ?? "") ||
2569
- desired.hermesVersion !== "0.21.3" ||
2569
+ desired.hermesVersion !== "0.21.5" ||
2570
2570
  !/^@sellable\/install@\d+\.\d+\.\d+(?:[-.A-Za-z0-9]+)?$/.test(
2571
2571
  desired.installerPackage ?? ""
2572
2572
  ) ||
@@ -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.766";
28
+ export const PINNED_INSTALL_PACKAGE = "@sellable/install@0.1.768-wip.hermes-20260925.4";
29
29
  export const PINNED_MCP_PACKAGE = "@sellable/mcp@0.1.941";
30
30
  const PINNED_INSTALL_VERSION = PINNED_INSTALL_PACKAGE.slice(
31
31
  PINNED_INSTALL_PACKAGE.lastIndexOf("@") + 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/install",
3
- "version": "0.1.766",
3
+ "version": "0.1.768-wip.hermes-20260925.4",
4
4
  "type": "module",
5
5
  "description": "One-command installer for Sellable MCP in Claude Code, Codex, and Hermes",
6
6
  "bin": {