@inline-chat/hermes-agent-adapter 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -12
- package/dist/install.js +108 -7
- package/package.json +4 -4
- package/plugin/inline/adapter.py +657 -41
- package/plugin/inline/plugin.yaml +2 -2
- package/plugin/inline/sidecar/index.mjs +9457 -3279
- package/plugin/inline/tools.py +58 -5
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Supported:
|
|
|
27
27
|
- Realtime inbound messages, catch-up, replies to bot messages, and action callbacks.
|
|
28
28
|
- Outbound text, Markdown parsing, opt-in edit-message streaming, long-message splitting, edits, deletes, typing, and presence.
|
|
29
29
|
- Inline reply-thread routing, explicit-request auto mode, `/threads` controls, explicit `/follow` and `/unfollow` dialog relevance controls, parent chat metadata, parent/thread prompt fallback, and thread-specific skill bindings.
|
|
30
|
-
- Native Hermes `inline` tool for current-chat/thread reads, bounded history and search, exact message lookup, editing/deleting bot-owned messages, reactions, pin/unpin/list pins, reply-thread creation, and avatar presence/status.
|
|
30
|
+
- Native Hermes `inline` tool for current-chat/thread reads, bounded history and search, exact message lookup, editing/deleting bot-owned messages, reactions, pin/unpin/list pins, reply-thread creation, top-level thread/chat creation outside the current conversation, and avatar presence/status.
|
|
31
31
|
- Cached, privacy-safe sender names/usernames plus chat/thread IDs, selective reply/thread/observed context, and parent-thread context, with first-name/username Markdown mention guidance and current chat/thread links.
|
|
32
32
|
- OpenClaw-style entity summaries for live turns and tool-fetched history, including mentions, text links, thread links, thread-title links, code/pre blocks, bot commands, and group mentions as untrusted Hermes context.
|
|
33
33
|
- DM and group policies, user allowlists, group sender allowlists, mention requirements, strict mention mode, allowed chats, and free-response chats.
|
|
@@ -58,6 +58,12 @@ hermes plugins enable inline-platform
|
|
|
58
58
|
hermes gateway setup
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
When installation runs as root but the Hermes home belongs to its service user,
|
|
62
|
+
the installer automatically aligns the plugin directory ownership with that
|
|
63
|
+
service user. Subsequent `/inline_update` commands replace the durable plugin
|
|
64
|
+
directly; users do not need to maintain a second npm prefix or repeat the
|
|
65
|
+
host-side install commands for routine updates.
|
|
66
|
+
|
|
61
67
|
Select Inline in the messaging-platform picker. The default path is: go to
|
|
62
68
|
**Inline → Settings → Bots → Create a new bot**, then paste its token. See the
|
|
63
69
|
[Inline bot creation guide](https://inline.chat/docs/creating-a-bot). The
|
|
@@ -106,10 +112,12 @@ inline-hermes --version
|
|
|
106
112
|
|
|
107
113
|
`doctor` verifies required plugin files, the Node executable used for the
|
|
108
114
|
sidecar, the installed sidecar bundle hash, and whether Hermes config enables
|
|
109
|
-
the external plugin with `plugins.enabled: [inline-platform]`. It
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
the external plugin with `plugins.enabled: [inline-platform]`. It detects
|
|
116
|
+
Inline credentials from the current environment, Hermes config, or the managed
|
|
117
|
+
credential store used by `hermes gateway setup`, without printing token values.
|
|
118
|
+
It honors `INLINE_NODE_BIN` and fails if that explicit path is missing, not
|
|
119
|
+
executable, older than Node 20, or cannot report a Node version. It also fails
|
|
120
|
+
if a copied plugin has drifted from the package bundle.
|
|
113
121
|
|
|
114
122
|
Confirm Hermes sees the plugin:
|
|
115
123
|
|
|
@@ -121,7 +129,7 @@ uv run ./hermes plugins list --plain --no-bundled
|
|
|
121
129
|
Expected local output includes:
|
|
122
130
|
|
|
123
131
|
```text
|
|
124
|
-
enabled user 0.0.
|
|
132
|
+
enabled user 0.0.6 inline-platform
|
|
125
133
|
```
|
|
126
134
|
|
|
127
135
|
## Update Or Reinstall
|
|
@@ -144,10 +152,10 @@ mismatch, rerun the same command after rebuilding or upgrading the package.
|
|
|
144
152
|
|
|
145
153
|
- Hermes Agent: requires the external user plugin registry and native platform
|
|
146
154
|
plugin loader available in Hermes Agent `0.17.x`. This package was validated
|
|
147
|
-
against Hermes Agent `0.
|
|
155
|
+
against Hermes Agent `0.19.1` from source commit `cc4cab2`.
|
|
148
156
|
- Node.js: `>=20` is required for the bundled sidecar. Hermes-managed Node 22,
|
|
149
157
|
system Node, or an explicit `INLINE_NODE_BIN` path all work.
|
|
150
|
-
- Inline transport: the sidecar uses `@inline-chat/realtime-sdk@0.0.
|
|
158
|
+
- Inline transport: the sidecar uses `@inline-chat/realtime-sdk@0.0.14` and is
|
|
151
159
|
bundled into the npm package, so Hermes startup does not run `npm install`.
|
|
152
160
|
- Live sends require a valid Inline user or bot token in `INLINE_TOKEN`,
|
|
153
161
|
`INLINE_BOT_TOKEN`, `platforms.inline.token`, or `inline.token`.
|
|
@@ -254,7 +262,7 @@ Access control follows Hermes' native platform model:
|
|
|
254
262
|
| `INLINE_DM_POLICY=open|allowlist|disabled` | Controls direct-message intake. `allowlist` requires `INLINE_ALLOWED_USERS` or config `allow_from`. |
|
|
255
263
|
| `INLINE_GROUP_POLICY=open|allowlist|disabled` | Controls group intake. `allowlist` requires `INLINE_GROUP_ALLOW_FROM`. |
|
|
256
264
|
| `INLINE_GROUP_ALLOW_FROM` | Comma-separated Inline user ids allowed to invoke the bot from group chats. |
|
|
257
|
-
| `INLINE_REQUIRE_MENTION` | Requires a mention or wake word in groups by default. Replies to the bot and
|
|
265
|
+
| `INLINE_REQUIRE_MENTION` | Requires a mention or wake word in groups by default. Replies to the bot and dialogs already marked `FOLLOWING` are accepted without the wake word. |
|
|
258
266
|
| `INLINE_STRICT_MENTION` | Requires a mention or wake word on every group turn, including replies to the bot and followed threads. Defaults to `false`. |
|
|
259
267
|
| `INLINE_ALLOWED_CHATS` | Comma-separated group/thread chat ids where the bot may respond. Parent chat ids also match their Inline reply threads. DMs are not filtered. Empty means no chat restriction. |
|
|
260
268
|
| `INLINE_FREE_RESPONSE_CHATS` | Comma-separated group/thread chat ids where no mention is required. Parent chat ids also match their Inline reply threads. Useful for dedicated agent rooms. |
|
|
@@ -324,7 +332,11 @@ normalizes names to Inline Bot API constraints
|
|
|
324
332
|
(`^[a-z0-9_]+$`, max 32 characters), and calls `setMyCommands`. If Inline
|
|
325
333
|
rejects the full list with `BOT_COMMANDS_TOO_MUCH`, the adapter retries with a
|
|
326
334
|
smaller prefix. Menu sync failures are logged as warnings and do not prevent
|
|
327
|
-
message transport; `/commands` remains the full fallback list.
|
|
335
|
+
message transport; `/commands` remains the full fallback list. In chats with
|
|
336
|
+
multiple bots, Inline may insert `/command@botusername` to disambiguate a menu
|
|
337
|
+
choice. Hermes accepts that form only when the suffix matches its own username,
|
|
338
|
+
then removes the suffix before command dispatch; commands addressed to another
|
|
339
|
+
bot are ignored.
|
|
328
340
|
|
|
329
341
|
Run `/inline_update` to install the newest adapter from the plugin's current
|
|
330
342
|
npm release channel. Stable installs continue following `latest`, while
|
|
@@ -341,7 +353,18 @@ marker, so `hermes logs` and Hermes debug reports can surface the root cause.
|
|
|
341
353
|
Run `/follow` in an Inline DM, group, or reply thread to explicitly opt into
|
|
342
354
|
eligible unmentioned activity waking Hermes. Run `/unfollow` to explicitly opt
|
|
343
355
|
out; server auto-follow heuristics will not turn following back on, while
|
|
344
|
-
mentions and replies retain their normal relevance behavior.
|
|
356
|
+
mentions and replies retain their normal relevance behavior. If an otherwise
|
|
357
|
+
implicit follow/reply wake begins with a concrete mention of another person,
|
|
358
|
+
Hermes treats that explicit address as higher priority and does not respond
|
|
359
|
+
unless the bot is also explicitly mentioned.
|
|
360
|
+
|
|
361
|
+
The model-callable `inline` tool keeps reply and top-level creation separate:
|
|
362
|
+
`create_thread` creates a reply subthread under the current or explicit parent
|
|
363
|
+
chat, while `create_chat` creates a new top-level destination. `create_chat`
|
|
364
|
+
requires a title, defaults to private, accepts optional participant user IDs or
|
|
365
|
+
a parent space ID, and requires both `space_id` and explicit `is_public: true`
|
|
366
|
+
for space-wide visibility. It returns the new chat ID so Hermes can link it in
|
|
367
|
+
the normal reply.
|
|
345
368
|
|
|
346
369
|
The plugin id is `inline`, which is intentionally the same id an eventual
|
|
347
370
|
bundled Hermes adapter should use.
|
|
@@ -349,7 +372,8 @@ bundled Hermes adapter should use.
|
|
|
349
372
|
## Troubleshooting
|
|
350
373
|
|
|
351
374
|
Run `inline-hermes doctor --json` first. It checks the installed plugin path,
|
|
352
|
-
required files, Node executable,
|
|
375
|
+
required files, Node executable, source/installed sidecar bundle hashes, and
|
|
376
|
+
whether an Inline token is available to Hermes.
|
|
353
377
|
|
|
354
378
|
- `plugin is not installed`: run `inline-hermes install`.
|
|
355
379
|
- `Hermes plugin 'inline-platform' is not enabled`: run
|
package/dist/install.js
CHANGED
|
@@ -6946,7 +6946,7 @@ var require_public_api = __commonJS((exports) => {
|
|
|
6946
6946
|
|
|
6947
6947
|
// src/install.ts
|
|
6948
6948
|
import { constants as fsConstants, existsSync, realpathSync } from "node:fs";
|
|
6949
|
-
import { access, cp, lstat, mkdir, readFile, realpath, rm, stat, symlink } from "node:fs/promises";
|
|
6949
|
+
import { access, chown, cp, lchown, lstat, mkdir, readFile, readdir, realpath, rm, stat, symlink } from "node:fs/promises";
|
|
6950
6950
|
import http from "node:http";
|
|
6951
6951
|
import { createHash, randomBytes } from "node:crypto";
|
|
6952
6952
|
import { spawn, spawnSync } from "node:child_process";
|
|
@@ -7114,6 +7114,7 @@ async function installPlugin(params) {
|
|
|
7114
7114
|
filter: shouldCopyPluginFile
|
|
7115
7115
|
});
|
|
7116
7116
|
}
|
|
7117
|
+
await alignInstallOwnership(params.opts.hermesHome, params.target, params.opts.link);
|
|
7117
7118
|
const after = await inspectInstall(params);
|
|
7118
7119
|
return {
|
|
7119
7120
|
...after,
|
|
@@ -7139,7 +7140,7 @@ async function inspectInstall(params) {
|
|
|
7139
7140
|
const sourceSidecar = await inspectSidecar(params.source);
|
|
7140
7141
|
const targetSidecar = targetExists ? await inspectSidecar(params.target) : null;
|
|
7141
7142
|
const node = await inspectNode();
|
|
7142
|
-
const activation = await inspectActivation(params.opts.hermesHome);
|
|
7143
|
+
const activation = await inspectActivation(params.opts.hermesHome, params.target);
|
|
7143
7144
|
const issues = [];
|
|
7144
7145
|
const warnings = [];
|
|
7145
7146
|
if (!sourceValid) {
|
|
@@ -7164,7 +7165,10 @@ async function inspectInstall(params) {
|
|
|
7164
7165
|
warnings.push("Inline platform config is not enabled. Add platforms.inline.enabled: true and set INLINE_TOKEN/INLINE_BOT_TOKEN in the gateway environment, or set platforms.inline.token/inline.token in Hermes config");
|
|
7165
7166
|
}
|
|
7166
7167
|
if (targetExists && activation.pluginEnabled && !activation.tokenConfigured) {
|
|
7167
|
-
warnings.push("No Inline token was detected in INLINE_TOKEN, INLINE_BOT_TOKEN, or Hermes Inline config; live Inline realtime checks will not connect");
|
|
7168
|
+
warnings.push("No Inline token was detected in INLINE_TOKEN, INLINE_BOT_TOKEN, the Hermes credential store, or Hermes Inline config; live Inline realtime checks will not connect");
|
|
7169
|
+
}
|
|
7170
|
+
if (targetExists && !activation.installOwnershipAligned) {
|
|
7171
|
+
warnings.push("Installed plugin ownership differs from the Hermes home owner; internal /inline_update may fail until inline-hermes install --force repairs it");
|
|
7168
7172
|
}
|
|
7169
7173
|
return {
|
|
7170
7174
|
ok: sourceValid && (!targetExists || targetValid) && node.ok && issues.length === 0,
|
|
@@ -7488,7 +7492,7 @@ async function inspectNode() {
|
|
|
7488
7492
|
error
|
|
7489
7493
|
};
|
|
7490
7494
|
}
|
|
7491
|
-
async function inspectActivation(hermesHome) {
|
|
7495
|
+
async function inspectActivation(hermesHome, target) {
|
|
7492
7496
|
const configPath = path.join(hermesHome, "config.yaml");
|
|
7493
7497
|
let config = null;
|
|
7494
7498
|
let configExists = false;
|
|
@@ -7500,16 +7504,106 @@ async function inspectActivation(hermesHome) {
|
|
|
7500
7504
|
}
|
|
7501
7505
|
const tokenPresent = Boolean(process.env.INLINE_TOKEN || process.env.INLINE_BOT_TOKEN);
|
|
7502
7506
|
const configTokenConfigured = configTokenIsConfigured(config, ["platforms", defaultPluginId, "token"]) || configTokenIsConfigured(config, [defaultPluginId, "token"]);
|
|
7507
|
+
const hermesCredentialStore = inspectHermesCredentialStore();
|
|
7508
|
+
const installOwnershipAligned = await inspectInstallOwnership(hermesHome, target);
|
|
7503
7509
|
return {
|
|
7504
7510
|
configPath,
|
|
7505
7511
|
configExists,
|
|
7506
7512
|
pluginEnabled: readConfigList(config, ["plugins", "enabled"]).includes(pluginEnableKey),
|
|
7507
7513
|
platformConfigured: readConfigBoolean(config, ["platforms", defaultPluginId, "enabled"]) || readConfigBoolean(config, [defaultPluginId, "enabled"]),
|
|
7508
7514
|
configTokenConfigured,
|
|
7515
|
+
hermesCredentialStoreChecked: hermesCredentialStore.checked,
|
|
7516
|
+
hermesCredentialStoreTokenConfigured: hermesCredentialStore.tokenConfigured,
|
|
7509
7517
|
tokenPresent,
|
|
7510
|
-
tokenConfigured: tokenPresent || configTokenConfigured
|
|
7518
|
+
tokenConfigured: tokenPresent || configTokenConfigured || hermesCredentialStore.tokenConfigured,
|
|
7519
|
+
installOwnershipAligned
|
|
7511
7520
|
};
|
|
7512
7521
|
}
|
|
7522
|
+
async function inspectInstallOwnership(hermesHome, target) {
|
|
7523
|
+
if (!await exists(target))
|
|
7524
|
+
return true;
|
|
7525
|
+
try {
|
|
7526
|
+
const homeInfo = await stat(hermesHome);
|
|
7527
|
+
const pluginsInfo = await stat(path.dirname(target));
|
|
7528
|
+
return pluginsInfo.uid === homeInfo.uid && pluginsInfo.gid === homeInfo.gid && await treeOwnershipMatches(target, homeInfo.uid, homeInfo.gid);
|
|
7529
|
+
} catch {
|
|
7530
|
+
return false;
|
|
7531
|
+
}
|
|
7532
|
+
}
|
|
7533
|
+
async function treeOwnershipMatches(target, uid, gid) {
|
|
7534
|
+
const info = await lstat(target);
|
|
7535
|
+
if (info.uid !== uid || info.gid !== gid)
|
|
7536
|
+
return false;
|
|
7537
|
+
if (!info.isDirectory())
|
|
7538
|
+
return true;
|
|
7539
|
+
const entries = await readdir(target);
|
|
7540
|
+
for (const entry of entries) {
|
|
7541
|
+
if (!await treeOwnershipMatches(path.join(target, entry), uid, gid))
|
|
7542
|
+
return false;
|
|
7543
|
+
}
|
|
7544
|
+
return true;
|
|
7545
|
+
}
|
|
7546
|
+
async function alignInstallOwnership(hermesHome, target, linked) {
|
|
7547
|
+
if (typeof process.getuid !== "function" || process.getuid() !== 0)
|
|
7548
|
+
return;
|
|
7549
|
+
const homeInfo = await stat(hermesHome);
|
|
7550
|
+
if (homeInfo.uid === 0)
|
|
7551
|
+
return;
|
|
7552
|
+
await chown(path.dirname(target), homeInfo.uid, homeInfo.gid);
|
|
7553
|
+
if (linked) {
|
|
7554
|
+
await lchown(target, homeInfo.uid, homeInfo.gid);
|
|
7555
|
+
return;
|
|
7556
|
+
}
|
|
7557
|
+
await chownTree(target, homeInfo.uid, homeInfo.gid);
|
|
7558
|
+
}
|
|
7559
|
+
async function chownTree(target, uid, gid) {
|
|
7560
|
+
const info = await lstat(target);
|
|
7561
|
+
if (info.isSymbolicLink()) {
|
|
7562
|
+
await lchown(target, uid, gid);
|
|
7563
|
+
return;
|
|
7564
|
+
}
|
|
7565
|
+
if (info.isDirectory()) {
|
|
7566
|
+
const entries = await readdir(target);
|
|
7567
|
+
for (const entry of entries)
|
|
7568
|
+
await chownTree(path.join(target, entry), uid, gid);
|
|
7569
|
+
}
|
|
7570
|
+
await chown(target, uid, gid);
|
|
7571
|
+
}
|
|
7572
|
+
function inspectHermesCredentialStore() {
|
|
7573
|
+
const configuredPython = normalizeToken(process.env.INLINE_HERMES_PYTHON_BIN);
|
|
7574
|
+
const candidates = configuredPython ? [configuredPython] : hermesPythonCandidates();
|
|
7575
|
+
const probe = [
|
|
7576
|
+
"from hermes_cli import gateway",
|
|
7577
|
+
"configured = bool(gateway.get_env_value('INLINE_TOKEN') or gateway.get_env_value('INLINE_BOT_TOKEN'))",
|
|
7578
|
+
"print('__INLINE_HERMES_TOKEN_CONFIGURED__=' + ('1' if configured else '0'))"
|
|
7579
|
+
].join("; ");
|
|
7580
|
+
for (const candidate of candidates) {
|
|
7581
|
+
const result = spawnSync(candidate, ["-c", probe], {
|
|
7582
|
+
encoding: "utf8",
|
|
7583
|
+
timeout: 2000,
|
|
7584
|
+
maxBuffer: 64 * 1024
|
|
7585
|
+
});
|
|
7586
|
+
if (result.status !== 0)
|
|
7587
|
+
continue;
|
|
7588
|
+
const match = /^__INLINE_HERMES_TOKEN_CONFIGURED__=([01])$/m.exec(result.stdout || "");
|
|
7589
|
+
if (match)
|
|
7590
|
+
return { checked: true, tokenConfigured: match[1] === "1" };
|
|
7591
|
+
}
|
|
7592
|
+
return { checked: false, tokenConfigured: false };
|
|
7593
|
+
}
|
|
7594
|
+
function hermesPythonCandidates() {
|
|
7595
|
+
const candidates = ["/opt/hermes/.venv/bin/python"];
|
|
7596
|
+
const hermesCommand = spawnSync("which", ["hermes"], { encoding: "utf8", timeout: 1000 });
|
|
7597
|
+
const hermesPath = normalizeToken(hermesCommand.stdout);
|
|
7598
|
+
if (hermesCommand.status === 0 && hermesPath) {
|
|
7599
|
+
try {
|
|
7600
|
+
const binDir = path.dirname(realpathSync(hermesPath));
|
|
7601
|
+
candidates.push(path.join(binDir, "python"), path.join(binDir, "python3"));
|
|
7602
|
+
} catch {}
|
|
7603
|
+
}
|
|
7604
|
+
candidates.push("python3", "python");
|
|
7605
|
+
return [...new Set(candidates)];
|
|
7606
|
+
}
|
|
7513
7607
|
function readConfigList(config, pathParts) {
|
|
7514
7608
|
const value = readConfigValue(config, pathParts);
|
|
7515
7609
|
if (Array.isArray(value))
|
|
@@ -7840,8 +7934,14 @@ function printInstallResult(result) {
|
|
|
7840
7934
|
printStatus(result);
|
|
7841
7935
|
if (result.installed || result.dryRun) {
|
|
7842
7936
|
console.log("");
|
|
7843
|
-
|
|
7844
|
-
|
|
7937
|
+
if (!result.activation.pluginEnabled) {
|
|
7938
|
+
console.log(`Enable the Hermes plugin with \`hermes plugins enable ${pluginEnableKey}\`.`);
|
|
7939
|
+
}
|
|
7940
|
+
if (!result.activation.platformConfigured || !result.activation.tokenConfigured) {
|
|
7941
|
+
console.log("Run `hermes gateway setup`, select Inline, and follow the guided bot setup.");
|
|
7942
|
+
} else if (result.installed) {
|
|
7943
|
+
console.log("Restart the Hermes gateway to load the updated Inline plugin files.");
|
|
7944
|
+
}
|
|
7845
7945
|
}
|
|
7846
7946
|
}
|
|
7847
7947
|
function printTestSendResult(result) {
|
|
@@ -7879,6 +7979,7 @@ function printStatus(status) {
|
|
|
7879
7979
|
console.log(`node: ${formatNodeInfo(status.node)}`);
|
|
7880
7980
|
console.log(`hermes plugin enabled: ${status.activation.pluginEnabled ? "yes" : "no"}`);
|
|
7881
7981
|
console.log(`inline platform configured: ${status.activation.platformConfigured || status.activation.tokenConfigured ? "yes" : "no"}`);
|
|
7982
|
+
console.log(`inline token configured: ${status.activation.tokenConfigured ? "yes" : "no"}`);
|
|
7882
7983
|
if (status.warnings.length > 0) {
|
|
7883
7984
|
console.log("warnings:");
|
|
7884
7985
|
for (const warning of status.warnings)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inline-chat/hermes-agent-adapter",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Hermes Agent platform adapter for Inline, with a native Python plugin and bundled Inline realtime sidecar.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"check": "bun run typecheck && bun run lint && bun run test"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@inline-chat/realtime-sdk": "0.0.
|
|
63
|
+
"@inline-chat/realtime-sdk": "0.0.14",
|
|
64
64
|
"yaml": "2.9.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"pluginId": "inline",
|
|
77
77
|
"pluginPath": "plugin/inline",
|
|
78
78
|
"minHermesVersion": "0.17.0",
|
|
79
|
-
"testedHermesVersion": "0.
|
|
80
|
-
"testedHermesCommit": "
|
|
79
|
+
"testedHermesVersion": "0.19.1",
|
|
80
|
+
"testedHermesCommit": "cc4cab2"
|
|
81
81
|
}
|
|
82
82
|
}
|