@zokizuan/satori-cli 0.4.0 → 0.4.2
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/LICENSE +1 -1
- package/README.md +38 -7
- package/dist/doctor.js +39 -2
- package/dist/install.js +76 -7
- package/package.json +2 -2
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -5,14 +5,16 @@ Installer and shell client for Satori MCP. Use this package to configure support
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npx -y @zokizuan/satori-cli@0.4.
|
|
9
|
-
npx -y @zokizuan/satori-cli@0.4.
|
|
8
|
+
npx -y @zokizuan/satori-cli@0.4.2 install --client all
|
|
9
|
+
npx -y @zokizuan/satori-cli@0.4.2 doctor
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
Supported clients are `codex`, `claude`, `opencode`, and `all`.
|
|
13
13
|
|
|
14
14
|
The installer performs package resolution once, stores the MCP server under `~/.satori/mcp-runtime/`, writes a stable launcher at `~/.satori/bin/satori-mcp.js`, and writes client-specific config that starts the launcher directly with Node. Resident MCP startup should not run `npx` or require a custom long startup timeout.
|
|
15
15
|
|
|
16
|
+
Treat `~/.satori/` as installer-owned state. The public setup path is the installer command above, not manual copying of runtime cache paths into each harness.
|
|
17
|
+
|
|
16
18
|
The installer only manages Satori-owned config and the first-party workflow skill:
|
|
17
19
|
|
|
18
20
|
- `satori`
|
|
@@ -20,15 +22,44 @@ The installer only manages Satori-owned config and the first-party workflow skil
|
|
|
20
22
|
## Commands
|
|
21
23
|
|
|
22
24
|
```bash
|
|
23
|
-
npx -y @zokizuan/satori-cli@0.4.
|
|
24
|
-
npx -y @zokizuan/satori-cli@0.4.
|
|
25
|
-
npx -y @zokizuan/satori-cli@0.4.
|
|
26
|
-
npx -y @zokizuan/satori-cli@0.4.
|
|
27
|
-
npx -y @zokizuan/satori-cli@0.4.
|
|
25
|
+
npx -y @zokizuan/satori-cli@0.4.2 install --client codex
|
|
26
|
+
npx -y @zokizuan/satori-cli@0.4.2 install --client claude
|
|
27
|
+
npx -y @zokizuan/satori-cli@0.4.2 install --client opencode
|
|
28
|
+
npx -y @zokizuan/satori-cli@0.4.2 install --client all --dry-run
|
|
29
|
+
npx -y @zokizuan/satori-cli@0.4.2 uninstall --client codex
|
|
28
30
|
```
|
|
29
31
|
|
|
30
32
|
`doctor` checks Node, package visibility, provider env, and Milvus env without starting an MCP client.
|
|
31
33
|
|
|
34
|
+
Typical first run:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx -y @zokizuan/satori-cli@0.4.2 install --client all
|
|
38
|
+
npx -y @zokizuan/satori-cli@0.4.2 doctor
|
|
39
|
+
# restart your MCP client
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The installer writes launcher config only. Runtime provider settings are read when the MCP client starts.
|
|
43
|
+
|
|
44
|
+
Supported client installs expose the Satori runtime variable names in the client config:
|
|
45
|
+
|
|
46
|
+
- Codex writes active `env_vars` forwarding plus an optional commented `[mcp_servers.satori.env]` template in `~/.codex/config.toml`.
|
|
47
|
+
- Claude Code writes `mcpServers.satori.env` in `~/.claude.json` with `${VAR:-}` pass-through values.
|
|
48
|
+
- OpenCode writes `mcp.satori.environment` in `~/.config/opencode/opencode.json` with `{env:VAR}` pass-through values.
|
|
49
|
+
|
|
50
|
+
If you want a client to store literal values, replace the generated pass-through value for that client. In Codex, uncomment or add this table outside the installer-managed launcher block so reinstalls keep your edits:
|
|
51
|
+
|
|
52
|
+
```toml
|
|
53
|
+
[mcp_servers.satori.env]
|
|
54
|
+
EMBEDDING_PROVIDER = "VoyageAI"
|
|
55
|
+
EMBEDDING_MODEL = "voyage-4-large"
|
|
56
|
+
EMBEDDING_OUTPUT_DIMENSION = "1024"
|
|
57
|
+
VOYAGEAI_API_KEY = "pa-..."
|
|
58
|
+
VOYAGEAI_RERANKER_MODEL = "rerank-2.5"
|
|
59
|
+
MILVUS_ADDRESS = "https://your-zilliz-endpoint"
|
|
60
|
+
MILVUS_TOKEN = "your-zilliz-token"
|
|
61
|
+
```
|
|
62
|
+
|
|
32
63
|
## Direct Tool Calls
|
|
33
64
|
|
|
34
65
|
```bash
|
package/dist/doctor.js
CHANGED
|
@@ -7,6 +7,32 @@ function parseNodeMajor(version) {
|
|
|
7
7
|
function selectedProvider(env) {
|
|
8
8
|
return env.EMBEDDING_PROVIDER || "VoyageAI";
|
|
9
9
|
}
|
|
10
|
+
function defaultModelForProvider(provider) {
|
|
11
|
+
switch (provider) {
|
|
12
|
+
case "OpenAI":
|
|
13
|
+
return "text-embedding-3-small";
|
|
14
|
+
case "VoyageAI":
|
|
15
|
+
return "voyage-4-large";
|
|
16
|
+
case "Gemini":
|
|
17
|
+
return "gemini-embedding-001";
|
|
18
|
+
case "Ollama":
|
|
19
|
+
return "nomic-embed-text";
|
|
20
|
+
default:
|
|
21
|
+
return "voyage-4-large";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function selectedModel(env, provider) {
|
|
25
|
+
if (provider === "Ollama") {
|
|
26
|
+
return env.OLLAMA_MODEL || env.EMBEDDING_MODEL || defaultModelForProvider(provider);
|
|
27
|
+
}
|
|
28
|
+
return env.EMBEDDING_MODEL || defaultModelForProvider(provider);
|
|
29
|
+
}
|
|
30
|
+
function selectedDimension(env, provider) {
|
|
31
|
+
if (env.EMBEDDING_OUTPUT_DIMENSION) {
|
|
32
|
+
return env.EMBEDDING_OUTPUT_DIMENSION;
|
|
33
|
+
}
|
|
34
|
+
return provider === "VoyageAI" ? "1024" : "provider default";
|
|
35
|
+
}
|
|
10
36
|
function requiredEmbeddingEnv(provider) {
|
|
11
37
|
switch (provider) {
|
|
12
38
|
case "OpenAI":
|
|
@@ -62,17 +88,25 @@ export function runDoctor(options = {}) {
|
|
|
62
88
|
nextSteps.push("Verify npm can access @zokizuan/satori-mcp from this machine.");
|
|
63
89
|
}
|
|
64
90
|
const provider = selectedProvider(env);
|
|
91
|
+
addCheck(checks, "embedding_provider", "ok", `Embedding provider: ${provider}.`);
|
|
92
|
+
addCheck(checks, "embedding_model", "ok", `Embedding model: ${selectedModel(env, provider)}.`);
|
|
93
|
+
addCheck(checks, "embedding_dimension", "ok", `Embedding output dimension: ${selectedDimension(env, provider)}.`);
|
|
65
94
|
const requiredKey = requiredEmbeddingEnv(provider);
|
|
66
95
|
if (requiredKey && !env[requiredKey]) {
|
|
67
96
|
addCheck(checks, "embedding_provider_env", "error", `${provider} requires ${requiredKey}.`);
|
|
68
|
-
|
|
97
|
+
if (provider === "VoyageAI") {
|
|
98
|
+
nextSteps.push("Set VOYAGEAI_API_KEY from the Voyage AI dashboard API keys page.");
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
nextSteps.push(`Set ${requiredKey}.`);
|
|
102
|
+
}
|
|
69
103
|
}
|
|
70
104
|
else {
|
|
71
105
|
addCheck(checks, "embedding_provider_env", "ok", requiredKey ? `${requiredKey} is present.` : `${provider} does not require an API key.`);
|
|
72
106
|
}
|
|
73
107
|
if (!env.MILVUS_ADDRESS) {
|
|
74
108
|
addCheck(checks, "milvus_address", "error", "MILVUS_ADDRESS is required for index/search/clear operations.");
|
|
75
|
-
nextSteps.push("Set MILVUS_ADDRESS.");
|
|
109
|
+
nextSteps.push("Set MILVUS_ADDRESS to a Zilliz Cloud public endpoint or local Milvus address such as localhost:19530.");
|
|
76
110
|
}
|
|
77
111
|
else {
|
|
78
112
|
addCheck(checks, "milvus_address", "ok", "MILVUS_ADDRESS is present.");
|
|
@@ -83,6 +117,9 @@ export function runDoctor(options = {}) {
|
|
|
83
117
|
else {
|
|
84
118
|
addCheck(checks, "milvus_token", "ok", "MILVUS_TOKEN is not set; local/unauthenticated Milvus endpoints are supported.");
|
|
85
119
|
}
|
|
120
|
+
if (nextSteps.length > 0) {
|
|
121
|
+
nextSteps.push("Restart your MCP client after changing Satori environment variables.");
|
|
122
|
+
}
|
|
86
123
|
return {
|
|
87
124
|
status: overallStatus(checks),
|
|
88
125
|
checks,
|
package/dist/install.js
CHANGED
|
@@ -8,12 +8,47 @@ import { CliError } from "./errors.js";
|
|
|
8
8
|
import { resolveManagedPackageSpecifier } from "./managed-package.js";
|
|
9
9
|
const MANAGED_BLOCK_START = "# >>> satori-cli managed satori start >>>";
|
|
10
10
|
const MANAGED_BLOCK_END = "# <<< satori-cli managed satori end <<<";
|
|
11
|
+
const CODEX_ENV_TEMPLATE_START = "# >>> satori-cli optional satori env template >>>";
|
|
12
|
+
const CODEX_ENV_TEMPLATE_END = "# <<< satori-cli optional satori env template <<<";
|
|
11
13
|
const INSTRUCTIONS_BLOCK_START = "<!-- satori-mcp:start -->";
|
|
12
14
|
const INSTRUCTIONS_BLOCK_END = "<!-- satori-mcp:end -->";
|
|
13
15
|
const OWNED_SKILL_DIRS = ["satori"];
|
|
14
16
|
const MANAGED_RUNTIME_DIR = "mcp-runtime";
|
|
15
17
|
const MANAGED_BIN_DIR = "bin";
|
|
16
18
|
const MANAGED_LAUNCHER_FILE = "satori-mcp.js";
|
|
19
|
+
const SATORI_RUNTIME_ENV_VARS = [
|
|
20
|
+
"EMBEDDING_PROVIDER",
|
|
21
|
+
"EMBEDDING_MODEL",
|
|
22
|
+
"EMBEDDING_OUTPUT_DIMENSION",
|
|
23
|
+
"OPENAI_API_KEY",
|
|
24
|
+
"OPENAI_BASE_URL",
|
|
25
|
+
"VOYAGEAI_API_KEY",
|
|
26
|
+
"VOYAGEAI_RERANKER_MODEL",
|
|
27
|
+
"GEMINI_API_KEY",
|
|
28
|
+
"GEMINI_BASE_URL",
|
|
29
|
+
"OLLAMA_HOST",
|
|
30
|
+
"OLLAMA_MODEL",
|
|
31
|
+
"MILVUS_ADDRESS",
|
|
32
|
+
"MILVUS_TOKEN",
|
|
33
|
+
"READ_FILE_MAX_LINES",
|
|
34
|
+
"MCP_ENABLE_WATCHER",
|
|
35
|
+
"MCP_WATCH_DEBOUNCE_MS",
|
|
36
|
+
];
|
|
37
|
+
const CODEX_ENV_TEMPLATE_LINES = [
|
|
38
|
+
CODEX_ENV_TEMPLATE_START,
|
|
39
|
+
"# Optional direct Codex env values. Uncomment/fill these if you prefer",
|
|
40
|
+
"# ~/.codex/config.toml to store Satori runtime settings directly.",
|
|
41
|
+
"# This template is outside the launcher block so reinstall keeps edits.",
|
|
42
|
+
"# [mcp_servers.satori.env]",
|
|
43
|
+
"# EMBEDDING_PROVIDER = \"VoyageAI\"",
|
|
44
|
+
"# EMBEDDING_MODEL = \"voyage-4-large\"",
|
|
45
|
+
"# EMBEDDING_OUTPUT_DIMENSION = \"1024\"",
|
|
46
|
+
"# VOYAGEAI_API_KEY = \"pa-...\"",
|
|
47
|
+
"# VOYAGEAI_RERANKER_MODEL = \"rerank-2.5\"",
|
|
48
|
+
"# MILVUS_ADDRESS = \"https://your-zilliz-endpoint\"",
|
|
49
|
+
"# MILVUS_TOKEN = \"your-zilliz-token\"",
|
|
50
|
+
CODEX_ENV_TEMPLATE_END,
|
|
51
|
+
];
|
|
17
52
|
const OPENCODE_INSTRUCTIONS = `# Satori MCP
|
|
18
53
|
|
|
19
54
|
This project uses Satori MCP for semantic code search, deterministic navigation, and index lifecycle management.
|
|
@@ -56,7 +91,7 @@ function resolveClientTargets(homeDir) {
|
|
|
56
91
|
},
|
|
57
92
|
{
|
|
58
93
|
client: "claude",
|
|
59
|
-
configPath: path.join(homeDir, ".claude
|
|
94
|
+
configPath: path.join(homeDir, ".claude.json"),
|
|
60
95
|
companion: {
|
|
61
96
|
kind: "skills",
|
|
62
97
|
path: path.join(homeDir, ".claude", "skills"),
|
|
@@ -103,6 +138,21 @@ function toTomlString(value) {
|
|
|
103
138
|
function buildTomlArray(values) {
|
|
104
139
|
return `[${values.map(toTomlString).join(", ")}]`;
|
|
105
140
|
}
|
|
141
|
+
function runtimeEnvMap(valueForName) {
|
|
142
|
+
return Object.fromEntries(SATORI_RUNTIME_ENV_VARS.map((name) => [name, valueForName(name)]));
|
|
143
|
+
}
|
|
144
|
+
function objectValue(value) {
|
|
145
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
function mergeRuntimeEnv(existing, defaults) {
|
|
151
|
+
return {
|
|
152
|
+
...defaults,
|
|
153
|
+
...(objectValue(existing) ?? {}),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
106
156
|
function packageNameFromSpecifier(packageSpecifier) {
|
|
107
157
|
if (packageSpecifier.startsWith("@")) {
|
|
108
158
|
const versionMarker = packageSpecifier.indexOf("@", 1);
|
|
@@ -258,10 +308,25 @@ function buildCodexManagedBlock(runtimeCommand) {
|
|
|
258
308
|
"[mcp_servers.satori]",
|
|
259
309
|
`command = ${toTomlString(runtimeCommand.command)}`,
|
|
260
310
|
`args = ${buildTomlArray(runtimeCommand.args)}`,
|
|
311
|
+
"# Satori reads provider/vector settings from environment at MCP startup.",
|
|
312
|
+
"# env_vars forwards these names from Codex's parent environment when set.",
|
|
313
|
+
`env_vars = ${buildTomlArray([...SATORI_RUNTIME_ENV_VARS])}`,
|
|
261
314
|
MANAGED_BLOCK_END,
|
|
262
315
|
"",
|
|
263
316
|
].join("\n");
|
|
264
317
|
}
|
|
318
|
+
function buildCodexEnvTemplateBlock() {
|
|
319
|
+
return `${CODEX_ENV_TEMPLATE_LINES.join("\n")}\n`;
|
|
320
|
+
}
|
|
321
|
+
function codexHasSatoriEnvTable(content) {
|
|
322
|
+
return /^\s*\[mcp_servers\.satori\.env\]\s*$/m.test(content);
|
|
323
|
+
}
|
|
324
|
+
function ensureCodexEnvTemplate(content) {
|
|
325
|
+
if (content.includes(CODEX_ENV_TEMPLATE_START) || codexHasSatoriEnvTable(content)) {
|
|
326
|
+
return content;
|
|
327
|
+
}
|
|
328
|
+
return `${normalizeTrailingNewline(content)}\n${buildCodexEnvTemplateBlock()}`;
|
|
329
|
+
}
|
|
265
330
|
function codexHasUnmanagedSatoriSection(content) {
|
|
266
331
|
if (!content.includes("[mcp_servers.satori]")) {
|
|
267
332
|
return false;
|
|
@@ -284,6 +349,7 @@ function prepareCodexInstall(filePath, runtimeCommand) {
|
|
|
284
349
|
else {
|
|
285
350
|
next = `${normalizeTrailingNewline(current)}\n${managedBlock}`;
|
|
286
351
|
}
|
|
352
|
+
next = ensureCodexEnvTemplate(next);
|
|
287
353
|
return {
|
|
288
354
|
changed: next !== current,
|
|
289
355
|
apply: () => {
|
|
@@ -337,10 +403,12 @@ function parseJsonObject(filePath) {
|
|
|
337
403
|
}
|
|
338
404
|
return parsed;
|
|
339
405
|
}
|
|
340
|
-
function buildClaudeServerConfig(runtimeCommand) {
|
|
406
|
+
function buildClaudeServerConfig(runtimeCommand, existing) {
|
|
341
407
|
return {
|
|
408
|
+
type: "stdio",
|
|
342
409
|
command: runtimeCommand.command,
|
|
343
410
|
args: runtimeCommand.args,
|
|
411
|
+
env: mergeRuntimeEnv(existing?.env, runtimeEnvMap((name) => `\${${name}:-}`)),
|
|
344
412
|
};
|
|
345
413
|
}
|
|
346
414
|
function isManagedLauncherPath(value) {
|
|
@@ -366,7 +434,8 @@ function isManagedClaudeEntry(value) {
|
|
|
366
434
|
function prepareClaudeInstall(filePath, runtimeCommand) {
|
|
367
435
|
const currentObject = parseJsonObject(filePath);
|
|
368
436
|
const currentSerialized = JSON.stringify(currentObject);
|
|
369
|
-
const
|
|
437
|
+
const existingSatori = objectValue(currentObject.mcpServers?.satori);
|
|
438
|
+
const desiredServer = buildClaudeServerConfig(runtimeCommand, existingSatori);
|
|
370
439
|
const mcpServersValue = currentObject.mcpServers;
|
|
371
440
|
let mcpServers;
|
|
372
441
|
if (mcpServersValue === undefined) {
|
|
@@ -378,8 +447,7 @@ function prepareClaudeInstall(filePath, runtimeCommand) {
|
|
|
378
447
|
else {
|
|
379
448
|
throw new CliError("E_USAGE", `Expected mcpServers to be an object in ${filePath}.`, 2);
|
|
380
449
|
}
|
|
381
|
-
|
|
382
|
-
if (existingSatori !== undefined && !isManagedClaudeEntry(existingSatori)) {
|
|
450
|
+
if (mcpServers.satori !== undefined && !isManagedClaudeEntry(mcpServers.satori)) {
|
|
383
451
|
throw new CliError("E_USAGE", `Refusing to overwrite unmanaged Satori config in ${filePath}. Remove mcpServers.satori manually or align it to the managed Satori form first.`, 2);
|
|
384
452
|
}
|
|
385
453
|
mcpServers.satori = {
|
|
@@ -439,11 +507,12 @@ function parseJsoncObject(filePath, content) {
|
|
|
439
507
|
}
|
|
440
508
|
return parsed;
|
|
441
509
|
}
|
|
442
|
-
function buildOpenCodeServerConfig(runtimeCommand) {
|
|
510
|
+
function buildOpenCodeServerConfig(runtimeCommand, existing) {
|
|
443
511
|
return {
|
|
444
512
|
enabled: true,
|
|
445
513
|
type: "local",
|
|
446
514
|
command: [runtimeCommand.command, ...runtimeCommand.args],
|
|
515
|
+
environment: mergeRuntimeEnv(existing?.environment, runtimeEnvMap((name) => `{env:${name}}`)),
|
|
447
516
|
};
|
|
448
517
|
}
|
|
449
518
|
function isManagedOpenCodeEntry(value) {
|
|
@@ -488,7 +557,7 @@ function prepareOpenCodeInstall(filePath, runtimeCommand) {
|
|
|
488
557
|
if (existingSatori !== undefined && !isManagedOpenCodeEntry(existingSatori)) {
|
|
489
558
|
throw new CliError("E_USAGE", `Refusing to overwrite unmanaged Satori config in ${filePath}. Remove mcp.satori manually or align it to the managed Satori form first.`, 2);
|
|
490
559
|
}
|
|
491
|
-
return mutateJsonc(filePath, current, ["mcp", "satori"], buildOpenCodeServerConfig(runtimeCommand));
|
|
560
|
+
return mutateJsonc(filePath, current, ["mcp", "satori"], buildOpenCodeServerConfig(runtimeCommand, objectValue(existingSatori)));
|
|
492
561
|
}
|
|
493
562
|
function prepareOpenCodeUninstall(filePath) {
|
|
494
563
|
const current = readTextIfExists(filePath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zokizuan/satori-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Shell CLI for Satori MCP installation and skill-based workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
13
13
|
"jsonc-parser": "^3.3.1",
|
|
14
|
-
"@zokizuan/satori-mcp": "4.11.
|
|
14
|
+
"@zokizuan/satori-mcp": "4.11.2"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@types/node": "^20.0.0",
|