@sellable/install 0.1.308 → 0.1.309
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 +7 -0
- package/bin/sellable-install.mjs +62 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -122,6 +122,13 @@ It creates:
|
|
|
122
122
|
/srv/hermes/profiles/acme/.env # only when Slack token inputs are supplied
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
+
For profile paths under a gateway root such as
|
|
126
|
+
`/srv/hermes/profiles/acme`, bootstrap also registers
|
|
127
|
+
`/srv/hermes/profiles/acme/skills/sellable` in the gateway root
|
|
128
|
+
`/srv/hermes/config.yaml` as `skills.external_dirs`. Keep this behavior:
|
|
129
|
+
Hermes Desktop command autocomplete scans the gateway/root skill config, not
|
|
130
|
+
only the selected profile's local skill tree.
|
|
131
|
+
|
|
125
132
|
If no token is supplied, bootstrap still creates a pending
|
|
126
133
|
`sellable/config.json` so the profile path is concrete from the first MCP
|
|
127
134
|
launch. Finish auth with:
|
package/bin/sellable-install.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
writeFileSync,
|
|
14
14
|
} from "node:fs";
|
|
15
15
|
import { homedir } from "node:os";
|
|
16
|
-
import { dirname, join, relative, resolve } from "node:path";
|
|
16
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
17
17
|
import { stdout as output } from "node:process";
|
|
18
18
|
import { createInterface } from "node:readline/promises";
|
|
19
19
|
import { fileURLToPath } from "node:url";
|
|
@@ -3663,6 +3663,19 @@ function hermesSkillsRoot(opts = {}) {
|
|
|
3663
3663
|
return join(hermesHome(opts), "skills", "sellable");
|
|
3664
3664
|
}
|
|
3665
3665
|
|
|
3666
|
+
function hermesGatewayRoot(opts = {}) {
|
|
3667
|
+
const profileRoot = hermesHome(opts);
|
|
3668
|
+
const profilesRoot = dirname(profileRoot);
|
|
3669
|
+
if (basename(profilesRoot) !== "profiles") return null;
|
|
3670
|
+
return dirname(profilesRoot);
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3673
|
+
function hermesGatewayConfigPath(opts = {}) {
|
|
3674
|
+
const root = hermesGatewayRoot(opts);
|
|
3675
|
+
if (!root) return null;
|
|
3676
|
+
return join(root, "config.yaml");
|
|
3677
|
+
}
|
|
3678
|
+
|
|
3666
3679
|
function hermesLikelyInstalled() {
|
|
3667
3680
|
return (
|
|
3668
3681
|
Boolean(process.env.HERMES_HOME?.trim()) ||
|
|
@@ -3742,6 +3755,38 @@ function writeHermesMcpServer(opts) {
|
|
|
3742
3755
|
return configPath;
|
|
3743
3756
|
}
|
|
3744
3757
|
|
|
3758
|
+
function writeHermesGatewaySkillDirectory(opts) {
|
|
3759
|
+
const configPath = hermesGatewayConfigPath(opts);
|
|
3760
|
+
if (!configPath || configPath === hermesConfigPath(opts)) return null;
|
|
3761
|
+
|
|
3762
|
+
const skillDir = hermesSkillsRoot(opts);
|
|
3763
|
+
const raw = existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
|
|
3764
|
+
const config = parseHermesConfig(raw, configPath);
|
|
3765
|
+
// Hermes Desktop slash autocomplete scans the gateway/root HERMES_HOME. A
|
|
3766
|
+
// profile can execute its own skills without this, but Desktop will not show
|
|
3767
|
+
// /sellable-* commands until the root scanner sees the profile skill dir.
|
|
3768
|
+
const skills =
|
|
3769
|
+
config.skills && typeof config.skills === "object" && !Array.isArray(config.skills)
|
|
3770
|
+
? config.skills
|
|
3771
|
+
: {};
|
|
3772
|
+
const current = Array.isArray(skills.external_dirs)
|
|
3773
|
+
? skills.external_dirs
|
|
3774
|
+
: skills.external_dirs
|
|
3775
|
+
? [skills.external_dirs]
|
|
3776
|
+
: [];
|
|
3777
|
+
const externalDirs = current.includes(skillDir) ? current : [...current, skillDir];
|
|
3778
|
+
const nextConfig = {
|
|
3779
|
+
...config,
|
|
3780
|
+
skills: {
|
|
3781
|
+
...skills,
|
|
3782
|
+
external_dirs: externalDirs,
|
|
3783
|
+
},
|
|
3784
|
+
};
|
|
3785
|
+
|
|
3786
|
+
writeHermesConfig(configPath, nextConfig, opts);
|
|
3787
|
+
return { configPath, skillDir };
|
|
3788
|
+
}
|
|
3789
|
+
|
|
3745
3790
|
function installHermesSkills(opts) {
|
|
3746
3791
|
const root = hermesSkillsRoot(opts);
|
|
3747
3792
|
for (const skill of hermesSkillDefinitions()) {
|
|
@@ -3762,8 +3807,15 @@ function installHermes(opts) {
|
|
|
3762
3807
|
try {
|
|
3763
3808
|
skillsRoot = installHermesSkills(opts);
|
|
3764
3809
|
const configPath = writeHermesMcpServer(opts);
|
|
3810
|
+
const gateway = writeHermesGatewaySkillDirectory(opts);
|
|
3765
3811
|
logVerbose(`${C.grey}+ Hermes config updated: ${configPath}${C.reset}`);
|
|
3766
|
-
return {
|
|
3812
|
+
return {
|
|
3813
|
+
installed: true,
|
|
3814
|
+
configPath,
|
|
3815
|
+
skillsRoot,
|
|
3816
|
+
gatewayConfigPath: gateway?.configPath || null,
|
|
3817
|
+
gatewayExternalSkillsDir: gateway?.skillDir || null,
|
|
3818
|
+
};
|
|
3767
3819
|
} catch (err) {
|
|
3768
3820
|
if (skillsRoot && !opts.dryRun) {
|
|
3769
3821
|
rmSync(skillsRoot, { recursive: true, force: true });
|
|
@@ -4001,6 +4053,7 @@ function runHermesProfileBootstrap(argv) {
|
|
|
4001
4053
|
sellableConfigPath,
|
|
4002
4054
|
sellableConfigsDir,
|
|
4003
4055
|
skillsRoot: hermesSkillsRoot(opts),
|
|
4056
|
+
gatewayConfigPath: hermesGatewayConfigPath(opts),
|
|
4004
4057
|
},
|
|
4005
4058
|
auth: {
|
|
4006
4059
|
apiUrl: opts.apiUrl,
|
|
@@ -4085,6 +4138,8 @@ function runHermesProfileBootstrap(argv) {
|
|
|
4085
4138
|
}
|
|
4086
4139
|
|
|
4087
4140
|
const hermesConfigExisted = existsSync(hermesConfigPath(opts));
|
|
4141
|
+
const gatewayConfigPath = hermesGatewayConfigPath(opts);
|
|
4142
|
+
const gatewayConfigExisted = gatewayConfigPath ? existsSync(gatewayConfigPath) : false;
|
|
4088
4143
|
const skillsExisted = existsSync(hermesSkillsRoot(opts));
|
|
4089
4144
|
const authExisted = existsSync(sellableConfigPath);
|
|
4090
4145
|
const configsDirExisted = existsSync(sellableConfigsDir);
|
|
@@ -4138,6 +4193,11 @@ function runHermesProfileBootstrap(argv) {
|
|
|
4138
4193
|
(hermesConfigExisted ? summary.updated : summary.created).push(
|
|
4139
4194
|
hermesConfigPath(opts)
|
|
4140
4195
|
);
|
|
4196
|
+
if (gatewayConfigPath) {
|
|
4197
|
+
(gatewayConfigExisted ? summary.updated : summary.created).push(
|
|
4198
|
+
gatewayConfigPath
|
|
4199
|
+
);
|
|
4200
|
+
}
|
|
4141
4201
|
(skillsExisted ? summary.updated : summary.created).push(hermesSkillsRoot(opts));
|
|
4142
4202
|
if (Object.values(slackTokens).some(Boolean)) {
|
|
4143
4203
|
(envExisted ? summary.updated : summary.created).push(envPath);
|