@sellable/install 0.1.797-wip.runtime-ux.20261004.2 → 0.1.799

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.797-wip.runtime-ux.20261004.2
6
+ ARG INSTALLER_PACKAGE=@sellable/install@0.1.799
7
7
  ARG MCP_PACKAGE=@sellable/mcp@0.1.957
8
8
  ARG INSTALLER_INTEGRITY
9
9
  ARG MCP_INTEGRITY=sha512-tIZuO5IEanT/afamDIWdorUNMdqZA6xnjL9jGAmGqYIlIqkXdHB9slWiwfLfmM44iEp7OT98IBHJlvbpMThk6A==
10
10
 
11
- RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.797-wip.runtime-ux.20261004.2" \
11
+ RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.799" \
12
12
  && test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.957" \
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.797-wip.runtime-ux.2026
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.797-wip.runtime-ux.20261004.2' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.957') 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.799' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.957') 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.797-wip.runtime-ux.20261004.2', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.957', 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.799', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.957', 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.797-wip.runtime-ux.20261004.2` is
6
+ `@sellable/install@0.1.799` is
7
7
  published:
8
8
 
9
9
  ```sh
@@ -8,7 +8,7 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright
8
8
 
9
9
  ARG MCP_PACKAGE=@sellable/mcp@0.1.957
10
10
  ARG MCP_INTEGRITY=sha512-tIZuO5IEanT/afamDIWdorUNMdqZA6xnjL9jGAmGqYIlIqkXdHB9slWiwfLfmM44iEp7OT98IBHJlvbpMThk6A==
11
- ARG INSTALLER_PACKAGE=@sellable/install@0.1.797-wip.runtime-ux.20261004.2
11
+ ARG INSTALLER_PACKAGE=@sellable/install@0.1.799
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
@@ -2,6 +2,7 @@ import type { SpawnOptions } from "node:child_process";
2
2
  import type { Server } from "node:http";
3
3
  import type { RunsApiConnection } from "./runs-api-connections.mjs";
4
4
 
5
+ export const CLAUDE_RUNS_MAX_CONCURRENCY: number;
5
6
  export type ClaudeRunsRequest = {
6
7
  input: string;
7
8
  instructions: string;
@@ -30,17 +31,25 @@ export type ClaudeRunsServer = Server & { stopActiveRuns(): Promise<void> };
30
31
  export type ClaudeRunsApiOptions = {
31
32
  token: string;
32
33
  connection: RunsApiConnection;
33
- execute?: (request: ClaudeRunsRequest) => {
34
- promise: Promise<ClaudeRunsResult>;
35
- stop(): void;
36
- };
34
+ execute?:
35
+ | ((request: ClaudeRunsRequest) => {
36
+ promise: Promise<ClaudeRunsResult>;
37
+ stop(): void;
38
+ })
39
+ | null;
37
40
  audit?: (entry: Record<string, unknown>) => void;
38
41
  maxConcurrency?: number;
39
42
  maxToolConcurrency?: number;
40
43
  toolLanes?: ClaudeRunsToolLanes | null;
41
- checkAuthentication?: () => Promise<
42
- "READY" | "SIGN_IN_REQUIRED" | "UNAVAILABLE"
43
- >;
44
+ checkAuthentication?: (
45
+ configDir: string
46
+ ) => Promise<"READY" | "SIGN_IN_REQUIRED" | "UNAVAILABLE">;
47
+ accounts?: () => string[];
48
+ startRun?: (
49
+ request: ClaudeRunsRequest,
50
+ options: { root: string; configDir: string }
51
+ ) => { promise: Promise<ClaudeRunsResult>; stop(code?: string): void };
52
+ now?: () => number;
44
53
  };
45
54
  export function validateClaudeRunsRequest(
46
55
  body: unknown,
@@ -54,8 +63,14 @@ export function endpointToolNames(options: {
54
63
  export function claudeInvocation(
55
64
  request: ClaudeRunsRequest,
56
65
  root: string,
57
- mcpSpecPath?: string | null
66
+ mcpSpecPath?: string | null,
67
+ configDir?: string
58
68
  ): { command: string; args: string[]; options: SpawnOptions };
69
+ export function claudeAccountDirs(root: string): string[];
70
+ export function claudeUsageLimit(
71
+ stdout: string,
72
+ now?: number
73
+ ): { retryAt: number } | null;
59
74
  export function parseClaudeResult(
60
75
  stdout: string,
61
76
  request: ClaudeRunsRequest
@@ -64,6 +79,7 @@ export function startClaudeRun(
64
79
  request: ClaudeRunsRequest,
65
80
  options: {
66
81
  root: string;
82
+ configDir?: string;
67
83
  spawnImpl?: (...args: any[]) => any;
68
84
  timeoutMs?: number;
69
85
  }
@@ -81,6 +97,7 @@ export function startConfiguredClaudeRunsApis(options?: {
81
97
 
82
98
  export function readClaudeAuthentication(options: {
83
99
  root: string;
100
+ configDir?: string;
84
101
  execFileImpl?: any;
85
102
  timeoutMs?: number;
86
103
  }): Promise<"READY" | "SIGN_IN_REQUIRED" | "UNAVAILABLE">;
@@ -2,7 +2,9 @@ import { execFile, spawn } from "node:child_process";
2
2
  import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
3
3
  import {
4
4
  appendFileSync,
5
+ existsSync,
5
6
  lstatSync,
7
+ readdirSync,
6
8
  readFileSync,
7
9
  rmSync,
8
10
  writeFileSync,
@@ -20,6 +22,9 @@ import {
20
22
  RUNS_API_CONNECTIONS_ENV,
21
23
  } from "./runs-api-connections.mjs";
22
24
 
25
+ // Each pool runs as many generations at once as one Hermes endpoint may
26
+ // (ENDPOINT_USER_MAX_CONCURRENCY); the runtime still caps the machine at 10.
27
+ export const CLAUDE_RUNS_MAX_CONCURRENCY = 8;
23
28
  const MAX_BODY = 320 * 1024;
24
29
  const MAX_OUTPUT = 48 * 1024;
25
30
  const MAX_CLI_OUTPUT = 512 * 1024;
@@ -129,7 +134,12 @@ export function endpointToolNames({
129
134
  return [...names];
130
135
  }
131
136
 
132
- export function claudeInvocation(request, root, mcpSpecPath = null) {
137
+ export function claudeInvocation(
138
+ request,
139
+ root,
140
+ mcpSpecPath = null,
141
+ configDir = `${root}/claude`
142
+ ) {
133
143
  return {
134
144
  command: `${root}/cli/node_modules/.bin/claude`,
135
145
  args: [
@@ -186,8 +196,8 @@ export function claudeInvocation(request, root, mcpSpecPath = null) {
186
196
  stdio: ["pipe", "pipe", "pipe"],
187
197
  env: {
188
198
  PATH: "/usr/local/bin:/usr/bin:/bin",
189
- HOME: `${root}/claude`,
190
- CLAUDE_CONFIG_DIR: `${root}/claude`,
199
+ HOME: configDir,
200
+ CLAUDE_CONFIG_DIR: configDir,
191
201
  LANG: "C.UTF-8",
192
202
  CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1",
193
203
  },
@@ -199,12 +209,15 @@ export function claudeInvocation(request, root, mcpSpecPath = null) {
199
209
  // this boundary; CLI stdout can contain account identity and is never forwarded.
200
210
  export function readClaudeAuthentication({
201
211
  root,
212
+ configDir = `${root}/claude`,
202
213
  execFileImpl = execFile,
203
214
  timeoutMs = 8_000,
204
215
  } = {}) {
205
216
  const invocation = claudeInvocation(
206
217
  { instructions: "", input: "", model: "claude-opus", effort: "high" },
207
- root
218
+ root,
219
+ null,
220
+ configDir
208
221
  );
209
222
  return new Promise((resolve) => {
210
223
  execFileImpl(
@@ -231,6 +244,90 @@ export function readClaudeAuthentication({
231
244
  });
232
245
  }
233
246
 
247
+ // Each sign-in is its own Claude config folder: the primary `claude`, then
248
+ // `accounts/<name>` in name order. Refresh tokens rotate inside a folder, so a
249
+ // login is never copied between folders.
250
+ export function claudeAccountDirs(root) {
251
+ const dirs = [`${root}/claude`];
252
+ let names = [];
253
+ try {
254
+ names = readdirSync(`${root}/accounts`).sort();
255
+ } catch {
256
+ /* No extra accounts. */
257
+ }
258
+ for (const name of names)
259
+ if (
260
+ /^[a-z0-9][a-z0-9-]{0,62}$/.test(name) &&
261
+ existsSync(`${root}/accounts/${name}/.credentials.json`)
262
+ )
263
+ dirs.push(`${root}/accounts/${name}`);
264
+ return dirs;
265
+ }
266
+
267
+ const MONTHS = "janfebmaraprmayjunjulaugsepoctnovdec";
268
+ const USAGE_LIMIT_RETRY_MS = 15 * 60_000;
269
+
270
+ // Claude Code reports a used-up plan as an API 429 result, for example
271
+ // "You've hit your weekly limit · resets Oct 7, 10am (UTC)". Returns when that
272
+ // account can be tried again, or null for any other result.
273
+ export function claudeUsageLimit(stdout, now = Date.now()) {
274
+ let value;
275
+ try {
276
+ value = JSON.parse(stdout);
277
+ } catch {
278
+ return null;
279
+ }
280
+ if (
281
+ !record(value) ||
282
+ value.is_error !== true ||
283
+ value.api_error_status !== 429
284
+ )
285
+ return null;
286
+ const reset =
287
+ /resets\s+(?:([a-z]{3})[a-z]*\s+(\d{1,2}),?\s+)?(\d{1,2})(?::(\d{2}))?\s*(am|pm)\s*\(UTC\)/i.exec(
288
+ String(value.result ?? "")
289
+ );
290
+ let retryAt = null;
291
+ if (reset) {
292
+ const hour =
293
+ (Number(reset[3]) % 12) + (reset[5].toLowerCase() === "pm" ? 12 : 0);
294
+ const minute = Number(reset[4] ?? 0);
295
+ const today = new Date(now);
296
+ if (reset[1]) {
297
+ const month = MONTHS.indexOf(reset[1].toLowerCase()) / 3;
298
+ if (Number.isInteger(month)) {
299
+ retryAt = Date.UTC(
300
+ today.getUTCFullYear(),
301
+ month,
302
+ Number(reset[2]),
303
+ hour,
304
+ minute
305
+ );
306
+ if (retryAt < now - 86_400_000)
307
+ retryAt = Date.UTC(
308
+ today.getUTCFullYear() + 1,
309
+ month,
310
+ Number(reset[2]),
311
+ hour,
312
+ minute
313
+ );
314
+ }
315
+ } else {
316
+ retryAt = Date.UTC(
317
+ today.getUTCFullYear(),
318
+ today.getUTCMonth(),
319
+ today.getUTCDate(),
320
+ hour,
321
+ minute
322
+ );
323
+ if (retryAt <= now) retryAt += 86_400_000;
324
+ }
325
+ }
326
+ if (retryAt === null || retryAt <= now || retryAt > now + 8 * 86_400_000)
327
+ retryAt = now + USAGE_LIMIT_RETRY_MS;
328
+ return { retryAt };
329
+ }
330
+
234
331
  export function parseClaudeResult(stdout, request) {
235
332
  const result = JSON.parse(stdout);
236
333
  const models = Object.keys(result.modelUsage ?? {});
@@ -269,7 +366,12 @@ export function parseClaudeResult(stdout, request) {
269
366
 
270
367
  export function startClaudeRun(
271
368
  request,
272
- { root, spawnImpl = spawn, timeoutMs = 750_000 } = {}
369
+ {
370
+ root,
371
+ configDir = `${root}/claude`,
372
+ spawnImpl = spawn,
373
+ timeoutMs = 750_000,
374
+ } = {}
273
375
  ) {
274
376
  // The tool server's environment travels in a private per-run file, never
275
377
  // in argv, and is removed when the run ends.
@@ -285,7 +387,7 @@ export function startClaudeRun(
285
387
  const removeSpec = () => {
286
388
  if (mcpSpecPath) rmSync(mcpSpecPath, { force: true });
287
389
  };
288
- const invocation = claudeInvocation(request, root, mcpSpecPath);
390
+ const invocation = claudeInvocation(request, root, mcpSpecPath, configDir);
289
391
  let child;
290
392
  try {
291
393
  child = spawnImpl(invocation.command, invocation.args, invocation.options);
@@ -331,12 +433,16 @@ export function startClaudeRun(
331
433
  clearTimeout(timer);
332
434
  clearTimeout(killTimer);
333
435
  removeSpec();
436
+ const stdout = Buffer.concat(chunks).toString("utf8");
437
+ const limit = reason ? null : claudeUsageLimit(stdout);
438
+ if (limit)
439
+ return reject(
440
+ Object.assign(new Error("claude_runs_usage_limited"), limit)
441
+ );
334
442
  if (reason || code !== 0)
335
443
  return reject(new Error(reason ?? "claude_runs_cli_failed"));
336
444
  try {
337
- resolve(
338
- parseClaudeResult(Buffer.concat(chunks).toString("utf8"), request)
339
- );
445
+ resolve(parseClaudeResult(stdout, request));
340
446
  } catch {
341
447
  reject(new Error("claude_runs_output_rejected"));
342
448
  }
@@ -350,39 +456,100 @@ export function startClaudeRun(
350
456
  export function createClaudeRunsApi({
351
457
  token,
352
458
  connection,
353
- execute = (request) => {
459
+ execute = null,
460
+ audit = () => {},
461
+ maxConcurrency = CLAUDE_RUNS_MAX_CONCURRENCY,
462
+ // Tool lanes (replies, follow-ups) have their own slots so a batch of
463
+ // openers can never crowd them out.
464
+ maxToolConcurrency = CLAUDE_RUNS_MAX_CONCURRENCY,
465
+ toolLanes = null,
466
+ checkAuthentication = (configDir) =>
467
+ readClaudeAuthentication({ root: connection.localRoot, configDir }),
468
+ accounts = () => claudeAccountDirs(connection.localRoot),
469
+ startRun = startClaudeRun,
470
+ now = Date.now,
471
+ } = {}) {
472
+ if (!/^[a-f0-9]{64}$/.test(token ?? ""))
473
+ throw new Error("claude_runs_key_rejected");
474
+ // An account whose plan is used up rests until its reset; runs go to the
475
+ // next signed-in account meanwhile, and back to the first once it resets.
476
+ const usageLimitedUntil = new Map();
477
+ const resting = (configDir) =>
478
+ (usageLimitedUntil.get(configDir) ?? 0) > now();
479
+ const runOnAccounts = (request) => {
354
480
  let activeRun;
355
481
  let stopped = false;
356
482
  return {
357
483
  promise: (async () => {
358
- const state = await checkAuthentication();
359
- if (stopped) throw new Error("claude_runs_cancelled");
360
- if (state !== "READY")
361
- throw new Error(
362
- state === "SIGN_IN_REQUIRED"
363
- ? "claude_runs_sign_in_required"
364
- : "claude_runs_auth_check_unavailable"
365
- );
366
- activeRun = startClaudeRun(request, { root: connection.localRoot });
367
- return activeRun.promise;
484
+ let failure = null;
485
+ for (const configDir of accounts()) {
486
+ if (resting(configDir)) {
487
+ failure = "claude_runs_usage_limited";
488
+ continue;
489
+ }
490
+ const state = await checkAuthentication(configDir);
491
+ if (stopped) throw new Error("claude_runs_cancelled");
492
+ if (state !== "READY") {
493
+ failure ??=
494
+ state === "SIGN_IN_REQUIRED"
495
+ ? "claude_runs_sign_in_required"
496
+ : "claude_runs_auth_check_unavailable";
497
+ continue;
498
+ }
499
+ activeRun = startRun(request, {
500
+ root: connection.localRoot,
501
+ configDir,
502
+ });
503
+ try {
504
+ return await activeRun.promise;
505
+ } catch (error) {
506
+ if (stopped || error.message !== "claude_runs_usage_limited")
507
+ throw error;
508
+ usageLimitedUntil.set(configDir, error.retryAt);
509
+ failure = "claude_runs_usage_limited";
510
+ }
511
+ }
512
+ throw new Error(failure ?? "claude_runs_sign_in_required");
368
513
  })(),
369
514
  stop() {
370
515
  stopped = true;
371
516
  activeRun?.stop();
372
517
  },
373
518
  };
374
- },
375
- audit = () => {},
376
- maxConcurrency = 2,
377
- // Tool lanes (replies, follow-ups) have their own slots so a batch of
378
- // openers can never crowd them out.
379
- maxToolConcurrency = 2,
380
- toolLanes = null,
381
- checkAuthentication = () =>
382
- readClaudeAuthentication({ root: connection.localRoot }),
383
- } = {}) {
384
- if (!/^[a-f0-9]{64}$/.test(token ?? ""))
385
- throw new Error("claude_runs_key_rejected");
519
+ };
520
+ const executeRun = execute ?? runOnAccounts;
521
+ const readHealth = async () => {
522
+ const dirs = accounts();
523
+ let ready = 0;
524
+ let signedOut = 0;
525
+ const retryAts = [];
526
+ for (const configDir of dirs) {
527
+ if (resting(configDir)) {
528
+ retryAts.push(usageLimitedUntil.get(configDir));
529
+ continue;
530
+ }
531
+ const state = await checkAuthentication(configDir).catch(
532
+ () => "UNAVAILABLE"
533
+ );
534
+ if (state === "READY") ready++;
535
+ if (state === "SIGN_IN_REQUIRED") signedOut++;
536
+ }
537
+ return {
538
+ authentication: ready
539
+ ? "READY"
540
+ : signedOut === dirs.length
541
+ ? "SIGN_IN_REQUIRED"
542
+ : "UNAVAILABLE",
543
+ accounts: {
544
+ total: dirs.length,
545
+ ready,
546
+ usageLimited: retryAts.length,
547
+ retryAt: retryAts.length
548
+ ? new Date(Math.min(...retryAts)).toISOString()
549
+ : null,
550
+ },
551
+ };
552
+ };
386
553
  // The run's own tools and the profile's MCP server, or null for a tool-free run.
387
554
  const resolveTools = (request) => {
388
555
  if (!connection.toolEndpointIds || !toolLanes) return null;
@@ -462,12 +629,11 @@ export function createClaudeRunsApi({
462
629
  )
463
630
  return json(res, 403, { error: "claude_runs_scope_rejected" });
464
631
  if (req.method === "GET" && req.url === "/health") {
465
- const authentication = await checkAuthentication().catch(
466
- () => "UNAVAILABLE"
467
- );
632
+ const { authentication, accounts: accountHealth } = await readHealth();
468
633
  return json(res, 200, {
469
634
  ok: authentication === "READY",
470
635
  authentication,
636
+ accounts: accountHealth,
471
637
  provider: "claude-code",
472
638
  active: inFlight.plain + inFlight.tools,
473
639
  toolActive: inFlight.tools,
@@ -518,7 +684,7 @@ export function createClaudeRunsApi({
518
684
  inFlight[pool]++;
519
685
  runs.set(run.run_id, run);
520
686
  try {
521
- run.execution = execute(request);
687
+ run.execution = executeRun(request);
522
688
  run.execution.promise
523
689
  .then(
524
690
  (result) =>
@@ -539,6 +705,7 @@ export function createClaudeRunsApi({
539
705
  error: [
540
706
  "claude_runs_sign_in_required",
541
707
  "claude_runs_auth_check_unavailable",
708
+ "claude_runs_usage_limited",
542
709
  ].includes(error.message)
543
710
  ? error.message
544
711
  : "claude_runs_generation_failed",
@@ -126,7 +126,7 @@ const RUNTIME_GENERATION = Number(
126
126
  const BOOT_SESSION_ID = randomUUID();
127
127
  const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.21.5";
128
128
  const INSTALLER_PACKAGE =
129
- process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.797-wip.runtime-ux.20261004.2";
129
+ process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.799";
130
130
  const MCP_PACKAGE =
131
131
  process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.957";
132
132
  export const ENDPOINT_MAX_CONCURRENT_RUNS = 10;
@@ -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.797-wip.runtime-ux.20261004.2";
41
+ const INSTALLER_PACKAGE = "@sellable/install@0.1.799";
42
42
  const MCP_PACKAGE = "@sellable/mcp@0.1.957";
43
43
  const HERMES_VERSION = "0.18.0";
44
44
  const SHA256 = /^[a-f0-9]{64}$/;
@@ -1546,7 +1546,7 @@ export function compileClaimToProfileDesired(activeClaim, config) {
1546
1546
  ]) ||
1547
1547
  pinned.hermesCli !== "hermes" ||
1548
1548
  pinned.hermesVersion !== "0.18.0" ||
1549
- pinned.installerPackage !== "@sellable/install@0.1.797-wip.runtime-ux.20261004.2" ||
1549
+ pinned.installerPackage !== "@sellable/install@0.1.799" ||
1550
1550
  pinned.mcpPackage !== "@sellable/mcp@0.1.957" ||
1551
1551
  !Array.isArray(policy.toolInclude) ||
1552
1552
  policy.toolInclude.length === 0 ||
@@ -312,7 +312,7 @@ function validateDesired(desired) {
312
312
  desired.serviceCredentialGeneration < 1 ||
313
313
  desired.hermesCli !== "hermes" ||
314
314
  desired.hermesVersion !== "0.18.0" ||
315
- desired.installerPackage !== "@sellable/install@0.1.797-wip.runtime-ux.20261004.2" ||
315
+ desired.installerPackage !== "@sellable/install@0.1.799" ||
316
316
  desired.mcpPackage !== "@sellable/mcp@0.1.957" ||
317
317
  !Array.isArray(desired.toolInclude) ||
318
318
  desired.toolInclude.length === 0 ||
@@ -25,7 +25,7 @@ import { fileURLToPath } from "node:url";
25
25
  import { deriveContainedProfileId } from "./profile-materializer.mjs";
26
26
 
27
27
  export const PROVISIONING_ACTION = "PROVISION_HERMES_PROFILE";
28
- export const PINNED_INSTALL_PACKAGE = "@sellable/install@0.1.797-wip.runtime-ux.20261004.2";
28
+ export const PINNED_INSTALL_PACKAGE = "@sellable/install@0.1.799";
29
29
  export const PINNED_MCP_PACKAGE = "@sellable/mcp@0.1.957";
30
30
  const PINNED_INSTALL_VERSION = PINNED_INSTALL_PACKAGE.slice(
31
31
  PINNED_INSTALL_PACKAGE.lastIndexOf("@") + 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/install",
3
- "version": "0.1.797-wip.runtime-ux.20261004.2",
3
+ "version": "0.1.799",
4
4
  "type": "module",
5
5
  "description": "One-command installer for Sellable MCP in Claude Code, Codex, and Hermes",
6
6
  "bin": {