@ran-sh/dsh-crew 2.2.15 → 2.2.17

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-crew",
3
- "version": "2.2.15",
3
+ "version": "2.2.17",
4
4
  "description": "Dispatch subtasks to DeepSeek Harness (DSH) agents as native subagents with live progress",
5
5
  "author": {
6
6
  "name": "ZSeven-W"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ran-sh/dsh-crew",
3
- "version": "2.2.15",
3
+ "version": "2.2.17",
4
4
  "type": "module",
5
5
  "main": "./src/hub/entry.mjs",
6
6
  "bin": {
@@ -9,7 +9,11 @@
9
9
  "description": "DeepSeek Harness plugin: dispatch work to DSH agents from Claude Code / Codex, as native subagents with live progress",
10
10
  "dshCrew": {
11
11
  "payloadSchema": 2,
12
- "windowsSupervisorHandoff": 1
12
+ "windowsSupervisorHandoff": 1,
13
+ "payloadRewrite": {
14
+ "schema": 1,
15
+ "rewritten": false
16
+ }
13
17
  },
14
18
  "dsh": {
15
19
  "bundle": {
@@ -45,6 +49,7 @@
45
49
  "@deepseek-ai/dsh": "^0.1.0 || ^0.2.0-rc.1",
46
50
  "@deepseek-ai/dsh-agent": "^0.1.0 || ^0.2.0-rc.1",
47
51
  "@deepseek-ai/dsh-agent-loop": "^0.1.0 || ^0.2.0-rc.1",
52
+ "@deepseek-ai/dsh-agent-preset-registry": "^0.1.0 || ^0.2.0-rc.1",
48
53
  "@deepseek-ai/dsh-bash-local": "^0.1.0 || ^0.2.0-rc.1",
49
54
  "@deepseek-ai/dsh-client-locale": "^0.1.0 || ^0.2.0-rc.1",
50
55
  "@deepseek-ai/dsh-client-ui-renderer": "^0.1.0 || ^0.2.0-rc.1",
@@ -78,6 +83,9 @@
78
83
  "@deepseek-ai/dsh-agent-loop": {
79
84
  "optional": true
80
85
  },
86
+ "@deepseek-ai/dsh-agent-preset-registry": {
87
+ "optional": true
88
+ },
81
89
  "@deepseek-ai/dsh-bash-local": {
82
90
  "optional": true
83
91
  },
@@ -146,30 +154,30 @@
146
154
  }
147
155
  },
148
156
  "devDependencies": {
149
- "@deepseek-ai/dsh": "0.1.6-alpha.1",
150
- "@deepseek-ai/dsh-agent": "0.1.6-alpha.1",
151
- "@deepseek-ai/dsh-agent-loop": "0.1.6-alpha.1",
152
- "@deepseek-ai/dsh-agent-presets": "0.1.6-alpha.1",
153
- "@deepseek-ai/dsh-bash-local": "0.1.6-alpha.1",
154
- "@deepseek-ai/dsh-client-locale": "0.1.6-alpha.1",
155
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.6-alpha.1",
156
- "@deepseek-ai/dsh-client-ui-settings": "0.1.6-alpha.1",
157
- "@deepseek-ai/dsh-compaction-basic": "0.1.6-alpha.1",
158
- "@deepseek-ai/dsh-fs-local": "0.1.6-alpha.1",
159
- "@deepseek-ai/dsh-fs-observation-policy": "0.1.6-alpha.1",
160
- "@deepseek-ai/dsh-llm": "0.1.6-alpha.1",
161
- "@deepseek-ai/dsh-llm-deepseek": "0.1.6-alpha.1",
162
- "@deepseek-ai/dsh-sandbox-local": "0.1.6-alpha.1",
163
- "@deepseek-ai/dsh-sandbox-policy": "0.1.6-alpha.1",
164
- "@deepseek-ai/dsh-sdk-client": "0.1.6-alpha.1",
165
- "@deepseek-ai/dsh-sdk-jsonrpc-server": "0.1.6-alpha.1",
166
- "@deepseek-ai/dsh-sdk-minimal": "0.1.6-alpha.1",
167
- "@deepseek-ai/dsh-session": "0.1.6-alpha.1",
168
- "@deepseek-ai/dsh-session-persistence-jsonl": "0.1.6-alpha.1",
169
- "@deepseek-ai/dsh-subprocess-local": "0.1.6-alpha.1",
170
- "@deepseek-ai/dsh-token-meter": "0.1.6-alpha.1",
171
- "@deepseek-ai/dsh-tool-fs": "0.1.6-alpha.1",
172
- "@deepseek-ai/dsh-tool-todo": "0.1.6-alpha.1",
157
+ "@deepseek-ai/dsh": "0.2.0-rc.2",
158
+ "@deepseek-ai/dsh-agent": "0.2.0-rc.2",
159
+ "@deepseek-ai/dsh-agent-loop": "0.2.0-rc.2",
160
+ "@deepseek-ai/dsh-agent-preset-registry": "0.2.0-rc.2",
161
+ "@deepseek-ai/dsh-bash-local": "0.2.0-rc.2",
162
+ "@deepseek-ai/dsh-client-locale": "0.2.0-rc.2",
163
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.2",
164
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.2",
165
+ "@deepseek-ai/dsh-compaction-basic": "0.2.0-rc.2",
166
+ "@deepseek-ai/dsh-fs-local": "0.2.0-rc.2",
167
+ "@deepseek-ai/dsh-fs-observation-policy": "0.2.0-rc.2",
168
+ "@deepseek-ai/dsh-llm": "0.2.0-rc.2",
169
+ "@deepseek-ai/dsh-llm-deepseek": "0.2.0-rc.2",
170
+ "@deepseek-ai/dsh-sandbox-local": "0.2.0-rc.2",
171
+ "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2",
172
+ "@deepseek-ai/dsh-sdk-client": "0.2.0-rc.2",
173
+ "@deepseek-ai/dsh-sdk-jsonrpc-server": "0.2.0-rc.2",
174
+ "@deepseek-ai/dsh-sdk-minimal": "0.2.0-rc.2",
175
+ "@deepseek-ai/dsh-session": "0.2.0-rc.2",
176
+ "@deepseek-ai/dsh-session-persistence-jsonl": "0.2.0-rc.2",
177
+ "@deepseek-ai/dsh-subprocess-local": "0.2.0-rc.2",
178
+ "@deepseek-ai/dsh-token-meter": "0.2.0-rc.2",
179
+ "@deepseek-ai/dsh-tool-fs": "0.2.0-rc.2",
180
+ "@deepseek-ai/dsh-tool-todo": "0.2.0-rc.2",
173
181
  "@types/react": "^18.3.0",
174
182
  "react": "^18.3.1",
175
183
  "react-dom": "^18.3.1",
@@ -4,7 +4,7 @@
4
4
  // resolve to this exact version. All other modules re-export from here so a
5
5
  // cohort bump touches exactly one file (plus package.json's 48 DSH pins).
6
6
  export const DSH_CLI_PACKAGE = '@deepseek-ai/dsh';
7
- export const TARGET_DSH_VERSION = '0.1.6-alpha.1';
7
+ export const TARGET_DSH_VERSION = '0.2.0-rc.2';
8
8
  export const TARGET_DSH_SPEC = `${DSH_CLI_PACKAGE}@${TARGET_DSH_VERSION}`;
9
9
 
10
10
  export const DSH_SCOPE = '@deepseek-ai/';
@@ -14,26 +14,40 @@ export function isDshCohortPackage(name) {
14
14
  return name === DSH_CLI_PACKAGE || name.startsWith(`${DSH_CLI_PACKAGE}-`);
15
15
  }
16
16
 
17
- // The packages a persisted Crew payload vendors, at TARGET_DSH_VERSION.
17
+ // WHAT THIS LIST IS: the names a persisted Crew payload pins to
18
+ // TARGET_DSH_VERSION when the plugin declares them. It is the payload's cohort
19
+ // authority, and it answers one question — "which exact version does this
20
+ // package resolve to inside a release?"
18
21
  //
19
- // This list — not `package.json`'s DSH peer keys — decides what the standalone
20
- // payload installs. The two answer different questions: a peer key declares
21
- // which hosts will load the plugin, so it carries a RANGE that a host gate
22
- // compares against the running version, while a released payload must resolve
23
- // ONE exact cohort, because a half-upgraded tree is the failure it exists to
24
- // prevent. Reading the payload cohort out of the peer block conflated them, so
25
- // widening a peer range silently unlocked the cohort: nothing stayed pinned,
26
- // `exactSpecOverrides` produced no overrides, and npm materialized the newest
27
- // matching release instead of the one the embedded runtime runs.
22
+ // WHAT IT IS NOT: an inventory of everything that must exist at run time. The
23
+ // runtime tree is a cohort of its own, and `src/dsh-cli-runtime.mjs` judges it
24
+ // dynamically — it walks every installed @deepseek-ai/dsh* copy and compares it
25
+ // against TARGET_DSH_VERSION, so a member it was never told about still fails
26
+ // the reuse gate instead of drifting silently. Adding a name here does not make
27
+ // the runtime install it; removing one does not excuse it from that judgement.
28
28
  //
29
- // Names here are the cohort of TARGET_DSH_VERSION. A package that exists only
30
- // in a later cohort (a rename, for example) belongs in the peer block for that
31
- // host and must NOT be added here until TARGET_DSH_VERSION moves with it.
29
+ // Two boundary cases, recorded so they are not re-litigated:
30
+ // * @deepseek-ai/dsh-base and @deepseek-ai/dsh-web-app are PROFILE BUNDLES,
31
+ // named by CREW_PROFILE_DEFAULT_BUNDLES in src/dsh-cli-runtime.mjs. They
32
+ // belong to the runtime tree the profile composes, not to this plugin's
33
+ // peer set, so they are correctly absent here. A payload never vendors them.
34
+ // * @deepseek-ai/dsh-agent-preset-registry is the provider of the
35
+ // `agentPresets` service this plugin resolves, and it is declared, so it is
36
+ // both pinned here and carried as a peer. Its predecessor
37
+ // `@deepseek-ai/dsh-agent-presets` stopped publishing at 0.1.6-alpha.2 and is
38
+ // named nowhere — a cohort that still listed it would be describing a package
39
+ // no registry can serve.
40
+ //
41
+ // The list is authoritative wherever a member is declared: a peer range and an
42
+ // explicit dependency both resolve to TARGET_DSH_VERSION in the staged payload.
43
+ // A package that exists only in a later cohort — a rename, for example — belongs
44
+ // in the peer block for that host and must NOT be added here until
45
+ // TARGET_DSH_VERSION moves with it.
32
46
  export const DSH_COHORT_PACKAGES = Object.freeze([
33
47
  DSH_CLI_PACKAGE,
34
48
  '@deepseek-ai/dsh-agent',
35
49
  '@deepseek-ai/dsh-agent-loop',
36
- '@deepseek-ai/dsh-agent-presets',
50
+ '@deepseek-ai/dsh-agent-preset-registry',
37
51
  '@deepseek-ai/dsh-bash-local',
38
52
  '@deepseek-ai/dsh-client-locale',
39
53
  '@deepseek-ai/dsh-client-ui-renderer',
@@ -9,7 +9,7 @@
9
9
  //
10
10
  // Two hazards shape the rules:
11
11
  // 1. The desktop app runs a DIFFERENT cohort than Crew pins (0.1.7-rc.2 vs
12
- // 0.1.6-alpha.1), so an entry may name a package Crew's runtime does not
12
+ // 0.2.0-rc.2), so an entry may name a package Crew's runtime does not
13
13
  // have. The Harness installs patches fail-loud, so such an entry would break
14
14
  // the hub: it is skipped and reported instead.
15
15
  // 2. Crew's own managed blocks (the desktop bridge insert) are not user
@@ -36,7 +36,7 @@ import {
36
36
  writeFileSync,
37
37
  } from 'node:fs';
38
38
  import { createRequire } from 'node:module';
39
- import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
39
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
40
40
  import { fileURLToPath } from 'node:url';
41
41
  import { homedir } from 'node:os';
42
42
  import * as realInstaller from './install.mjs';
@@ -998,6 +998,22 @@ export function exactSpecOverrides(dependencies) {
998
998
 
999
999
  // ---- payload staging ---------------------------------------------------------
1000
1000
 
1001
+ // Which manifest form a file is: absent or `rewritten: false` is the shape npm
1002
+ // published, `rewritten: true` is the shape the CLI staged. A version number alone
1003
+ // cannot tell the two apart, and they do not behave alike (`npm ls`, the dependency
1004
+ // tree, and any future integrity check all see different content), so a bug report
1005
+ // has to be able to name its form without guessing.
1006
+ export function payloadRewriteRecord({ source, dshVersion, now = new Date() } = {}) {
1007
+ const kind = typeof source?.kind === 'string' && source.kind ? source.kind : 'unknown';
1008
+ const record = { schema: 1, rewritten: true, source: { kind }, targetDshVersion: dshVersion ?? null };
1009
+ for (const key of ['spec', 'integrity', 'file', 'path', 'version']) {
1010
+ const value = source?.[key];
1011
+ if (typeof value === 'string' && value) record.source[key] = value;
1012
+ }
1013
+ if (now instanceof Date && !Number.isNaN(now.valueOf())) record.rewrittenAt = now.toISOString();
1014
+ return record;
1015
+ }
1016
+
1001
1017
  /**
1002
1018
  * Stage the candidate into its FINAL release directory, guarded by an
1003
1019
  * incompleteness marker. Committing = removing the marker (a single-file
@@ -1005,13 +1021,15 @@ export function exactSpecOverrides(dependencies) {
1005
1021
  * pointer last. This avoids directory renames, which Windows can refuse with
1006
1022
  * transient EPERM while a freshly written tree is being scanned.
1007
1023
  *
1008
- * The persisted manifest merges the exact-pinned DSH peer cohort into
1009
- * `dependencies` (peer declarations are dropped): the installed payload runs
1010
- * standalone — `src/server.mjs` statically imports DSH peers — so those
1011
- * packages must exist inside the release, not be assumed from a host.
1024
+ * The persisted manifest re-pins every declared DSH peer to the cohort in
1025
+ * `dependencies`, with matching `overrides`, so a released payload resolves
1026
+ * exactly one cohort, and it keeps the `peerDependencies` declaration so the
1027
+ * host compatibility gate still has something to check. Only `devDependencies`
1028
+ * is dropped — it is not a runtime input.
1012
1029
  */
1013
1030
  export function stageCandidatePayload({
1014
1031
  sourceRoot = runningPackageRoot(),
1032
+ source = null,
1015
1033
  home = homedir(),
1016
1034
  log = () => {},
1017
1035
  now = new Date(),
@@ -1055,27 +1073,50 @@ export function stageCandidatePayload({
1055
1073
  // declaration only: the running host supplies it, as it supplies every other
1056
1074
  // shared module. Without this pin the payload stops carrying a resolvable
1057
1075
  // cohort at all, and `payloadDshVersion` fails closed on the range.
1076
+ //
1077
+ // `peerDependencies` STAYS in the payload. The host gate opens with
1078
+ // `if (!Object.hasOwn(fields, "peerDependencies")) return void 0`, so a payload
1079
+ // that dropped the key stops being checked at all: the installed form would
1080
+ // trade the host's compatibility protection for nothing, and a future runtime
1081
+ // that genuinely mismatched would fail silently at run time instead of being
1082
+ // refused at boot. Keeping the declaration costs nothing — the exact cohort pin
1083
+ // lives in `dependencies` plus `overrides`, which answers a different question
1084
+ // than the range a host gate compares — and `peerDependenciesMeta.optional`
1085
+ // keeps npm from treating the pinned copies as unsatisfied required peers.
1086
+ // `devDependencies` is removed: it is not a runtime input and must never be
1087
+ // materialized into the payload.
1058
1088
  const stagedManifest = { ...manifest };
1059
1089
  delete stagedManifest.devDependencies;
1060
- delete stagedManifest.peerDependencies;
1061
- delete stagedManifest.peerDependenciesMeta;
1062
1090
  const optionalNames = new Set(Object.keys(manifest.optionalDependencies ?? {}));
1063
1091
  const cohortPins = dshCohortPins();
1064
- const explicitDependencies = new Set(Object.keys(manifest.dependencies ?? {}));
1065
1092
  const stagedDependencies = { ...(manifest.dependencies ?? {}) };
1066
1093
  for (const [name, spec] of Object.entries(manifest.peerDependencies ?? {})) {
1067
1094
  if (!name.startsWith(DSH_SCOPE)) {
1068
1095
  if (!(name in stagedDependencies)) stagedDependencies[name] = spec;
1069
1096
  continue;
1070
1097
  }
1071
- // An explicit runtime dependency wins over the peer shorthand.
1072
- if (explicitDependencies.has(name)) continue;
1098
+ // A scoped peer outside the cohort is a host-gate declaration only.
1073
1099
  if (!Object.hasOwn(cohortPins, name)) continue;
1074
1100
  stagedDependencies[name] = cohortPins[name];
1075
1101
  }
1102
+ // The cohort list is authoritative wherever a member is declared, including a
1103
+ // member an author promoted into `dependencies`. Pinning there too keeps one
1104
+ // exact cohort; the alternative silently floats that package and re-opens
1105
+ // exactly the drift the payload pin exists to prevent.
1106
+ for (const [name, spec] of Object.entries(stagedDependencies)) {
1107
+ if (!Object.hasOwn(cohortPins, name)) continue;
1108
+ if (spec !== cohortPins[name]) {
1109
+ log(`- pinning ${name} ${spec} -> ${cohortPins[name]} (the payload resolves one cohort)`);
1110
+ }
1111
+ stagedDependencies[name] = cohortPins[name];
1112
+ }
1076
1113
  stagedManifest.dependencies = stagedDependencies;
1077
1114
  const overrides = exactSpecOverrides(stagedManifest.dependencies);
1078
1115
  if (overrides) stagedManifest.overrides = overrides;
1116
+ stagedManifest.dshCrew = {
1117
+ ...(stagedManifest.dshCrew ?? {}),
1118
+ payloadRewrite: payloadRewriteRecord({ source, dshVersion: TARGET_DSH_VERSION, now }),
1119
+ };
1079
1120
  writeFileSync(join(stageDir, 'package.json'), JSON.stringify(stagedManifest, null, 2) + '\n');
1080
1121
 
1081
1122
  // Materialize dependencies: prefer replicating the exact bits the candidate
@@ -2881,7 +2922,7 @@ async function npxInstallInner({ home, log, sourceRoot, installer, ensureRuntime
2881
2922
  return { ok: true, repaired: true, version: manifest.version, path: health.pointer.path };
2882
2923
  }
2883
2924
 
2884
- const staged = stageCandidatePayload({ sourceRoot: candidateRoot, home, log, npmInstaller });
2925
+ const staged = stageCandidatePayload({ sourceRoot: candidateRoot, home, log, npmInstaller, source: { kind: 'running', path: candidateRoot, version: manifest.version } });
2885
2926
  if (!staged.ok) {
2886
2927
  log(`✗ staging failed (${staged.code})${staged.detail ? `: ${Array.isArray(staged.detail) ? staged.detail.join('; ') : String(staged.detail)}` : ''}`);
2887
2928
  return { ok: false, error: `staging failed (${staged.code})` };
@@ -2979,7 +3020,7 @@ export function resolveUpdateCandidate({
2979
3020
  if (existsSync(join(value, 'package.json'))) {
2980
3021
  const manifest = readManifest(value);
2981
3022
  if (!manifest?.name || !manifest?.version) return { ok: false, code: 'CANDIDATE_MANIFEST_INVALID', detail: value };
2982
- return { ok: true, sourceRoot: value, version: manifest.version, cleanup: null };
3023
+ return { ok: true, sourceRoot: value, version: manifest.version, cleanup: null, source: { kind: 'candidate', path: value } };
2983
3024
  }
2984
3025
  if (/\.tgz$/i.test(value)) {
2985
3026
  const tmpRoot = join(crewReleasesDir({ home }), `.candidate-${timestampStamp()}-${process.pid}`);
@@ -2997,6 +3038,7 @@ export function resolveUpdateCandidate({
2997
3038
  ok: true,
2998
3039
  sourceRoot: extracted.sourceRoot,
2999
3040
  version: manifest.version,
3041
+ source: { kind: 'candidate', file: basename(value) },
3000
3042
  cleanup: () => rmSync(tmpRoot, { recursive: true, force: true }),
3001
3043
  };
3002
3044
  }
@@ -3041,6 +3083,7 @@ export function resolveUpdateCandidate({
3041
3083
  ok: true,
3042
3084
  sourceRoot: extracted.sourceRoot,
3043
3085
  version: manifest.version,
3086
+ source: { kind: 'registry', spec: effectiveSpec, ...(typeof info.integrity === 'string' && info.integrity ? { integrity: info.integrity } : {}), ...(typeof info.filename === 'string' && info.filename ? { file: info.filename } : {}) },
3044
3087
  cleanup: () => rmSync(tmpDir, { recursive: true, force: true }),
3045
3088
  };
3046
3089
  } catch (error) {
@@ -3097,7 +3140,7 @@ async function npxUpdateInner({ home, log, sourceRoot, candidate, spec, installe
3097
3140
  let resolved;
3098
3141
  if (launcherCanConverge) {
3099
3142
  log(`- newer launcher ${launcherManifest.version}; converging managed payload ${initialHealth.pointer.version} before registry resolution`);
3100
- resolved = { ok: true, sourceRoot: launcherRoot, version: launcherManifest.version, cleanup: null };
3143
+ resolved = { ok: true, sourceRoot: launcherRoot, version: launcherManifest.version, cleanup: null, source: { kind: 'launcher', path: launcherRoot, version: launcherManifest.version } };
3101
3144
  } else {
3102
3145
  resolved = resolveUpdateCandidate({ candidate: explicitCandidate, spec, home, log, runner });
3103
3146
  }
@@ -3139,7 +3182,7 @@ async function npxUpdateInner({ home, log, sourceRoot, candidate, spec, installe
3139
3182
  log(`- updating managed payload ${health.pointer.version} -> ${manifest.version}`);
3140
3183
  }
3141
3184
 
3142
- const staged = stageCandidatePayload({ sourceRoot: resolved.sourceRoot, home, log, npmInstaller });
3185
+ const staged = stageCandidatePayload({ sourceRoot: resolved.sourceRoot, home, log, npmInstaller, source: resolved.source });
3143
3186
  if (!staged.ok) {
3144
3187
  log(`✗ staging failed (${staged.code})${staged.detail ? `: ${Array.isArray(staged.detail) ? staged.detail.join('; ') : String(staged.detail)}` : ''}`);
3145
3188
  return { ok: false, error: `staging failed (${staged.code})` };
@@ -13,6 +13,15 @@ function runtimeManifest(manifest) {
13
13
  delete normalized.devDependencies;
14
14
  delete normalized.peerDependencies;
15
15
  delete normalized.peerDependenciesMeta;
16
+ // The install-form record is bookkeeping about the manifest, not a property of
17
+ // the shipped files: normalize it away so one payload keeps one digest before
18
+ // and after the CLI rewrite. Without this, `samePayloadContent` would report
19
+ // every rewritten payload as changed and the same-version repair path would
20
+ // never be reachable again.
21
+ if (normalized.dshCrew && typeof normalized.dshCrew === 'object') {
22
+ const { payloadRewrite, ...rest } = normalized.dshCrew;
23
+ normalized.dshCrew = rest;
24
+ }
16
25
  return canonical(normalized);
17
26
  }
18
27
 
@@ -5,7 +5,7 @@
5
5
  // - HUB_PROTOCOL_VERSION changes only when Hub <-> MCP wire semantics become
6
6
  // incompatible.
7
7
  //
8
- // The Harness/DSH cohort version (e.g. 0.1.6-alpha.1) is a THIRD, independent
8
+ // The Harness/DSH cohort version (e.g. 0.2.0-rc.2) is a THIRD, independent
9
9
  // domain: it identifies the installed @deepseek-ai/dsh package generation,
10
10
  // never the Crew release. Verifiers must compare the cohort against
11
11
  // dsh_version, never against runtime_version.
@@ -36,7 +36,7 @@ export {
36
36
  // included in the identity contract.
37
37
  const RUNTIME_ID = randomUUID();
38
38
 
39
- export const RUNTIME_VERSION = '2.2.15';
39
+ export const RUNTIME_VERSION = '2.2.17';
40
40
  export const HUB_PROTOCOL_VERSION = 1;
41
41
 
42
42
  export const HUB_CAPABILITIES = Object.freeze([