@vibecodr/cli 0.1.8 → 0.1.9
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/CHANGELOG.md +14 -14
- package/README.md +17 -17
- package/dist/auth/token-manager.js +31 -3
- package/dist/bin/vibecodr-mcp.js +7 -1
- package/dist/cli/parse.js +3 -6
- package/dist/commands/call.js +4 -4
- package/dist/commands/pulse-publish.js +90 -0
- package/dist/commands/status.js +1 -1
- package/dist/commands/tools.js +2 -2
- package/docs/architecture.md +35 -35
- package/docs/auth.md +21 -21
- package/docs/commands.md +10 -7
- package/docs/install.md +3 -3
- package/docs/licensing.md +14 -14
- package/docs/troubleshooting.md +12 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## Unreleased
|
|
4
|
-
|
|
5
|
-
- rename the npm package to `@vibecodr/cli` while keeping `vibecodr` as the primary executable and `vibecodr-mcp` as a compatibility alias
|
|
6
|
-
|
|
7
|
-
## 0.1.8
|
|
8
|
-
|
|
9
|
-
- report the actual package version in MCP client metadata instead of a stale hardcoded value
|
|
10
|
-
- publish the CLI after redeploying the hosted Vibecodr MCP gateway
|
|
11
|
-
|
|
12
|
-
## 0.1.7
|
|
13
|
-
|
|
14
|
-
- add the `pulse-setup` command for live Pulse setup guidance
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
- rename the npm package to `@vibecodr/cli` while keeping `vibecodr` as the primary executable and `vibecodr-mcp` as a compatibility alias
|
|
6
|
+
|
|
7
|
+
## 0.1.8
|
|
8
|
+
|
|
9
|
+
- report the actual package version in MCP client metadata instead of a stale hardcoded value
|
|
10
|
+
- publish the CLI after redeploying the hosted Vibecodr MCP gateway
|
|
11
|
+
|
|
12
|
+
## 0.1.7
|
|
13
|
+
|
|
14
|
+
- add the `pulse-setup` command for live Pulse setup guidance
|
|
15
15
|
- align CLI Pulse setup docs with the gateway runtime contract for policy-bound secrets, Stripe-first webhook helper guidance, generic HMAC presets, and provider-scoped connections
|
|
16
16
|
- refresh release-lock coverage for current in-range MCP SDK, keyring, and Node type packages before publishing
|
|
17
17
|
|
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
# Vibecodr CLI
|
|
6
|
+
# Vibecodr CLI
|
|
7
7
|
|
|
8
|
-
Direct terminal client for the hosted Vibecodr MCP server.
|
|
8
|
+
Direct terminal client for the hosted Vibecodr MCP server.
|
|
9
9
|
|
|
10
10
|
This repository is intentionally separate from the PolyForm-licensed server implementation. The CLI is a client and installer surface, not a second server. It talks to the same hosted Vibecodr MCP gateway used by Codex, Cursor, VS Code, Windsurf, ChatGPT, and other MCP-capable clients.
|
|
11
11
|
|
|
@@ -30,21 +30,21 @@ Currently implemented command surface:
|
|
|
30
30
|
- `install`
|
|
31
31
|
- `uninstall`
|
|
32
32
|
|
|
33
|
-
Primary executable:
|
|
34
|
-
|
|
35
|
-
- `vibecodr`
|
|
36
|
-
|
|
37
|
-
Compatibility alias:
|
|
38
|
-
|
|
39
|
-
- `vibecodr-mcp`
|
|
40
|
-
|
|
41
|
-
Published package:
|
|
42
|
-
|
|
43
|
-
- `@vibecodr/cli`
|
|
44
|
-
|
|
45
|
-
Legacy package compatibility:
|
|
46
|
-
|
|
47
|
-
- `@vibecodr/mcp`
|
|
33
|
+
Primary executable:
|
|
34
|
+
|
|
35
|
+
- `vibecodr`
|
|
36
|
+
|
|
37
|
+
Compatibility alias:
|
|
38
|
+
|
|
39
|
+
- `vibecodr-mcp`
|
|
40
|
+
|
|
41
|
+
Published package:
|
|
42
|
+
|
|
43
|
+
- `@vibecodr/cli`
|
|
44
|
+
|
|
45
|
+
Legacy package compatibility:
|
|
46
|
+
|
|
47
|
+
- `@vibecodr/mcp`
|
|
48
48
|
|
|
49
49
|
The runtime path talks directly to `https://openai.vibecodr.space/mcp`. Editor installers are not part of the runtime path.
|
|
50
50
|
|
|
@@ -23,6 +23,28 @@ function computeExpiresAt(expiresIn) {
|
|
|
23
23
|
return undefined;
|
|
24
24
|
return new Date(Date.now() + expiresIn * 1000).toISOString();
|
|
25
25
|
}
|
|
26
|
+
function normalizeServerUrlForSessionMatch(value) {
|
|
27
|
+
if (!value)
|
|
28
|
+
return undefined;
|
|
29
|
+
try {
|
|
30
|
+
const url = new URL(value);
|
|
31
|
+
url.hash = "";
|
|
32
|
+
url.search = "";
|
|
33
|
+
url.pathname = url.pathname.replace(/\/+$/, "") || "/";
|
|
34
|
+
return url.toString();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return value.replace(/\/+$/, "");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function sessionMatchesServer(session, serverUrl) {
|
|
41
|
+
if (!serverUrl)
|
|
42
|
+
return true;
|
|
43
|
+
const target = normalizeServerUrlForSessionMatch(serverUrl);
|
|
44
|
+
const sessionServer = normalizeServerUrlForSessionMatch(session.serverUrl);
|
|
45
|
+
const sessionResource = normalizeServerUrlForSessionMatch(session.resourceUrl);
|
|
46
|
+
return Boolean(target && (target === sessionServer || target === sessionResource));
|
|
47
|
+
}
|
|
26
48
|
async function startLoopbackListener(timeoutSec) {
|
|
27
49
|
const callbackPath = "/oauth/callback/vibecodr";
|
|
28
50
|
const server = createServer();
|
|
@@ -108,11 +130,17 @@ export class TokenManager {
|
|
|
108
130
|
return {
|
|
109
131
|
profileName: name,
|
|
110
132
|
profile,
|
|
111
|
-
serverUrl:
|
|
133
|
+
serverUrl: profile.serverUrl
|
|
112
134
|
};
|
|
113
135
|
}
|
|
114
|
-
async getSession(profileName) {
|
|
115
|
-
|
|
136
|
+
async getSession(profileName, serverUrl) {
|
|
137
|
+
const session = await this.secretStore.get(profileName);
|
|
138
|
+
if (!session)
|
|
139
|
+
return undefined;
|
|
140
|
+
// SECURITY: Never replay a stored bearer token to a different MCP origin.
|
|
141
|
+
// Profiles may be repointed during development; the existing token remains
|
|
142
|
+
// valid only for the server/resource that issued it.
|
|
143
|
+
return sessionMatchesServer(session, serverUrl) ? session : undefined;
|
|
116
144
|
}
|
|
117
145
|
sessionState(session) {
|
|
118
146
|
if (!session)
|
package/dist/bin/vibecodr-mcp.js
CHANGED
|
@@ -16,6 +16,7 @@ import { runConfigCommand } from "../commands/config.js";
|
|
|
16
16
|
import { runInstallCommand } from "../commands/install.js";
|
|
17
17
|
import { runUninstallCommand } from "../commands/uninstall.js";
|
|
18
18
|
import { runPulseSetupCommand } from "../commands/pulse-setup.js";
|
|
19
|
+
import { runPulsePublishCommand } from "../commands/pulse-publish.js";
|
|
19
20
|
function helpText() {
|
|
20
21
|
return [
|
|
21
22
|
"vibecodr <command> [options]",
|
|
@@ -32,10 +33,12 @@ function helpText() {
|
|
|
32
33
|
" uninstall <client>",
|
|
33
34
|
" config",
|
|
34
35
|
" pulse-setup [--descriptor-setup-json <json> | --descriptor-setup-file <path>]",
|
|
36
|
+
" pulse-publish --name <name> (--code <source> | --code-file <path>) --confirm",
|
|
37
|
+
" Publishes a standalone Pulse with private source/metadata visibility by default.",
|
|
38
|
+
" The runtime URL is still public HTTP unless the Pulse code rejects callers.",
|
|
35
39
|
"",
|
|
36
40
|
"Global flags:",
|
|
37
41
|
" --profile <name>",
|
|
38
|
-
" --server-url <url>",
|
|
39
42
|
" --json",
|
|
40
43
|
" --verbose",
|
|
41
44
|
" --non-interactive"
|
|
@@ -91,6 +94,9 @@ async function main() {
|
|
|
91
94
|
case "pulse-setup":
|
|
92
95
|
await runPulseSetupCommand(commandArgs, context);
|
|
93
96
|
return;
|
|
97
|
+
case "pulse-publish":
|
|
98
|
+
await runPulsePublishCommand(commandArgs, context);
|
|
99
|
+
return;
|
|
94
100
|
default:
|
|
95
101
|
throw new CliError("usage.command", `Unknown command: ${command}`, EXIT_CODES.usage);
|
|
96
102
|
}
|
package/dist/cli/parse.js
CHANGED
|
@@ -55,12 +55,9 @@ export function parseGlobalOptions(argv) {
|
|
|
55
55
|
continue;
|
|
56
56
|
}
|
|
57
57
|
if (token === "--server-url") {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
globalOptions.serverUrl = value;
|
|
62
|
-
index += 1;
|
|
63
|
-
continue;
|
|
58
|
+
throw new CliError("usage.unknown_global_flag", "--server-url is no longer accepted as a global runtime override.", EXIT_CODES.usage, {
|
|
59
|
+
nextStep: "Create a separate profile with `vibecodr config profile create <name> --server-url <url>` and login to that profile. Stored tokens are bound to the server they were issued for."
|
|
60
|
+
});
|
|
64
61
|
}
|
|
65
62
|
if (token === "--json") {
|
|
66
63
|
globalOptions.json = true;
|
package/dist/commands/call.js
CHANGED
|
@@ -32,7 +32,7 @@ async function readStdin() {
|
|
|
32
32
|
}
|
|
33
33
|
export async function callToolWithRetry(context, toolName, input, allowLogin) {
|
|
34
34
|
const { profileName, serverUrl } = await context.tokenManager.resolveProfile(context.globalOptions);
|
|
35
|
-
const existingSession = await context.tokenManager.getSession(profileName);
|
|
35
|
+
const existingSession = await context.tokenManager.getSession(profileName, serverUrl);
|
|
36
36
|
try {
|
|
37
37
|
return {
|
|
38
38
|
result: await context.runtimeClient.callTool(serverUrl, existingSession?.accessToken, toolName, input),
|
|
@@ -54,7 +54,7 @@ export async function callToolWithRetry(context, toolName, input, allowLogin) {
|
|
|
54
54
|
await context.tokenManager.login(context.globalOptions, {
|
|
55
55
|
scope
|
|
56
56
|
});
|
|
57
|
-
const nextSession = await context.tokenManager.getSession(profileName);
|
|
57
|
+
const nextSession = await context.tokenManager.getSession(profileName, serverUrl);
|
|
58
58
|
return {
|
|
59
59
|
result: await context.runtimeClient.callTool(serverUrl, nextSession?.accessToken, toolName, input),
|
|
60
60
|
...(nextSession ? { session: nextSession } : {})
|
|
@@ -65,7 +65,7 @@ export async function callToolWithRetry(context, toolName, input, allowLogin) {
|
|
|
65
65
|
}
|
|
66
66
|
async function listToolsWithRetry(context, allowLogin) {
|
|
67
67
|
const { profileName, serverUrl } = await context.tokenManager.resolveProfile(context.globalOptions);
|
|
68
|
-
const existingSession = await context.tokenManager.getSession(profileName);
|
|
68
|
+
const existingSession = await context.tokenManager.getSession(profileName, serverUrl);
|
|
69
69
|
try {
|
|
70
70
|
return await context.runtimeClient.listTools(serverUrl, existingSession?.accessToken);
|
|
71
71
|
}
|
|
@@ -80,7 +80,7 @@ async function listToolsWithRetry(context, allowLogin) {
|
|
|
80
80
|
await context.tokenManager.login(context.globalOptions, {
|
|
81
81
|
scope: challengedScope(error)
|
|
82
82
|
});
|
|
83
|
-
const nextSession = await context.tokenManager.getSession(profileName);
|
|
83
|
+
const nextSession = await context.tokenManager.getSession(profileName, serverUrl);
|
|
84
84
|
return await context.runtimeClient.listTools(serverUrl, nextSession?.accessToken);
|
|
85
85
|
}
|
|
86
86
|
throw error;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { CliError, EXIT_CODES } from "../cli/errors.js";
|
|
3
|
+
import { parseFlags } from "../cli/parse.js";
|
|
4
|
+
import { renderToolResult } from "../core/renderers.js";
|
|
5
|
+
import { callToolWithRetry } from "./call.js";
|
|
6
|
+
const PUBLISH_STANDALONE_PULSE_TOOL_NAME = "publish_standalone_pulse";
|
|
7
|
+
const PULSE_VISIBILITIES = new Set(["public", "unlisted", "private"]);
|
|
8
|
+
const DEFAULT_PULSE_VISIBILITY = "private";
|
|
9
|
+
function parseJsonObject(raw, source) {
|
|
10
|
+
let parsed;
|
|
11
|
+
try {
|
|
12
|
+
parsed = JSON.parse(raw);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
throw new CliError("usage.invalid_json", `${source} must be valid JSON: ${error instanceof Error ? error.message : String(error)}`, EXIT_CODES.usage);
|
|
16
|
+
}
|
|
17
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
18
|
+
throw new CliError("usage.invalid_json", `${source} must be a JSON object.`, EXIT_CODES.usage);
|
|
19
|
+
}
|
|
20
|
+
return parsed;
|
|
21
|
+
}
|
|
22
|
+
async function parsePulsePublishInput(args) {
|
|
23
|
+
const { flags } = parseFlags(args, {
|
|
24
|
+
valueFlags: ["name", "code", "code-file", "descriptor-json", "descriptor-file", "slug", "visibility"],
|
|
25
|
+
booleanFlags: ["confirm"]
|
|
26
|
+
});
|
|
27
|
+
const name = typeof flags["name"] === "string" ? flags["name"].trim() : "";
|
|
28
|
+
if (!name) {
|
|
29
|
+
throw new CliError("usage.pulse_name_required", "Usage: pulse-publish --name <name> (--code <source> | --code-file <path>) --confirm", EXIT_CODES.usage);
|
|
30
|
+
}
|
|
31
|
+
const hasCode = typeof flags["code"] === "string";
|
|
32
|
+
const hasCodeFile = typeof flags["code-file"] === "string";
|
|
33
|
+
if (hasCode === hasCodeFile) {
|
|
34
|
+
throw new CliError("usage.pulse_code_required", "Use exactly one of --code or --code-file.", EXIT_CODES.usage);
|
|
35
|
+
}
|
|
36
|
+
const code = hasCode ? String(flags["code"]) : await readFile(String(flags["code-file"]), "utf8");
|
|
37
|
+
if (!code.trim()) {
|
|
38
|
+
throw new CliError("usage.pulse_code_empty", "Pulse source code cannot be empty.", EXIT_CODES.usage);
|
|
39
|
+
}
|
|
40
|
+
const hasDescriptorJson = typeof flags["descriptor-json"] === "string";
|
|
41
|
+
const hasDescriptorFile = typeof flags["descriptor-file"] === "string";
|
|
42
|
+
if (hasDescriptorJson && hasDescriptorFile) {
|
|
43
|
+
throw new CliError("usage.duplicate_descriptor", "Use either --descriptor-json or --descriptor-file, not both.", EXIT_CODES.usage);
|
|
44
|
+
}
|
|
45
|
+
const input = {
|
|
46
|
+
name,
|
|
47
|
+
code,
|
|
48
|
+
visibility: DEFAULT_PULSE_VISIBILITY,
|
|
49
|
+
confirmed: flags["confirm"] === true
|
|
50
|
+
};
|
|
51
|
+
if (hasDescriptorJson) {
|
|
52
|
+
input["descriptor"] = parseJsonObject(String(flags["descriptor-json"]), "--descriptor-json");
|
|
53
|
+
}
|
|
54
|
+
else if (hasDescriptorFile) {
|
|
55
|
+
input["descriptor"] = parseJsonObject(await readFile(String(flags["descriptor-file"]), "utf8"), "--descriptor-file");
|
|
56
|
+
}
|
|
57
|
+
if (typeof flags["slug"] === "string" && flags["slug"].trim()) {
|
|
58
|
+
input["slug"] = flags["slug"].trim();
|
|
59
|
+
}
|
|
60
|
+
if (typeof flags["visibility"] === "string") {
|
|
61
|
+
if (!PULSE_VISIBILITIES.has(flags["visibility"])) {
|
|
62
|
+
throw new CliError("usage.invalid_visibility", "Pulse visibility must be public, unlisted, or private.", EXIT_CODES.usage);
|
|
63
|
+
}
|
|
64
|
+
input["visibility"] = flags["visibility"];
|
|
65
|
+
}
|
|
66
|
+
if (input["confirmed"] !== true) {
|
|
67
|
+
throw new CliError("usage.confirmation_required", "Publishing a standalone Pulse requires explicit confirmation. Re-run with --confirm after the user confirms.", EXIT_CODES.usage, {
|
|
68
|
+
nextStep: "Ask one clear confirmation question, then pass --confirm only after the user says yes."
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return input;
|
|
72
|
+
}
|
|
73
|
+
function redactPulsePublishArguments(input) {
|
|
74
|
+
const { code: _code, descriptor: _descriptor, ...safe } = input;
|
|
75
|
+
return {
|
|
76
|
+
...safe,
|
|
77
|
+
...(input["descriptor"] ? { descriptorProvided: true } : {}),
|
|
78
|
+
sourceProvided: true
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export async function runPulsePublishCommand(args, context) {
|
|
82
|
+
const input = await parsePulsePublishInput(args);
|
|
83
|
+
const { result } = await callToolWithRetry(context, PUBLISH_STANDALONE_PULSE_TOOL_NAME, input, true);
|
|
84
|
+
context.output.success({
|
|
85
|
+
schemaVersion: 1,
|
|
86
|
+
tool: PUBLISH_STANDALONE_PULSE_TOOL_NAME,
|
|
87
|
+
arguments: redactPulsePublishArguments(input),
|
|
88
|
+
result
|
|
89
|
+
}, [renderToolResult(result)]);
|
|
90
|
+
}
|
package/dist/commands/status.js
CHANGED
|
@@ -27,7 +27,7 @@ export async function runStatusCommand(args, context) {
|
|
|
27
27
|
booleanFlags: ["probe", "show-installs"]
|
|
28
28
|
});
|
|
29
29
|
const { profileName, profile, serverUrl } = await context.tokenManager.resolveProfile(context.globalOptions);
|
|
30
|
-
const session = await context.tokenManager.getSession(profileName);
|
|
30
|
+
const session = await context.tokenManager.getSession(profileName, serverUrl);
|
|
31
31
|
const sessionState = context.tokenManager.sessionState(session);
|
|
32
32
|
const installs = flags["show-installs"]
|
|
33
33
|
? await Promise.all((await new InstallManifestStore().find(() => true)).map((entry) => inspectInstall(entry)))
|
package/dist/commands/tools.js
CHANGED
|
@@ -9,7 +9,7 @@ function challengedScope(error) {
|
|
|
9
9
|
}
|
|
10
10
|
async function loadToolsWithRetry(context, allowLogin) {
|
|
11
11
|
const { profileName, serverUrl } = await context.tokenManager.resolveProfile(context.globalOptions);
|
|
12
|
-
const existingSession = await context.tokenManager.getSession(profileName);
|
|
12
|
+
const existingSession = await context.tokenManager.getSession(profileName, serverUrl);
|
|
13
13
|
try {
|
|
14
14
|
return {
|
|
15
15
|
tools: await context.runtimeClient.listTools(serverUrl, existingSession?.accessToken),
|
|
@@ -30,7 +30,7 @@ async function loadToolsWithRetry(context, allowLogin) {
|
|
|
30
30
|
await context.tokenManager.login(context.globalOptions, {
|
|
31
31
|
scope: challengedScope(error)
|
|
32
32
|
});
|
|
33
|
-
const nextSession = await context.tokenManager.getSession(profileName);
|
|
33
|
+
const nextSession = await context.tokenManager.getSession(profileName, serverUrl);
|
|
34
34
|
return {
|
|
35
35
|
tools: await context.runtimeClient.listTools(serverUrl, nextSession?.accessToken),
|
|
36
36
|
...(nextSession ? { session: nextSession } : {})
|
package/docs/architecture.md
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
# Architecture
|
|
2
|
-
|
|
3
|
-
The Vibecodr CLI is a client of the hosted Vibecodr MCP gateway.
|
|
4
|
-
|
|
5
|
-
## Boundary
|
|
6
|
-
|
|
7
|
-
- hosted MCP gateway/server repo: `Vibecodr-MCP`
|
|
8
|
-
- CLI client repo: `Vibecodr-MCP-CLI`
|
|
9
|
-
- CLI package: `@vibecodr/cli`
|
|
10
|
-
- primary executable: `vibecodr`
|
|
11
|
-
- compatibility executable: `vibecodr-mcp`
|
|
12
|
-
- legacy package compatibility: `@vibecodr/mcp`
|
|
13
|
-
- default MCP URL: `https://openai.vibecodr.space/mcp`
|
|
14
|
-
|
|
15
|
-
This repo does not run the hosted server. It installs client config, performs CLI-owned OAuth, discovers the live tool catalog, and calls tools over Streamable HTTP MCP.
|
|
16
|
-
|
|
17
|
-
## Auth Ownership
|
|
18
|
-
|
|
19
|
-
`vibecodr login` stores OAuth tokens for the CLI profile only.
|
|
20
|
-
|
|
21
|
-
Codex, Cursor, VS Code, Windsurf, ChatGPT, and other MCP clients own separate OAuth sessions. Installing MCP config into those clients points them at the same server, but it does not copy CLI tokens into them.
|
|
22
|
-
|
|
23
|
-
## Why The Repos Are Separate
|
|
24
|
-
|
|
25
|
-
The CLI is permissively licensed and safe to distribute as a public client package. The hosted gateway implementation is source-available under a different license because it contains server-side orchestration, OAuth gateway behavior, Cloudflare deployment wiring, and Vibecodr API integration code.
|
|
26
|
-
|
|
27
|
-
The package name is `@vibecodr/cli` because this repo distributes the user-facing command-line client. The older `@vibecodr/mcp` package name is kept only as a compatibility/deprecation surface; the bare `vibecodr` executable remains the canonical user command.
|
|
28
|
-
|
|
29
|
-
Local config directories and secure-token service names intentionally keep their historical `vibecodr-mcp` / `@vibecodr/mcp` identifiers during this migration. Those names are storage compatibility keys, not the public npm package identity.
|
|
30
|
-
|
|
31
|
-
Keeping the repos separate makes the contract clear:
|
|
32
|
-
|
|
33
|
-
- users can use the hosted service normally
|
|
34
|
-
- users can install and inspect the CLI freely under this repo license
|
|
35
|
-
- commercial reuse of the gateway implementation remains governed by the server repo license
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
The Vibecodr CLI is a client of the hosted Vibecodr MCP gateway.
|
|
4
|
+
|
|
5
|
+
## Boundary
|
|
6
|
+
|
|
7
|
+
- hosted MCP gateway/server repo: `Vibecodr-MCP`
|
|
8
|
+
- CLI client repo: `Vibecodr-MCP-CLI`
|
|
9
|
+
- CLI package: `@vibecodr/cli`
|
|
10
|
+
- primary executable: `vibecodr`
|
|
11
|
+
- compatibility executable: `vibecodr-mcp`
|
|
12
|
+
- legacy package compatibility: `@vibecodr/mcp`
|
|
13
|
+
- default MCP URL: `https://openai.vibecodr.space/mcp`
|
|
14
|
+
|
|
15
|
+
This repo does not run the hosted server. It installs client config, performs CLI-owned OAuth, discovers the live tool catalog, and calls tools over Streamable HTTP MCP.
|
|
16
|
+
|
|
17
|
+
## Auth Ownership
|
|
18
|
+
|
|
19
|
+
`vibecodr login` stores OAuth tokens for the CLI profile only.
|
|
20
|
+
|
|
21
|
+
Codex, Cursor, VS Code, Windsurf, ChatGPT, and other MCP clients own separate OAuth sessions. Installing MCP config into those clients points them at the same server, but it does not copy CLI tokens into them.
|
|
22
|
+
|
|
23
|
+
## Why The Repos Are Separate
|
|
24
|
+
|
|
25
|
+
The CLI is permissively licensed and safe to distribute as a public client package. The hosted gateway implementation is source-available under a different license because it contains server-side orchestration, OAuth gateway behavior, Cloudflare deployment wiring, and Vibecodr API integration code.
|
|
26
|
+
|
|
27
|
+
The package name is `@vibecodr/cli` because this repo distributes the user-facing command-line client. The older `@vibecodr/mcp` package name is kept only as a compatibility/deprecation surface; the bare `vibecodr` executable remains the canonical user command.
|
|
28
|
+
|
|
29
|
+
Local config directories and secure-token service names intentionally keep their historical `vibecodr-mcp` / `@vibecodr/mcp` identifiers during this migration. Those names are storage compatibility keys, not the public npm package identity.
|
|
30
|
+
|
|
31
|
+
Keeping the repos separate makes the contract clear:
|
|
32
|
+
|
|
33
|
+
- users can use the hosted service normally
|
|
34
|
+
- users can install and inspect the CLI freely under this repo license
|
|
35
|
+
- commercial reuse of the gateway implementation remains governed by the server repo license
|
package/docs/auth.md
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
# Auth
|
|
2
2
|
|
|
3
|
-
`vibecodr login` authenticates the CLI itself to the hosted Vibecodr MCP server. It does not log Codex, Cursor, VS Code, Windsurf, ChatGPT, or any other MCP client into MCP.
|
|
3
|
+
`vibecodr login` authenticates the CLI itself to the hosted Vibecodr MCP server. It does not log Codex, Cursor, VS Code, Windsurf, ChatGPT, or any other MCP client into MCP.
|
|
4
|
+
|
|
5
|
+
Vibecodr has one hosted MCP gateway. The CLI is one client of that gateway, with its own local OAuth token store.
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- `vibecodr-mcp login`
|
|
7
|
+
Compatibility alias:
|
|
8
|
+
|
|
9
|
+
- `vibecodr-mcp login`
|
|
10
10
|
|
|
11
11
|
## Implemented now
|
|
12
12
|
|
|
13
13
|
- protected-resource and authorization-server discovery against the MCP server
|
|
14
14
|
- PKCE S256 enforcement
|
|
15
15
|
- loopback callback on `127.0.0.1`
|
|
16
|
-
- secure token storage in the OS credential store via `@napi-rs/keyring`
|
|
17
|
-
- proactive refresh before protected runtime commands when a refresh token is available
|
|
18
|
-
- `logout` local token deletion plus best-effort revocation
|
|
19
|
-
|
|
20
|
-
The plaintext file secret store is for local automated tests only. It is ignored unless both `VIBECDR_MCP_INSECURE_SECRET_STORE_PATH` and `VIBECDR_MCP_ENABLE_INSECURE_SECRET_STORE=true` are set.
|
|
21
|
-
|
|
22
|
-
The local config and secure-token storage keys intentionally keep their historical `vibecodr-mcp` / `@vibecodr/mcp` names during the `@vibecodr/cli` package rename. That preserves existing CLI sessions instead of forcing users to re-authenticate for a package-name migration.
|
|
23
|
-
|
|
24
|
-
Supported OS credential stores:
|
|
25
|
-
|
|
26
|
-
- macOS: Keychain
|
|
27
|
-
- Windows: Credential Manager
|
|
28
|
-
- Linux: Secret Service through a desktop keyring such as GNOME Keyring or KWallet
|
|
29
|
-
|
|
30
|
-
Linux systems need a running, unlocked keyring on the current D-Bus session. Headless Linux should use a real Secret Service setup for persistent CLI login, or let the target MCP client own its own OAuth flow instead of storing CLI tokens.
|
|
16
|
+
- secure token storage in the OS credential store via `@napi-rs/keyring`
|
|
17
|
+
- proactive refresh before protected runtime commands when a refresh token is available
|
|
18
|
+
- `logout` local token deletion plus best-effort revocation
|
|
19
|
+
|
|
20
|
+
The plaintext file secret store is for local automated tests only. It is ignored unless both `VIBECDR_MCP_INSECURE_SECRET_STORE_PATH` and `VIBECDR_MCP_ENABLE_INSECURE_SECRET_STORE=true` are set.
|
|
21
|
+
|
|
22
|
+
The local config and secure-token storage keys intentionally keep their historical `vibecodr-mcp` / `@vibecodr/mcp` names during the `@vibecodr/cli` package rename. That preserves existing CLI sessions instead of forcing users to re-authenticate for a package-name migration.
|
|
23
|
+
|
|
24
|
+
Supported OS credential stores:
|
|
25
|
+
|
|
26
|
+
- macOS: Keychain
|
|
27
|
+
- Windows: Credential Manager
|
|
28
|
+
- Linux: Secret Service through a desktop keyring such as GNOME Keyring or KWallet
|
|
29
|
+
|
|
30
|
+
Linux systems need a running, unlocked keyring on the current D-Bus session. Headless Linux should use a real Secret Service setup for persistent CLI login, or let the target MCP client own its own OAuth flow instead of storing CLI tokens.
|
|
31
31
|
|
|
32
32
|
## Registration modes
|
|
33
33
|
|
package/docs/commands.md
CHANGED
|
@@ -4,13 +4,16 @@ This page documents the command surface implemented in the current repo.
|
|
|
4
4
|
|
|
5
5
|
## Global flags
|
|
6
6
|
|
|
7
|
-
All commands accept:
|
|
8
|
-
|
|
9
|
-
- `--profile <name>`
|
|
10
|
-
- `--
|
|
11
|
-
- `--
|
|
12
|
-
- `--
|
|
13
|
-
|
|
7
|
+
All commands accept:
|
|
8
|
+
|
|
9
|
+
- `--profile <name>`
|
|
10
|
+
- `--json`
|
|
11
|
+
- `--verbose`
|
|
12
|
+
- `--non-interactive`
|
|
13
|
+
|
|
14
|
+
Alternate MCP servers are profile-scoped, not runtime overrides. Use
|
|
15
|
+
`vibecodr config profile create <name> --server-url <url>` and then login to
|
|
16
|
+
that profile; stored tokens are bound to the server that issued them.
|
|
14
17
|
|
|
15
18
|
## Commands
|
|
16
19
|
|
package/docs/install.md
CHANGED
|
@@ -15,14 +15,14 @@ node dist/bin/vibecodr-mcp.js install codex --json
|
|
|
15
15
|
After the package is published:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npx -y -p @vibecodr/cli vibecodr install codex
|
|
18
|
+
npx -y -p @vibecodr/cli vibecodr install codex
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
Direct CLI-only usage:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
npx -y -p @vibecodr/cli vibecodr login
|
|
25
|
-
npx -y -p @vibecodr/cli vibecodr tools --json
|
|
24
|
+
npx -y -p @vibecodr/cli vibecodr login
|
|
25
|
+
npx -y -p @vibecodr/cli vibecodr tools --json
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
## Client commands
|
package/docs/licensing.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# Licensing
|
|
2
2
|
|
|
3
|
-
This repository is the public Vibecodr CLI surface.
|
|
4
|
-
|
|
5
|
-
- Package name: `@vibecodr/cli`
|
|
6
|
-
- Primary executable name: `vibecodr`
|
|
7
|
-
- Compatibility executable name: `vibecodr-mcp`
|
|
8
|
-
- Legacy package compatibility: `@vibecodr/mcp`
|
|
3
|
+
This repository is the public Vibecodr CLI surface.
|
|
4
|
+
|
|
5
|
+
- Package name: `@vibecodr/cli`
|
|
6
|
+
- Primary executable name: `vibecodr`
|
|
7
|
+
- Compatibility executable name: `vibecodr-mcp`
|
|
8
|
+
- Legacy package compatibility: `@vibecodr/mcp`
|
|
9
9
|
- Repo scope: direct CLI runtime, auth, diagnostics, and later thin installer adapters
|
|
10
10
|
- License: Apache-2.0
|
|
11
11
|
|
|
12
|
-
The hosted MCP gateway/server remains separate from this repo. That separation keeps hosted-service use distinct from any source-code reuse terms applied to the server implementation repo.
|
|
13
|
-
|
|
14
|
-
Practical split:
|
|
15
|
-
|
|
16
|
-
- this CLI repo governs distribution, modification, and reuse of the public client code
|
|
17
|
-
- the hosted Vibecodr MCP service remains governed by Vibecodr service terms for account holders
|
|
18
|
-
- the server implementation repo can carry different source-available terms without changing whether a commercial team may use the hosted service
|
|
12
|
+
The hosted MCP gateway/server remains separate from this repo. That separation keeps hosted-service use distinct from any source-code reuse terms applied to the server implementation repo.
|
|
19
13
|
|
|
20
|
-
|
|
14
|
+
Practical split:
|
|
15
|
+
|
|
16
|
+
- this CLI repo governs distribution, modification, and reuse of the public client code
|
|
17
|
+
- the hosted Vibecodr MCP service remains governed by Vibecodr service terms for account holders
|
|
18
|
+
- the server implementation repo can carry different source-available terms without changing whether a commercial team may use the hosted service
|
|
19
|
+
|
|
20
|
+
See [`architecture.md`](./architecture.md) for the client/server boundary.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -30,15 +30,15 @@ Run:
|
|
|
30
30
|
vibecodr doctor --json
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
If the `secret-store` check fails, the CLI cannot safely store tokens yet.
|
|
34
|
-
|
|
35
|
-
The plaintext file secret store is intentionally test-only. If `VIBECDR_MCP_INSECURE_SECRET_STORE_PATH` is set without `VIBECDR_MCP_ENABLE_INSECURE_SECRET_STORE=true`, the CLI refuses to start rather than silently storing tokens outside the OS credential store.
|
|
36
|
-
|
|
37
|
-
Platform notes:
|
|
38
|
-
|
|
39
|
-
- macOS uses Keychain. Unlock the login keychain and approve Terminal or Node access if prompted.
|
|
40
|
-
- Windows uses Credential Manager. Run from a normal signed-in desktop session with Credential Manager available.
|
|
41
|
-
- Linux uses Secret Service. Install libsecret support and run from a session with an unlocked GNOME Keyring or KWallet. Headless Linux needs an explicit Secret Service setup for persistent CLI login.
|
|
33
|
+
If the `secret-store` check fails, the CLI cannot safely store tokens yet.
|
|
34
|
+
|
|
35
|
+
The plaintext file secret store is intentionally test-only. If `VIBECDR_MCP_INSECURE_SECRET_STORE_PATH` is set without `VIBECDR_MCP_ENABLE_INSECURE_SECRET_STORE=true`, the CLI refuses to start rather than silently storing tokens outside the OS credential store.
|
|
36
|
+
|
|
37
|
+
Platform notes:
|
|
38
|
+
|
|
39
|
+
- macOS uses Keychain. Unlock the login keychain and approve Terminal or Node access if prompted.
|
|
40
|
+
- Windows uses Credential Manager. Run from a normal signed-in desktop session with Credential Manager available.
|
|
41
|
+
- Linux uses Secret Service. Install libsecret support and run from a session with an unlocked GNOME Keyring or KWallet. Headless Linux needs an explicit Secret Service setup for persistent CLI login.
|
|
42
42
|
|
|
43
43
|
## Proxy or TLS issues
|
|
44
44
|
|
|
@@ -81,9 +81,9 @@ The CLI writes the native path.
|
|
|
81
81
|
|
|
82
82
|
Codex config install and CLI login are separate.
|
|
83
83
|
|
|
84
|
-
- `install codex` configures Codex
|
|
85
|
-
- `login` authenticates the Vibecodr CLI only
|
|
86
|
-
- Codex will still own its own OAuth behavior when you use the server inside Codex
|
|
84
|
+
- `install codex` configures Codex
|
|
85
|
+
- `login` authenticates the Vibecodr CLI only
|
|
86
|
+
- Codex will still own its own OAuth behavior when you use the server inside Codex
|
|
87
87
|
|
|
88
88
|
## VS Code CLI not found
|
|
89
89
|
|