nubase_cli 0.1.6 → 0.1.7
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 +9 -7
- package/dist/src/index.js +7 -1
- package/dist/src/install-skills.js +37 -13
- package/package.json +1 -1
- package/skills/nubase/SKILL.md +5 -3
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Installing skills starts a one-time browser authorization session and prints an
|
|
|
16
16
|
npx -y nubase_cli@latest install-skills
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
This installs the bundled Claude/Codex skills into your user skill directories, writes project MCP config for Claude Code, and starts browser authorization. Open the printed URL, sign in to Studio, choose a project, and approve. The URL includes a per-session UUID and points back to the temporary localhost callback started by the install command. After approval, the CLI writes project-local `.nubase/config.json` and closes the localhost callback server.
|
|
19
|
+
This installs the bundled Claude/Codex skills into your user skill directories, writes a local project MCP bridge under `.nubase/mcp-bridge`, writes project MCP config for Claude Code, and starts browser authorization. Open the printed URL, sign in to Studio, choose a project, and approve. The URL includes a per-session UUID and points back to the temporary localhost callback started by the install command. After approval, the CLI writes project-local `.nubase/config.json` and closes the localhost callback server.
|
|
20
20
|
|
|
21
21
|
Restart Claude Code in the project after installing, then run `/mcp` and confirm `nubase` is connected.
|
|
22
22
|
|
|
@@ -69,11 +69,12 @@ node packages/mcp-bridge/dist/src/index.js
|
|
|
69
69
|
{
|
|
70
70
|
"mcpServers": {
|
|
71
71
|
"nubase": {
|
|
72
|
-
"
|
|
73
|
-
"
|
|
72
|
+
"type": "stdio",
|
|
73
|
+
"command": "node",
|
|
74
|
+
"args": ["/absolute/project/path/.nubase/mcp-bridge/dist/src/index.js"],
|
|
74
75
|
"env": {
|
|
75
76
|
"NUBASE_AGENT_ID": "claude-code",
|
|
76
|
-
"NUBASE_CONFIG": "
|
|
77
|
+
"NUBASE_CONFIG": "/absolute/project/path/.nubase/config.json"
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
}
|
|
@@ -98,14 +99,15 @@ Targets:
|
|
|
98
99
|
|
|
99
100
|
Use `--skills-scope project` to write `.claude/skills/nubase/**` and `.codex/skills/nubase/**` in the current project instead.
|
|
100
101
|
|
|
101
|
-
By default, when the target includes `claude`, the command also creates or merges project `.mcp.json`:
|
|
102
|
+
By default, when the target includes `claude`, the command also copies the local MCP bridge to `.nubase/mcp-bridge` and creates or merges project `.mcp.json`:
|
|
102
103
|
|
|
103
104
|
```json
|
|
104
105
|
{
|
|
105
106
|
"mcpServers": {
|
|
106
107
|
"nubase": {
|
|
107
|
-
"
|
|
108
|
-
"
|
|
108
|
+
"type": "stdio",
|
|
109
|
+
"command": "node",
|
|
110
|
+
"args": ["/absolute/project/path/.nubase/mcp-bridge/dist/src/index.js"],
|
|
109
111
|
"env": {
|
|
110
112
|
"NUBASE_AGENT_ID": "claude-code",
|
|
111
113
|
"NUBASE_CONFIG": "/absolute/project/path/.nubase/config.json"
|
package/dist/src/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { installSkills, parseInstallArgs } from './install-skills.js';
|
|
|
6
6
|
import { McpStdioServer } from './mcp-stdio.js';
|
|
7
7
|
import { NubaseClient } from './nubase-client.js';
|
|
8
8
|
import { callTool, TOOLS } from './tools.js';
|
|
9
|
-
const CLI_VERSION = '0.1.
|
|
9
|
+
const CLI_VERSION = '0.1.7';
|
|
10
10
|
if (process.argv[2] === 'install-skills') {
|
|
11
11
|
const options = parseInstallArgs(process.argv.slice(3));
|
|
12
12
|
const installed = await installSkills(options);
|
|
@@ -20,6 +20,9 @@ if (process.argv[2] === 'install-skills') {
|
|
|
20
20
|
else if (file.endsWith('.gitignore')) {
|
|
21
21
|
console.error(`Ensured Nubase local config is ignored by git: ${file}`);
|
|
22
22
|
}
|
|
23
|
+
else if (file.includes(`${defaultPathSep()}.nubase${defaultPathSep()}mcp-bridge${defaultPathSep()}`)) {
|
|
24
|
+
console.error(`Installed Nubase local MCP bridge: ${file}`);
|
|
25
|
+
}
|
|
23
26
|
else {
|
|
24
27
|
console.error(`Installed Nubase skill: ${file}`);
|
|
25
28
|
}
|
|
@@ -80,3 +83,6 @@ const server = new McpStdioServer(async (request) => {
|
|
|
80
83
|
}
|
|
81
84
|
});
|
|
82
85
|
server.start();
|
|
86
|
+
function defaultPathSep() {
|
|
87
|
+
return process.platform === 'win32' ? '\\' : '/';
|
|
88
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cp, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
1
|
+
import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
@@ -19,11 +19,16 @@ export async function installSkills(options) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
const mcpTargets = resolveMcpTargets(options.mcp ?? 'claude', targets);
|
|
22
|
+
let mcpCommand = null;
|
|
23
|
+
if (mcpTargets.length > 0) {
|
|
24
|
+
mcpCommand = await installProjectMcpBridge(options.projectDir);
|
|
25
|
+
installed.push(mcpCommand.entrypoint);
|
|
26
|
+
}
|
|
22
27
|
if (mcpTargets.includes('claude')) {
|
|
23
|
-
installed.push(await installClaudeMcpConfig(options.projectDir, configPath));
|
|
28
|
+
installed.push(await installClaudeMcpConfig(options.projectDir, configPath, mcpCommand));
|
|
24
29
|
}
|
|
25
30
|
if (mcpTargets.includes('codex')) {
|
|
26
|
-
installed.push(await installCodexMcpConfig(options.projectDir, configPath));
|
|
31
|
+
installed.push(await installCodexMcpConfig(options.projectDir, configPath, mcpCommand));
|
|
27
32
|
}
|
|
28
33
|
installed.push(await ensureProjectGitignore(options.projectDir));
|
|
29
34
|
return installed;
|
|
@@ -99,9 +104,11 @@ export function parseInstallArgs(argv) {
|
|
|
99
104
|
return { target, projectDir, authorize, authArgs, skills, skillsScope, mcp, configPath };
|
|
100
105
|
}
|
|
101
106
|
function bundledSkillDir() {
|
|
107
|
+
return path.join(bundledPackageRoot(), 'skills', 'nubase');
|
|
108
|
+
}
|
|
109
|
+
function bundledPackageRoot() {
|
|
102
110
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
103
|
-
|
|
104
|
-
return path.join(packageRoot, 'skills', 'nubase');
|
|
111
|
+
return path.resolve(here, '..', '..');
|
|
105
112
|
}
|
|
106
113
|
function skillDestDir(target, scope, projectDir, homeDir) {
|
|
107
114
|
if (scope === 'project') {
|
|
@@ -119,15 +126,30 @@ function resolveMcpTargets(mcp, skillTargets) {
|
|
|
119
126
|
const requested = mcp === 'both' ? ['claude', 'codex'] : [mcp];
|
|
120
127
|
return requested.filter((target) => skillTargets.includes(target));
|
|
121
128
|
}
|
|
122
|
-
async function
|
|
129
|
+
async function installProjectMcpBridge(projectDir) {
|
|
130
|
+
const packageRoot = bundledPackageRoot();
|
|
131
|
+
const destRoot = path.join(projectDir, '.nubase', 'mcp-bridge');
|
|
132
|
+
await rm(destRoot, { recursive: true, force: true });
|
|
133
|
+
await mkdir(destRoot, { recursive: true, mode: 0o700 });
|
|
134
|
+
await cp(path.join(packageRoot, 'dist', 'src'), path.join(destRoot, 'dist', 'src'), { recursive: true, force: true });
|
|
135
|
+
await cp(path.join(packageRoot, 'skills'), path.join(destRoot, 'skills'), { recursive: true, force: true });
|
|
136
|
+
await cp(path.join(packageRoot, 'package.json'), path.join(destRoot, 'package.json'), { force: true });
|
|
137
|
+
const entrypoint = path.join(destRoot, 'dist', 'src', 'index.js');
|
|
138
|
+
return {
|
|
139
|
+
command: 'node',
|
|
140
|
+
args: [entrypoint],
|
|
141
|
+
entrypoint,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async function installClaudeMcpConfig(projectDir, nubaseConfigPath, mcpCommand) {
|
|
123
145
|
const mcpConfigPath = path.join(projectDir, '.mcp.json');
|
|
124
146
|
const config = await readProjectMcpConfig(mcpConfigPath);
|
|
125
147
|
config.mcpServers = {
|
|
126
148
|
...(config.mcpServers ?? {}),
|
|
127
149
|
nubase: {
|
|
128
150
|
type: 'stdio',
|
|
129
|
-
command: 'npx',
|
|
130
|
-
args: ['-y', 'nubase_cli@latest'],
|
|
151
|
+
command: mcpCommand?.command ?? 'npx',
|
|
152
|
+
args: mcpCommand?.args ?? ['-y', 'nubase_cli@latest'],
|
|
131
153
|
env: {
|
|
132
154
|
NUBASE_AGENT_ID: 'claude-code',
|
|
133
155
|
NUBASE_CONFIG: nubaseConfigPath,
|
|
@@ -137,11 +159,11 @@ async function installClaudeMcpConfig(projectDir, nubaseConfigPath) {
|
|
|
137
159
|
await writeFile(mcpConfigPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
|
|
138
160
|
return mcpConfigPath;
|
|
139
161
|
}
|
|
140
|
-
async function installCodexMcpConfig(projectDir, nubaseConfigPath) {
|
|
162
|
+
async function installCodexMcpConfig(projectDir, nubaseConfigPath, mcpCommand) {
|
|
141
163
|
const configPath = path.join(projectDir, '.codex', 'config.toml');
|
|
142
164
|
await mkdir(path.dirname(configPath), { recursive: true });
|
|
143
165
|
const existing = await readTextIfExists(configPath);
|
|
144
|
-
const block = codexMcpBlock(nubaseConfigPath);
|
|
166
|
+
const block = codexMcpBlock(nubaseConfigPath, mcpCommand);
|
|
145
167
|
const next = upsertCodexMcpBlock(existing, block);
|
|
146
168
|
await writeFile(configPath, next, 'utf8');
|
|
147
169
|
return configPath;
|
|
@@ -166,12 +188,14 @@ async function readTextIfExists(filePath) {
|
|
|
166
188
|
throw err;
|
|
167
189
|
}
|
|
168
190
|
}
|
|
169
|
-
function codexMcpBlock(configPath) {
|
|
191
|
+
function codexMcpBlock(configPath, mcpCommand) {
|
|
192
|
+
const command = mcpCommand?.command ?? 'npx';
|
|
193
|
+
const args = mcpCommand?.args ?? ['-y', 'nubase_cli@latest'];
|
|
170
194
|
return [
|
|
171
195
|
'[mcp_servers.nubase]',
|
|
172
196
|
'type = "stdio"',
|
|
173
|
-
|
|
174
|
-
|
|
197
|
+
`command = "${escapeTomlString(command)}"`,
|
|
198
|
+
`args = [${args.map((arg) => `"${escapeTomlString(arg)}"`).join(', ')}]`,
|
|
175
199
|
'startup_timeout_sec = 30',
|
|
176
200
|
'',
|
|
177
201
|
'[mcp_servers.nubase.env]',
|
package/package.json
CHANGED
package/skills/nubase/SKILL.md
CHANGED
|
@@ -67,6 +67,7 @@ By default this writes:
|
|
|
67
67
|
- `~/.claude/skills/nubase/**`
|
|
68
68
|
- `~/.codex/skills/nubase/**`
|
|
69
69
|
- project `.mcp.json` with a `nubase` stdio MCP server for Claude Code
|
|
70
|
+
- project `.nubase/mcp-bridge/**` local MCP bridge runtime, so agent startup does not depend on `npx @latest`
|
|
70
71
|
- project `.nubase/config.json` after browser authorization
|
|
71
72
|
|
|
72
73
|
After installing, restart Claude Code in the project and run `/mcp`. The `nubase` server must be connected before this skill can call `nubase_overview`, `memory_context`, or other MCP tools.
|
|
@@ -77,11 +78,12 @@ Expected `.mcp.json` shape:
|
|
|
77
78
|
{
|
|
78
79
|
"mcpServers": {
|
|
79
80
|
"nubase": {
|
|
80
|
-
"
|
|
81
|
-
"
|
|
81
|
+
"type": "stdio",
|
|
82
|
+
"command": "node",
|
|
83
|
+
"args": ["/absolute/project/path/.nubase/mcp-bridge/dist/src/index.js"],
|
|
82
84
|
"env": {
|
|
83
85
|
"NUBASE_AGENT_ID": "claude-code",
|
|
84
|
-
"NUBASE_CONFIG": "
|
|
86
|
+
"NUBASE_CONFIG": "/absolute/project/path/.nubase/config.json"
|
|
85
87
|
}
|
|
86
88
|
}
|
|
87
89
|
}
|