Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/reference/commands-nemohermes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ Use `nemohermes my-assistant status` to see both the dashboard and API endpoints

`gateway-token` is not applicable to Hermes sandboxes.
Hermes API access uses bearer-token authentication configured through the Hermes runtime, not the OpenClaw gateway token.
For browser access to the dashboard, use `nemohermes <name> dashboard-url`; Hermes dashboard auth is read from the in-sandbox config (`~/.hermes/config.yaml`), not a gateway token.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
If you need the endpoint for an OpenAI-compatible client, use `nemohermes my-assistant status` and the API URL it reports.

### `nemohermes <name> destroy`
Expand Down
1 change: 1 addition & 0 deletions docs/reference/commands.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,7 @@ Do not log it, share it, or commit it to version control.

`gateway-token` is not applicable to Hermes sandboxes.
Hermes API access uses bearer-token authentication configured through the Hermes runtime, not the OpenClaw gateway token.
For browser access to the dashboard, use `nemohermes my-assistant dashboard-url`; Hermes dashboard auth is read from the in-sandbox config (`~/.hermes/config.yaml`), not a gateway token.
If you need the endpoint for an OpenAI-compatible client, use `nemohermes my-assistant status` and the API URL it reports.

</AgentOnly>
Expand Down
34 changes: 31 additions & 3 deletions src/lib/gateway-token-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,43 @@ describe("runGatewayTokenCommand", () => {
expect(getSandboxAgent).toHaveBeenCalledWith("hermes");
expect(fetchToken).not.toHaveBeenCalled();
expect(sinks.out).toEqual([]);
// Issue #3180 contract: a single agent-aware "not applicable" line.
// Nothing is written to the live stderr sink; diagnostics travel on the
// thrown error's `lines` so the caller renders them.
expect(sinks.err).toEqual([]);
expect(thrown?.lines).toHaveLength(1);
const stderr = thrown?.lines[0] ?? "";
const stderr = thrown?.lines.join("\n") ?? "";
// Issue #3180 contract: an agent-aware "not applicable" lead line.
expect(stderr).toMatch(/hermes/);
expect(stderr).toMatch(/OpenClaw/);
expect(stderr).toMatch(/not applicable/i);
expect(stderr).not.toMatch(/sandbox is running/i);
expect(stderr).not.toMatch(/ExitError|@oclif\/core|at Object\.exit/);
// Issue #5249: the Hermes message must direct users to the supported
// dashboard auth path instead of dead-ending on the OpenClaw-only note.
expect(stderr).toMatch(/dashboard-url/);
expect(stderr).toMatch(/\.hermes\/config\.yaml/);
});

it("keeps a single explanatory line for non-Hermes, non-OpenClaw agents", () => {
const sinks = makeSinks();
let thrown: GatewayTokenCommandError | null = null;
try {
runGatewayTokenCommand(
"beta",
{ quiet: false },
{
fetchToken: () => "unused",
getSandboxAgent: () => "someother",
log: sinks.log,
error: sinks.error,
},
);
} catch (error) {
thrown = error as GatewayTokenCommandError;
}
expect(thrown).toBeInstanceOf(GatewayTokenCommandError);
expect(thrown?.lines).toHaveLength(1);
expect(thrown?.lines[0]).toMatch(/not applicable/i);
expect(thrown?.lines[0]).not.toMatch(/dashboard-url/);
});

it("falls back to fetchToken when the agent lookup throws", () => {
Expand Down
25 changes: 22 additions & 3 deletions src/lib/gateway-token-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,27 @@ function gatewayTokenFail(lines: string | readonly string[], exitCode = 1): neve

const SECURITY_WARNING = "Treat this token like a password -- do not log, share, or commit it.";

/**
* Build the agent-aware "not applicable" diagnostic for a non-OpenClaw agent.
*
* NCQ #5249: the bare "this command only supports OpenClaw" line (NCQ #3180)
* leaves Hermes users following generic dashboard-token quickstart patterns
* without a next step. For Hermes specifically, point them at the supported
* dashboard auth path so Day0 verification is not a dead end. Other
* non-OpenClaw agents keep the single explanatory line.
*/
function notApplicableLines(sandboxName: string, agent: string): readonly string[] {
const lead = ` gateway-token is not applicable for sandbox '${sandboxName}': it uses the '${agent}' agent, which does not expose a gateway auth token. This command only supports the OpenClaw agent.`;
if (agent === "hermes") {
return [
lead,
` For Hermes dashboard access, run: nemoclaw ${sandboxName} dashboard-url`,
" Hermes dashboard auth is read from the in-sandbox config (~/.hermes/config.yaml), not a gateway token.",
];
}
return [lead];
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

/**
* Run the gateway-token command. Throws {@link GatewayTokenCommandError} on
* failure. The caller is responsible for rendering failures and for having
Expand All @@ -80,9 +101,7 @@ export function runGatewayTokenCommand(
}
}
if (resolvedAgent && resolvedAgent !== "openclaw") {
gatewayTokenFail(
` gateway-token is not applicable for sandbox '${sandboxName}': it uses the '${resolvedAgent}' agent, which does not expose a gateway auth token. This command only supports the OpenClaw agent.`,
);
gatewayTokenFail(notApplicableLines(sandboxName, resolvedAgent));
}

let token: string | null;
Expand Down
Loading