@gmickel/gno 1.11.0 → 1.12.0
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.
|
@@ -739,11 +739,11 @@ Install GNO skill for AI coding assistants.
|
|
|
739
739
|
gno skill install [options]
|
|
740
740
|
```
|
|
741
741
|
|
|
742
|
-
| Option | Default | Description
|
|
743
|
-
| -------------- | ------- |
|
|
744
|
-
| `-t, --target` | claude | Target: `claude`, `codex`, `opencode`, `openclaw`, `all` |
|
|
745
|
-
| `-s, --scope` | project | Scope: `project`, `user`
|
|
746
|
-
| `-f, --force` | false | Overwrite existing
|
|
742
|
+
| Option | Default | Description |
|
|
743
|
+
| -------------- | ------- | ------------------------------------------------------------------ |
|
|
744
|
+
| `-t, --target` | claude | Target: `claude`, `codex`, `opencode`, `openclaw`, `hermes`, `all` |
|
|
745
|
+
| `-s, --scope` | project | Scope: `project`, `user` |
|
|
746
|
+
| `-f, --force` | false | Overwrite existing |
|
|
747
747
|
|
|
748
748
|
Examples:
|
|
749
749
|
|
|
@@ -751,6 +751,7 @@ Examples:
|
|
|
751
751
|
gno skill install --target claude --scope project
|
|
752
752
|
gno skill install --target codex --scope user
|
|
753
753
|
gno skill install --target openclaw --scope user
|
|
754
|
+
gno skill install --target hermes --scope user
|
|
754
755
|
gno skill install --target all --force # Install to all targets
|
|
755
756
|
```
|
|
756
757
|
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Install GNO agent skill to
|
|
2
|
+
* Install GNO agent skill to supported agent targets.
|
|
3
3
|
* Atomic install via temp directory + rename.
|
|
4
4
|
*
|
|
5
5
|
* @module src/cli/commands/skill/install
|
|
@@ -149,7 +149,11 @@ export async function installSkillToTarget(
|
|
|
149
149
|
|
|
150
150
|
// Remove existing if present (with safety check)
|
|
151
151
|
if (destExists) {
|
|
152
|
-
const validationError = validatePathForDeletion(
|
|
152
|
+
const validationError = validatePathForDeletion(
|
|
153
|
+
paths.gnoDir,
|
|
154
|
+
paths.base,
|
|
155
|
+
paths.gnoDir
|
|
156
|
+
);
|
|
153
157
|
if (validationError) {
|
|
154
158
|
throw new CliError(
|
|
155
159
|
"RUNTIME",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Path resolution for skill installation.
|
|
3
|
-
* Supports Claude Code, Codex, OpenCode, and
|
|
3
|
+
* Supports Claude Code, Codex, OpenCode, OpenClaw, and Hermes targets with project/user scopes.
|
|
4
4
|
*
|
|
5
5
|
* @module src/cli/commands/skill/paths
|
|
6
6
|
*/
|
|
@@ -30,18 +30,27 @@ export const ENV_OPENCODE_SKILLS_DIR = "OPENCODE_SKILLS_DIR";
|
|
|
30
30
|
/** Override OpenClaw skills directory */
|
|
31
31
|
export const ENV_OPENCLAW_SKILLS_DIR = "OPENCLAW_SKILLS_DIR";
|
|
32
32
|
|
|
33
|
+
/** Override Hermes skills directory */
|
|
34
|
+
export const ENV_HERMES_SKILLS_DIR = "HERMES_SKILLS_DIR";
|
|
35
|
+
|
|
33
36
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
34
37
|
// Types
|
|
35
38
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
36
39
|
|
|
37
40
|
export type SkillScope = "project" | "user";
|
|
38
|
-
export type SkillTarget =
|
|
41
|
+
export type SkillTarget =
|
|
42
|
+
| "claude"
|
|
43
|
+
| "codex"
|
|
44
|
+
| "opencode"
|
|
45
|
+
| "openclaw"
|
|
46
|
+
| "hermes";
|
|
39
47
|
|
|
40
48
|
export const SKILL_TARGETS: SkillTarget[] = [
|
|
41
49
|
"claude",
|
|
42
50
|
"codex",
|
|
43
51
|
"opencode",
|
|
44
52
|
"openclaw",
|
|
53
|
+
"hermes",
|
|
45
54
|
];
|
|
46
55
|
|
|
47
56
|
export interface SkillPathOptions {
|
|
@@ -102,6 +111,12 @@ const TARGET_CONFIGS: Record<SkillTarget, TargetPathConfig> = {
|
|
|
102
111
|
skillsSubdir: "skills",
|
|
103
112
|
envVar: ENV_OPENCLAW_SKILLS_DIR,
|
|
104
113
|
},
|
|
114
|
+
hermes: {
|
|
115
|
+
projectBase: ".hermes",
|
|
116
|
+
userBase: ".hermes",
|
|
117
|
+
skillsSubdir: "skills",
|
|
118
|
+
envVar: ENV_HERMES_SKILLS_DIR,
|
|
119
|
+
},
|
|
105
120
|
};
|
|
106
121
|
|
|
107
122
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -201,17 +216,21 @@ function getExpectedSuffixes(): string[] {
|
|
|
201
216
|
*/
|
|
202
217
|
export function validatePathForDeletion(
|
|
203
218
|
destDir: string,
|
|
204
|
-
base: string
|
|
219
|
+
base: string,
|
|
220
|
+
expectedDir?: string
|
|
205
221
|
): string | null {
|
|
206
222
|
const normalized = normalize(destDir);
|
|
207
223
|
const normalizedBase = normalize(base);
|
|
224
|
+
const normalizedExpected = expectedDir ? normalize(expectedDir) : undefined;
|
|
208
225
|
const expectedSuffixes = getExpectedSuffixes();
|
|
209
226
|
|
|
210
|
-
// Must end with
|
|
227
|
+
// Must be the resolved target directory, or end with a known skill suffix.
|
|
228
|
+
// The exact resolved path covers absolute skills-dir env overrides.
|
|
229
|
+
const matchesExpectedDir = normalizedExpected === normalized;
|
|
211
230
|
const hasValidSuffix = expectedSuffixes.some((suffix) =>
|
|
212
231
|
normalized.endsWith(suffix)
|
|
213
232
|
);
|
|
214
|
-
if (!hasValidSuffix) {
|
|
233
|
+
if (!(matchesExpectedDir || hasValidSuffix)) {
|
|
215
234
|
return `Path does not end with expected suffix (${expectedSuffixes.join(" or ")})`;
|
|
216
235
|
}
|
|
217
236
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Uninstall GNO agent skill from
|
|
2
|
+
* Uninstall GNO agent skill from supported agent targets.
|
|
3
3
|
* Includes safety checks before deletion.
|
|
4
4
|
*
|
|
5
5
|
* @module src/cli/commands/skill/uninstall
|
|
@@ -58,7 +58,11 @@ async function uninstallFromTarget(
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// Safety validation
|
|
61
|
-
const validationError = validatePathForDeletion(
|
|
61
|
+
const validationError = validatePathForDeletion(
|
|
62
|
+
paths.gnoDir,
|
|
63
|
+
paths.base,
|
|
64
|
+
paths.gnoDir
|
|
65
|
+
);
|
|
62
66
|
if (validationError) {
|
|
63
67
|
throw new CliError(
|
|
64
68
|
"RUNTIME",
|
package/src/cli/program.ts
CHANGED
|
@@ -1939,7 +1939,7 @@ function wireSkillCommands(program: Command): void {
|
|
|
1939
1939
|
|
|
1940
1940
|
skillCmd
|
|
1941
1941
|
.command("install")
|
|
1942
|
-
.description("Install GNO skill to
|
|
1942
|
+
.description("Install GNO skill to supported agents")
|
|
1943
1943
|
.option(
|
|
1944
1944
|
"-s, --scope <scope>",
|
|
1945
1945
|
"installation scope (project, user)",
|
|
@@ -1947,7 +1947,7 @@ function wireSkillCommands(program: Command): void {
|
|
|
1947
1947
|
)
|
|
1948
1948
|
.option(
|
|
1949
1949
|
"-t, --target <target>",
|
|
1950
|
-
"target agent (claude, codex, opencode, openclaw, all)",
|
|
1950
|
+
"target agent (claude, codex, opencode, openclaw, hermes, all)",
|
|
1951
1951
|
"claude"
|
|
1952
1952
|
)
|
|
1953
1953
|
.option("-f, --force", "overwrite existing installation")
|
|
@@ -1965,18 +1965,26 @@ function wireSkillCommands(program: Command): void {
|
|
|
1965
1965
|
}
|
|
1966
1966
|
// Validate target
|
|
1967
1967
|
if (
|
|
1968
|
-
!["claude", "codex", "opencode", "openclaw", "all"].includes(
|
|
1968
|
+
!["claude", "codex", "opencode", "openclaw", "hermes", "all"].includes(
|
|
1969
|
+
target
|
|
1970
|
+
)
|
|
1969
1971
|
) {
|
|
1970
1972
|
throw new CliError(
|
|
1971
1973
|
"VALIDATION",
|
|
1972
|
-
`Invalid target: ${target}. Must be 'claude', 'codex', 'opencode', 'openclaw', or 'all'.`
|
|
1974
|
+
`Invalid target: ${target}. Must be 'claude', 'codex', 'opencode', 'openclaw', 'hermes', or 'all'.`
|
|
1973
1975
|
);
|
|
1974
1976
|
}
|
|
1975
1977
|
|
|
1976
1978
|
const { installSkill } = await import("./commands/skill/install.js");
|
|
1977
1979
|
await installSkill({
|
|
1978
1980
|
scope: scope as "project" | "user",
|
|
1979
|
-
target: target as
|
|
1981
|
+
target: target as
|
|
1982
|
+
| "claude"
|
|
1983
|
+
| "codex"
|
|
1984
|
+
| "opencode"
|
|
1985
|
+
| "openclaw"
|
|
1986
|
+
| "hermes"
|
|
1987
|
+
| "all",
|
|
1980
1988
|
force: Boolean(cmdOpts.force),
|
|
1981
1989
|
json: Boolean(cmdOpts.json),
|
|
1982
1990
|
});
|
|
@@ -1992,7 +2000,7 @@ function wireSkillCommands(program: Command): void {
|
|
|
1992
2000
|
)
|
|
1993
2001
|
.option(
|
|
1994
2002
|
"-t, --target <target>",
|
|
1995
|
-
"target agent (claude, codex, opencode, openclaw, all)",
|
|
2003
|
+
"target agent (claude, codex, opencode, openclaw, hermes, all)",
|
|
1996
2004
|
"claude"
|
|
1997
2005
|
)
|
|
1998
2006
|
.option("--json", "JSON output")
|
|
@@ -2009,18 +2017,26 @@ function wireSkillCommands(program: Command): void {
|
|
|
2009
2017
|
}
|
|
2010
2018
|
// Validate target
|
|
2011
2019
|
if (
|
|
2012
|
-
!["claude", "codex", "opencode", "openclaw", "all"].includes(
|
|
2020
|
+
!["claude", "codex", "opencode", "openclaw", "hermes", "all"].includes(
|
|
2021
|
+
target
|
|
2022
|
+
)
|
|
2013
2023
|
) {
|
|
2014
2024
|
throw new CliError(
|
|
2015
2025
|
"VALIDATION",
|
|
2016
|
-
`Invalid target: ${target}. Must be 'claude', 'codex', 'opencode', 'openclaw', or 'all'.`
|
|
2026
|
+
`Invalid target: ${target}. Must be 'claude', 'codex', 'opencode', 'openclaw', 'hermes', or 'all'.`
|
|
2017
2027
|
);
|
|
2018
2028
|
}
|
|
2019
2029
|
|
|
2020
2030
|
const { uninstallSkill } = await import("./commands/skill/uninstall.js");
|
|
2021
2031
|
await uninstallSkill({
|
|
2022
2032
|
scope: scope as "project" | "user",
|
|
2023
|
-
target: target as
|
|
2033
|
+
target: target as
|
|
2034
|
+
| "claude"
|
|
2035
|
+
| "codex"
|
|
2036
|
+
| "opencode"
|
|
2037
|
+
| "openclaw"
|
|
2038
|
+
| "hermes"
|
|
2039
|
+
| "all",
|
|
2024
2040
|
json: Boolean(cmdOpts.json),
|
|
2025
2041
|
});
|
|
2026
2042
|
});
|
|
@@ -2048,7 +2064,7 @@ function wireSkillCommands(program: Command): void {
|
|
|
2048
2064
|
)
|
|
2049
2065
|
.option(
|
|
2050
2066
|
"-t, --target <target>",
|
|
2051
|
-
"filter by target (claude, codex, opencode, openclaw, all)",
|
|
2067
|
+
"filter by target (claude, codex, opencode, openclaw, hermes, all)",
|
|
2052
2068
|
"all"
|
|
2053
2069
|
)
|
|
2054
2070
|
.option("--json", "JSON output")
|
|
@@ -2065,18 +2081,26 @@ function wireSkillCommands(program: Command): void {
|
|
|
2065
2081
|
}
|
|
2066
2082
|
// Validate target
|
|
2067
2083
|
if (
|
|
2068
|
-
!["claude", "codex", "opencode", "openclaw", "all"].includes(
|
|
2084
|
+
!["claude", "codex", "opencode", "openclaw", "hermes", "all"].includes(
|
|
2085
|
+
target
|
|
2086
|
+
)
|
|
2069
2087
|
) {
|
|
2070
2088
|
throw new CliError(
|
|
2071
2089
|
"VALIDATION",
|
|
2072
|
-
`Invalid target: ${target}. Must be 'claude', 'codex', 'opencode', 'openclaw', or 'all'.`
|
|
2090
|
+
`Invalid target: ${target}. Must be 'claude', 'codex', 'opencode', 'openclaw', 'hermes', or 'all'.`
|
|
2073
2091
|
);
|
|
2074
2092
|
}
|
|
2075
2093
|
|
|
2076
2094
|
const { showPaths } = await import("./commands/skill/paths-cmd.js");
|
|
2077
2095
|
await showPaths({
|
|
2078
2096
|
scope: scope as "project" | "user" | "all",
|
|
2079
|
-
target: target as
|
|
2097
|
+
target: target as
|
|
2098
|
+
| "claude"
|
|
2099
|
+
| "codex"
|
|
2100
|
+
| "opencode"
|
|
2101
|
+
| "openclaw"
|
|
2102
|
+
| "hermes"
|
|
2103
|
+
| "all",
|
|
2080
2104
|
json: Boolean(cmdOpts.json),
|
|
2081
2105
|
});
|
|
2082
2106
|
});
|
package/src/serve/connectors.ts
CHANGED
|
@@ -118,6 +118,18 @@ const CONNECTOR_DEFINITIONS: ConnectorDefinition[] = [
|
|
|
118
118
|
"Recommended default for local agent access without manual file edits.",
|
|
119
119
|
},
|
|
120
120
|
},
|
|
121
|
+
{
|
|
122
|
+
id: "hermes-skill",
|
|
123
|
+
appName: "Hermes Agent",
|
|
124
|
+
installKind: "skill",
|
|
125
|
+
target: "hermes",
|
|
126
|
+
scope: "user",
|
|
127
|
+
mode: {
|
|
128
|
+
label: "Read/search via skill",
|
|
129
|
+
detail:
|
|
130
|
+
"Recommended default for Hermes Agent. Uses the standard ~/.hermes/skills path.",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
121
133
|
] as const;
|
|
122
134
|
|
|
123
135
|
export async function getConnectorStatuses(overrides?: {
|