@sellable/install 0.1.577 → 0.1.578-wip.phase170.20260809.1
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/container/Dockerfile +4 -4
- package/container/README.md +2 -2
- package/lib/sellable-agent/fly-admin-image/Dockerfile +13 -0
- package/lib/sellable-agent/fly-admin-image/admin-runtime.mjs +82 -1
- package/lib/sellable-agent/fly-customer-image/Dockerfile +11 -2
- package/lib/sellable-agent/fly-customer-image/customer-runtime.mjs +1 -1
- package/lib/sellable-agent/fly-skills-bridge-exec.mjs +45 -0
- package/lib/sellable-agent/fly-skills-bridge.mjs +955 -0
- package/lib/sellable-agent/hermes-bridge.mjs +123 -0
- package/lib/sellable-agent/host-bootstrap.mjs +1 -1
- package/lib/sellable-agent/host-worker.mjs +12 -5
- package/lib/sellable-agent/profile-materializer.mjs +169 -14
- package/lib/sellable-agent/provisioning-adapter.mjs +4 -4
- package/package.json +1 -1
package/container/Dockerfile
CHANGED
|
@@ -3,12 +3,12 @@ FROM ${HERMES_IMAGE}
|
|
|
3
3
|
|
|
4
4
|
USER root
|
|
5
5
|
|
|
6
|
-
ARG INSTALLER_PACKAGE=@sellable/install@0.1.
|
|
6
|
+
ARG INSTALLER_PACKAGE=@sellable/install@0.1.578-wip.phase170.20260809.1
|
|
7
7
|
ARG MCP_PACKAGE=@sellable/mcp@0.1.858
|
|
8
8
|
ARG INSTALLER_INTEGRITY
|
|
9
9
|
ARG MCP_INTEGRITY=sha512-8yiUhwMbBk/KxZAXGXTsEHiN8XeB/qCqNgfApew0rhViJqiLlDN8oS67pZW5iB5gdmeuv4du0jx9Lhq/blr9hQ==
|
|
10
10
|
|
|
11
|
-
RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.
|
|
11
|
+
RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.578-wip.phase170.20260809.1" \
|
|
12
12
|
&& test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.858" \
|
|
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.577" \
|
|
|
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.
|
|
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.578-wip.phase170.20260809.1' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.858') 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.
|
|
28
|
+
&& node --input-type=module -e "import { chmodSync, writeFileSync } from 'node:fs'; const release = { installerPackage: '@sellable/install@0.1.578-wip.phase170.20260809.1', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.858', 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
|
package/container/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
This image is a dedicated Agent worker/runtime boundary beside an existing Hermes dashboard. It never replaces or reconfigures the dashboard container.
|
|
4
4
|
|
|
5
5
|
Build from this directory after
|
|
6
|
-
`@sellable/install@0.1.
|
|
6
|
+
`@sellable/install@0.1.578-wip.phase170.20260809.1` is
|
|
7
7
|
published:
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
10
|
docker build --platform linux/amd64 \
|
|
11
11
|
--build-arg INSTALLER_INTEGRITY='sha512-…' \
|
|
12
|
-
--tag sellable-agent-host:0.1.
|
|
12
|
+
--tag sellable-agent-host:0.1.578-wip.phase170.20260809.1 .
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Create a private `bootstrap/` directory owned by root with mode `0700`. It must contain `bootstrap.json`, `provider-auth`, and `slack-app`, each owned by root with mode `0600`. `bootstrap.json` contains only non-secret identities, hashes, package integrities, and the control-plane URL. The other two files contain the provider JSON and global Slack app token whose hashes are pinned by `bootstrap.json`.
|
|
@@ -86,6 +86,8 @@ COPY hermes-bridge.mjs /usr/local/lib/sellable-agent/hermes-bridge.mjs
|
|
|
86
86
|
COPY hermes-memory-snapshot.mjs /usr/local/lib/sellable-agent/hermes-memory-snapshot.mjs
|
|
87
87
|
COPY fly-soul-bridge.mjs /usr/local/lib/sellable-agent/fly-soul-bridge.mjs
|
|
88
88
|
COPY fly-soul-bridge-exec.mjs /usr/local/lib/sellable-agent/fly-soul-bridge-exec.mjs
|
|
89
|
+
COPY fly-skills-bridge.mjs /usr/local/lib/sellable-agent/fly-skills-bridge.mjs
|
|
90
|
+
COPY fly-skills-bridge-exec.mjs /usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs
|
|
89
91
|
COPY soul-artifact-validator.mjs /usr/local/lib/sellable-agent/soul-artifact-validator.mjs
|
|
90
92
|
COPY hermes-memory-dirty.mjs /opt/sellable/bin/hermes-memory-dirty
|
|
91
93
|
COPY hermes-memory-reconcile.sh /opt/sellable/share/hermes-memory-reconcile.sh
|
|
@@ -107,9 +109,18 @@ RUN node --input-type=module -e \
|
|
|
107
109
|
'import("file:///usr/local/lib/sellable-agent/fly-soul-bridge-exec.mjs").then(({ runFlySoulBridgeExecCli }) => runFlySoulBridgeExecCli());' \
|
|
108
110
|
> /usr/local/bin/sellable-soul-bridge-exec \
|
|
109
111
|
&& chmod 0555 /usr/local/bin/sellable-soul-bridge-exec \
|
|
112
|
+
&& printf '%s\n' \
|
|
113
|
+
'#!/usr/bin/env node' \
|
|
114
|
+
'import("file:///usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs").then(({ runFlySkillsBridgeExecCli }) => runFlySkillsBridgeExecCli());' \
|
|
115
|
+
> /usr/local/bin/sellable-skills-bridge-exec \
|
|
116
|
+
&& chmod 0555 /usr/local/bin/sellable-skills-bridge-exec \
|
|
110
117
|
&& sha256sum /usr/local/lib/sellable-agent/fly-soul-bridge.mjs \
|
|
111
118
|
> /usr/local/share/sellable-agent/soul-bridge-source.sha256 \
|
|
119
|
+
&& sha256sum /usr/local/lib/sellable-agent/fly-skills-bridge.mjs \
|
|
120
|
+
/usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs \
|
|
121
|
+
> /usr/local/share/sellable-agent/skills-bridge-source.sha256 \
|
|
112
122
|
&& chmod 0444 /usr/local/share/sellable-agent/soul-bridge-source.sha256 \
|
|
123
|
+
/usr/local/share/sellable-agent/skills-bridge-source.sha256 \
|
|
113
124
|
&& chmod 0755 /etc \
|
|
114
125
|
&& chmod 0555 \
|
|
115
126
|
/usr/local/lib/sellable-agent/admin-runtime/admin-runtime.mjs \
|
|
@@ -122,6 +133,8 @@ RUN node --input-type=module -e \
|
|
|
122
133
|
/usr/local/lib/sellable-agent/hermes-memory-snapshot.mjs \
|
|
123
134
|
/usr/local/lib/sellable-agent/fly-soul-bridge.mjs \
|
|
124
135
|
/usr/local/lib/sellable-agent/fly-soul-bridge-exec.mjs \
|
|
136
|
+
/usr/local/lib/sellable-agent/fly-skills-bridge.mjs \
|
|
137
|
+
/usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs \
|
|
125
138
|
/usr/local/lib/sellable-agent/soul-artifact-validator.mjs \
|
|
126
139
|
/opt/sellable/bin/hermes-memory-dirty \
|
|
127
140
|
/opt/sellable/bin/hermes-endpoint-cron \
|
|
@@ -622,6 +622,78 @@ function installAdminModelConfig(profileRoot, modelConfig) {
|
|
|
622
622
|
}
|
|
623
623
|
}
|
|
624
624
|
|
|
625
|
+
const ADMIN_LIVE_SKILLS_CONFIG_KEYS = Object.freeze([
|
|
626
|
+
"disabled",
|
|
627
|
+
"platform_disabled",
|
|
628
|
+
]);
|
|
629
|
+
|
|
630
|
+
function adminPreservedSkillsIdentity(profileRoot) {
|
|
631
|
+
if (!existsSync(profileRoot)) return null;
|
|
632
|
+
const entries = [];
|
|
633
|
+
const skillsRoot = join(profileRoot, "skills");
|
|
634
|
+
const walk = (directory, relativePath = "") => {
|
|
635
|
+
for (const name of readdirSync(directory).sort()) {
|
|
636
|
+
const nextRelative = relativePath ? `${relativePath}/${name}` : name;
|
|
637
|
+
if (nextRelative === "sellable") continue;
|
|
638
|
+
const path = join(directory, name);
|
|
639
|
+
const stat = lstatSync(path);
|
|
640
|
+
if (stat.isSymbolicLink()) {
|
|
641
|
+
throw new Error("admin_runtime_live_skills_symlink_rejected");
|
|
642
|
+
}
|
|
643
|
+
if (stat.isDirectory()) walk(path, nextRelative);
|
|
644
|
+
else if (stat.isFile()) {
|
|
645
|
+
entries.push({
|
|
646
|
+
path: nextRelative,
|
|
647
|
+
sha256: sha256(readFileSync(path)),
|
|
648
|
+
});
|
|
649
|
+
} else throw new Error("admin_runtime_live_skills_entry_rejected");
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
if (existsSync(skillsRoot)) walk(skillsRoot);
|
|
653
|
+
const configPath = join(profileRoot, "config.yaml");
|
|
654
|
+
let disabled = {};
|
|
655
|
+
if (existsSync(configPath)) {
|
|
656
|
+
const document = parseDocument(readFileSync(configPath, "utf8"));
|
|
657
|
+
if (document.errors.length > 0) {
|
|
658
|
+
throw new Error("admin_runtime_live_skills_config_rejected");
|
|
659
|
+
}
|
|
660
|
+
const skills = document.toJS()?.skills;
|
|
661
|
+
if (skills && typeof skills === "object" && !Array.isArray(skills)) {
|
|
662
|
+
disabled = Object.fromEntries(
|
|
663
|
+
ADMIN_LIVE_SKILLS_CONFIG_KEYS.filter((key) =>
|
|
664
|
+
Object.prototype.hasOwnProperty.call(skills, key)
|
|
665
|
+
).map((key) => [key, skills[key]])
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
return sha256(canonicalJson({ disabled, entries }));
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
function mergeAdminLiveSkillsConfig(sourceRoot, targetRoot) {
|
|
673
|
+
const sourcePath = join(sourceRoot, "config.yaml");
|
|
674
|
+
const targetPath = join(targetRoot, "config.yaml");
|
|
675
|
+
if (!existsSync(sourcePath) || !existsSync(targetPath)) return;
|
|
676
|
+
const sourceDocument = parseDocument(readFileSync(sourcePath, "utf8"));
|
|
677
|
+
const targetDocument = parseDocument(readFileSync(targetPath, "utf8"));
|
|
678
|
+
if (sourceDocument.errors.length > 0 || targetDocument.errors.length > 0) {
|
|
679
|
+
throw new Error("admin_runtime_live_skills_config_rejected");
|
|
680
|
+
}
|
|
681
|
+
const sourceSkills = sourceDocument.toJS()?.skills;
|
|
682
|
+
if (
|
|
683
|
+
!sourceSkills ||
|
|
684
|
+
typeof sourceSkills !== "object" ||
|
|
685
|
+
Array.isArray(sourceSkills)
|
|
686
|
+
) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
for (const key of ADMIN_LIVE_SKILLS_CONFIG_KEYS) {
|
|
690
|
+
if (Object.prototype.hasOwnProperty.call(sourceSkills, key)) {
|
|
691
|
+
targetDocument.setIn(["skills", key], structuredClone(sourceSkills[key]));
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
atomicPrivateFile(targetPath, targetDocument.toString());
|
|
695
|
+
}
|
|
696
|
+
|
|
625
697
|
async function materializeAdminProfile({
|
|
626
698
|
profileContract,
|
|
627
699
|
settingsRoot,
|
|
@@ -727,7 +799,6 @@ async function materializeAdminProfile({
|
|
|
727
799
|
},
|
|
728
800
|
});
|
|
729
801
|
installAdminModelConfig(stageRoot, modelConfig);
|
|
730
|
-
mergeHermesState(profileHome, stageRoot);
|
|
731
802
|
installAdminHermesMemoryHook(stageRoot);
|
|
732
803
|
stageAdminRuntimeTree(stageRoot);
|
|
733
804
|
return stage;
|
|
@@ -751,6 +822,16 @@ async function materializeAdminProfile({
|
|
|
751
822
|
rmSync(stageRoot, { recursive: true, force: true });
|
|
752
823
|
return { status: "RESTAGE", stagedAuthority: finalAuthority };
|
|
753
824
|
}
|
|
825
|
+
const liveSkillsIdentity = adminPreservedSkillsIdentity(profileHome);
|
|
826
|
+
mergeHermesState(profileHome, stageRoot);
|
|
827
|
+
mergeAdminLiveSkillsConfig(profileHome, stageRoot);
|
|
828
|
+
if (
|
|
829
|
+
liveSkillsIdentity !== null &&
|
|
830
|
+
adminPreservedSkillsIdentity(stageRoot) !== liveSkillsIdentity
|
|
831
|
+
) {
|
|
832
|
+
rmSync(stageRoot, { recursive: true, force: true });
|
|
833
|
+
return { status: "RESTAGE", stagedAuthority: finalAuthority };
|
|
834
|
+
}
|
|
754
835
|
const stagedSoulPath = join(stageRoot, "SOUL.md");
|
|
755
836
|
const stagedSoul = lstatSync(stagedSoulPath);
|
|
756
837
|
const stagedSoulBytes = readFileSync(stagedSoulPath);
|
|
@@ -6,7 +6,7 @@ USER root
|
|
|
6
6
|
|
|
7
7
|
ARG MCP_PACKAGE=@sellable/mcp@0.1.858
|
|
8
8
|
ARG MCP_INTEGRITY=sha512-8yiUhwMbBk/KxZAXGXTsEHiN8XeB/qCqNgfApew0rhViJqiLlDN8oS67pZW5iB5gdmeuv4du0jx9Lhq/blr9hQ==
|
|
9
|
-
ARG INSTALLER_PACKAGE=@sellable/install@0.1.
|
|
9
|
+
ARG INSTALLER_PACKAGE=@sellable/install@0.1.578-wip.phase170.20260809.1
|
|
10
10
|
ARG TUS_JS_CLIENT_VERSION=4.3.1
|
|
11
11
|
ARG HERMES_VERSION=0.20.0
|
|
12
12
|
ARG TIRITH_VERSION=0.3.3
|
|
@@ -59,7 +59,7 @@ RUN --mount=type=secret,id=mcp_trust_root,required=true \
|
|
|
59
59
|
/etc/cont-init.d/02-reconcile-profiles \
|
|
60
60
|
&& npm cache clean --force
|
|
61
61
|
|
|
62
|
-
COPY mcp-context-proxy.mjs mcp-runtime-binding.mjs fly-customer-model.mjs fly-customer-worker.mjs profile-materializer.mjs hermes-bridge.mjs hermes-memory-snapshot.mjs fly-runtime-identity.mjs fly-soul-bridge.mjs fly-soul-bridge-exec.mjs soul-artifact-validator.mjs model-auth-reconciler.mjs model-auth-canary-reseed.mjs model-health-reporter.mjs \
|
|
62
|
+
COPY mcp-context-proxy.mjs mcp-runtime-binding.mjs fly-customer-model.mjs fly-customer-worker.mjs profile-materializer.mjs hermes-bridge.mjs hermes-memory-snapshot.mjs fly-runtime-identity.mjs fly-soul-bridge.mjs fly-soul-bridge-exec.mjs fly-skills-bridge.mjs fly-skills-bridge-exec.mjs soul-artifact-validator.mjs model-auth-reconciler.mjs model-auth-canary-reseed.mjs model-health-reporter.mjs \
|
|
63
63
|
/usr/local/lib/sellable-agent/
|
|
64
64
|
COPY hermes-memory-dirty.mjs /opt/sellable/bin/hermes-memory-dirty
|
|
65
65
|
COPY hermes-memory-reconcile.sh /opt/sellable/share/hermes-memory-reconcile.sh
|
|
@@ -86,9 +86,18 @@ RUN node --input-type=module -e \
|
|
|
86
86
|
'import("file:///usr/local/lib/sellable-agent/fly-soul-bridge-exec.mjs").then(({ runFlySoulBridgeExecCli }) => runFlySoulBridgeExecCli());' \
|
|
87
87
|
> /usr/local/bin/sellable-soul-bridge-exec \
|
|
88
88
|
&& chmod 0555 /usr/local/bin/sellable-soul-bridge-exec \
|
|
89
|
+
&& printf '%s\n' \
|
|
90
|
+
'#!/usr/bin/env node' \
|
|
91
|
+
'import("file:///usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs").then(({ runFlySkillsBridgeExecCli }) => runFlySkillsBridgeExecCli());' \
|
|
92
|
+
> /usr/local/bin/sellable-skills-bridge-exec \
|
|
93
|
+
&& chmod 0555 /usr/local/bin/sellable-skills-bridge-exec \
|
|
89
94
|
&& sha256sum /usr/local/lib/sellable-agent/fly-soul-bridge.mjs \
|
|
90
95
|
> /usr/local/share/sellable-agent/soul-bridge-source.sha256 \
|
|
96
|
+
&& sha256sum /usr/local/lib/sellable-agent/fly-skills-bridge.mjs \
|
|
97
|
+
/usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs \
|
|
98
|
+
> /usr/local/share/sellable-agent/skills-bridge-source.sha256 \
|
|
91
99
|
&& chmod 0444 /usr/local/share/sellable-agent/soul-bridge-source.sha256 \
|
|
100
|
+
/usr/local/share/sellable-agent/skills-bridge-source.sha256 \
|
|
92
101
|
&& chmod 0755 /etc \
|
|
93
102
|
&& chmod 0555 /usr/local/lib/sellable-agent/*.mjs \
|
|
94
103
|
&& chmod 0555 /opt/sellable/bin/hermes-memory-dirty /opt/sellable/bin/hermes-endpoint-cron \
|
|
@@ -94,7 +94,7 @@ const BOOT_SESSION_ID = randomUUID();
|
|
|
94
94
|
const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.20.0";
|
|
95
95
|
const INSTALLER_PACKAGE =
|
|
96
96
|
process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ??
|
|
97
|
-
"@sellable/install@0.1.
|
|
97
|
+
"@sellable/install@0.1.578-wip.phase170.20260809.1";
|
|
98
98
|
const MCP_PACKAGE =
|
|
99
99
|
process.env.SELLABLE_AGENT_MCP_PACKAGE ??
|
|
100
100
|
"@sellable/mcp@0.1.858";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
FlySkillsBridgeError,
|
|
8
|
+
SKILLS_REQUEST_MAX_BYTES,
|
|
9
|
+
executeExternalSkillsBridgeOperation,
|
|
10
|
+
} from "./fly-skills-bridge.mjs";
|
|
11
|
+
|
|
12
|
+
export async function runFlySkillsBridgeExecCli() {
|
|
13
|
+
try {
|
|
14
|
+
if (process.argv.length !== 2)
|
|
15
|
+
throw new FlySkillsBridgeError("skills_request_rejected");
|
|
16
|
+
const chunks = [];
|
|
17
|
+
let total = 0;
|
|
18
|
+
for await (const chunk of process.stdin) {
|
|
19
|
+
total += chunk.length;
|
|
20
|
+
if (total > SKILLS_REQUEST_MAX_BYTES)
|
|
21
|
+
throw new FlySkillsBridgeError("skills_request_too_large");
|
|
22
|
+
chunks.push(chunk);
|
|
23
|
+
}
|
|
24
|
+
let request;
|
|
25
|
+
try {
|
|
26
|
+
request = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
27
|
+
} catch {
|
|
28
|
+
throw new FlySkillsBridgeError("skills_request_rejected");
|
|
29
|
+
}
|
|
30
|
+
const result = executeExternalSkillsBridgeOperation(request);
|
|
31
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
32
|
+
process.exitCode = result.ok ? 0 : 2;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
process.stdout.write(
|
|
35
|
+
`${JSON.stringify({ ok: false, code: error instanceof FlySkillsBridgeError ? error.code : "skills_bridge_failed" })}\n`
|
|
36
|
+
);
|
|
37
|
+
process.exitCode = 2;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (
|
|
42
|
+
resolve(process.argv[1] ?? "") === resolve(fileURLToPath(import.meta.url))
|
|
43
|
+
) {
|
|
44
|
+
await runFlySkillsBridgeExecCli();
|
|
45
|
+
}
|