vault-cortex 0.9.0-beta.45 → 0.10.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.
- package/README.md +26 -7
- package/dist/init.js +17 -24
- package/dist/lifecycle.js +46 -13
- package/dist/main.js +6 -1
- package/dist/messages.js +6 -2
- package/dist/program.js +7 -0
- package/dist/scaffold.js +10 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,8 @@ manages the container so you don't have to.
|
|
|
25
25
|
restart to apply them
|
|
26
26
|
- [`upgrade`](#upgrade) — pull the latest image and re-create the container;
|
|
27
27
|
your data stays
|
|
28
|
+
- [`start`](#start) — start the server with your saved settings, e.g. after
|
|
29
|
+
`down`
|
|
28
30
|
- [`restart`](#restart) — re-create the container so your `.env` edits take
|
|
29
31
|
effect; no image pull
|
|
30
32
|
- [`logs`](#logs) — show the server's logs, live or after the fact
|
|
@@ -49,16 +51,17 @@ What it does:
|
|
|
49
51
|
2. Offers the most common optional settings — memory layer and folder,
|
|
50
52
|
file tools, semantic search, port, timezone (plus sync direction for
|
|
51
53
|
remote) — press enter to keep the defaults, or pick the ones you want to
|
|
52
|
-
change
|
|
53
|
-
[`configure`](#configure) instead)
|
|
54
|
+
change
|
|
54
55
|
3. Generates a `.env` file with a securely generated `MCP_AUTH_TOKEN`
|
|
55
56
|
4. Optionally starts the container and waits for the health check
|
|
56
57
|
5. Prints your connection details — the MCP URL, your auth token, and how to
|
|
57
58
|
connect your client
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
Re-running init where a setup already exists asks first — declining leaves
|
|
61
|
+
everything unchanged and points you at [`configure`](#configure), the right
|
|
62
|
+
tool for changing settings in place. Existing files are never overwritten
|
|
63
|
+
without asking. During a remote setup, init offers to run
|
|
64
|
+
[`get-sync-token`](#get-sync-token) for you when Docker is available.
|
|
62
65
|
|
|
63
66
|
Flags:
|
|
64
67
|
|
|
@@ -115,6 +118,22 @@ include Compose files you can use directly. If you set up with Compose, stick
|
|
|
115
118
|
with Compose for updates too (`docker compose pull && docker compose up -d`)
|
|
116
119
|
— the CLI and Compose manage the container independently.
|
|
117
120
|
|
|
121
|
+
## start
|
|
122
|
+
|
|
123
|
+
Start the server with your saved settings and verify health:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx vault-cortex@latest start
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
This is the command the CLI's own guidance points to whenever the server
|
|
130
|
+
isn't running — after [`down`](#down), or an `init` where the server wasn't
|
|
131
|
+
started. It's the same cycle as [`restart`](#restart) under the name you'd
|
|
132
|
+
look for: any existing container is replaced, and Docker pulls the server
|
|
133
|
+
image automatically on a first start.
|
|
134
|
+
|
|
135
|
+
Use `--dir <path>` if your config isn't in `./vault-cortex`.
|
|
136
|
+
|
|
118
137
|
## restart
|
|
119
138
|
|
|
120
139
|
Re-create the container from your `.env` and verify health:
|
|
@@ -125,7 +144,7 @@ npx vault-cortex@latest restart
|
|
|
125
144
|
|
|
126
145
|
Use it after editing `.env` — settings are only read when the container is
|
|
127
146
|
created, so a plain `docker restart` won't pick them up, but this will. Unlike
|
|
128
|
-
[`upgrade`](#upgrade), it never
|
|
147
|
+
[`upgrade`](#upgrade), it never updates the server image: you get the same
|
|
129
148
|
version back, with your current settings applied.
|
|
130
149
|
|
|
131
150
|
Use `--dir <path>` if your config isn't in `./vault-cortex`.
|
|
@@ -159,7 +178,7 @@ npx vault-cortex@latest down
|
|
|
159
178
|
|
|
160
179
|
Safe by design: your vault, search index, and `.env` settings all live
|
|
161
180
|
outside the container, so nothing is lost. Start again any time with
|
|
162
|
-
[`
|
|
181
|
+
[`start`](#start). Running `down` when nothing is running is fine — it
|
|
163
182
|
just tells you there's nothing to stop.
|
|
164
183
|
|
|
165
184
|
Use `--dir <path>` if your config isn't in `./vault-cortex`.
|
package/dist/init.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { buildLocalEnv, buildRemoteEnv } from "./env.js";
|
|
4
4
|
import { captureObsidianToken } from "./get-sync-token.js";
|
|
5
|
-
import { buildDaemonNotRunningMessage, buildDockerNotInstalledMessage, buildLocalConnectMessage, buildRemoteConnectMessage, } from "./messages.js";
|
|
5
|
+
import { buildDaemonNotRunningMessage, buildDockerNotInstalledMessage, buildLocalConnectMessage, buildRemoteConnectMessage, startCommand, } from "./messages.js";
|
|
6
6
|
import { pollHealth } from "./docker.js";
|
|
7
7
|
import { reportPublicUrlProbe } from "./lifecycle.js";
|
|
8
8
|
import { applyOptionalSettings, askOptionalSettings, derivePublicUrlOverride, } from "./optional-settings.js";
|
|
@@ -162,12 +162,12 @@ const offerDockerRun = async (params, deps) => {
|
|
|
162
162
|
const { prompts, docker, fetchFn } = deps;
|
|
163
163
|
const daemonStatus = docker.daemonStatus();
|
|
164
164
|
if (daemonStatus !== "running") {
|
|
165
|
-
const
|
|
165
|
+
const startHint = startCommand(targetDir);
|
|
166
166
|
prompts.warn(daemonStatus === "not-installed"
|
|
167
167
|
? buildDockerNotInstalledMessage({
|
|
168
|
-
nextStep: `\nThen start the server with:\n ${
|
|
168
|
+
nextStep: `\nThen start the server with:\n ${startHint}`,
|
|
169
169
|
})
|
|
170
|
-
: buildDaemonNotRunningMessage(`, then run:\n ${
|
|
170
|
+
: buildDaemonNotRunningMessage(`, then run:\n ${startHint}`));
|
|
171
171
|
return false;
|
|
172
172
|
}
|
|
173
173
|
const startNow = await prompts.confirm("Start the server now?", true);
|
|
@@ -239,18 +239,15 @@ const runLocalInit = async (flags, deps) => {
|
|
|
239
239
|
const token = generateToken();
|
|
240
240
|
// Guided optional settings: the chooser reads current values from the
|
|
241
241
|
// generated defaults; enter with nothing picked keeps them all. --yes
|
|
242
|
-
// skips the chooser (non-interactive by contract)
|
|
243
|
-
//
|
|
244
|
-
//
|
|
242
|
+
// skips the chooser (non-interactive by contract). An existing .env does
|
|
243
|
+
// NOT skip it: every interactive path here passed the re-init guard, so the
|
|
244
|
+
// user asked for a full re-run — the answers land in the regenerated file
|
|
245
|
+
// when they overwrite at the conflict prompt (keeping it discards them,
|
|
246
|
+
// which the write report states). In-place edits stay configure's job.
|
|
245
247
|
const defaultEnvContent = buildLocalEnv({ mcpAuthToken: token, vaultPath });
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
prompts.log('Found an existing .env — settings prompts skipped. Adjust settings with "npx vault-cortex@latest configure".');
|
|
250
|
-
}
|
|
251
|
-
const optionalOverrides = offerSettingsChooser
|
|
252
|
-
? await askOptionalSettings({ mode: "local", envContent: defaultEnvContent }, prompts)
|
|
253
|
-
: {};
|
|
248
|
+
const optionalOverrides = flags.yes
|
|
249
|
+
? {}
|
|
250
|
+
: await askOptionalSettings({ mode: "local", envContent: defaultEnvContent }, prompts);
|
|
254
251
|
const envContent = applyOptionalSettings(defaultEnvContent, derivePublicUrlOverride(defaultEnvContent, optionalOverrides));
|
|
255
252
|
// Conflict policy: identical existing files are skipped silently;
|
|
256
253
|
// differing ones prompt per file (default keep). --yes never overwrites —
|
|
@@ -317,8 +314,10 @@ const runRemoteInit = async (flags, deps) => {
|
|
|
317
314
|
: undefined;
|
|
318
315
|
const token = generateToken();
|
|
319
316
|
// Guided optional settings, mirroring the local flow — remote also offers
|
|
320
|
-
// SYNC_MODE. Remote init is always interactive (no --yes),
|
|
321
|
-
//
|
|
317
|
+
// SYNC_MODE. Remote init is always interactive (no --yes), and any existing
|
|
318
|
+
// .env passed the re-init guard — a consented re-run gets the full setup,
|
|
319
|
+
// chooser included (see the local flow's comment for the overwrite/keep
|
|
320
|
+
// semantics).
|
|
322
321
|
const defaultEnvContent = buildRemoteEnv({
|
|
323
322
|
mcpAuthToken: token,
|
|
324
323
|
publicUrl,
|
|
@@ -326,13 +325,7 @@ const runRemoteInit = async (flags, deps) => {
|
|
|
326
325
|
vaultName,
|
|
327
326
|
vaultPassword,
|
|
328
327
|
});
|
|
329
|
-
const
|
|
330
|
-
if (envAlreadyExists) {
|
|
331
|
-
prompts.log('Found an existing .env — settings prompts skipped. Adjust settings with "npx vault-cortex@latest configure".');
|
|
332
|
-
}
|
|
333
|
-
const optionalOverrides = envAlreadyExists
|
|
334
|
-
? {}
|
|
335
|
-
: await askOptionalSettings({ mode: "remote", envContent: defaultEnvContent }, prompts);
|
|
328
|
+
const optionalOverrides = await askOptionalSettings({ mode: "remote", envContent: defaultEnvContent }, prompts);
|
|
336
329
|
const envContent = applyOptionalSettings(defaultEnvContent, derivePublicUrlOverride(defaultEnvContent, optionalOverrides));
|
|
337
330
|
const files = buildFilesToWrite(envContent);
|
|
338
331
|
const results = await writeFiles({ targetDir, files }, confirmOverwrite(prompts));
|
package/dist/lifecycle.js
CHANGED
|
@@ -41,9 +41,7 @@ export const resolveDeployment = (dirFlag, prompts) => {
|
|
|
41
41
|
`Add this line to your .env:\n PUBLIC_URL=http://localhost:${port}`);
|
|
42
42
|
return undefined;
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
// duplicate the health check recreateContainer just ran, so remote-only.
|
|
46
|
-
const publicUrl = mode === "remote" ? readEnvPublicUrl(envFilePath) : undefined;
|
|
44
|
+
const publicUrl = readEnvPublicUrl(envFilePath);
|
|
47
45
|
return { mode, targetDir, envFilePath, port, vaultPath, publicUrl };
|
|
48
46
|
};
|
|
49
47
|
/**
|
|
@@ -59,6 +57,15 @@ export const ensureDaemonRunning = (docker, prompts) => {
|
|
|
59
57
|
: buildDaemonNotRunningMessage("."));
|
|
60
58
|
return false;
|
|
61
59
|
};
|
|
60
|
+
/**
|
|
61
|
+
* Whether the post-start public-URL probe should run — and, when it should,
|
|
62
|
+
* proof that publicUrl is set. Local's PUBLIC_URL is the derived localhost
|
|
63
|
+
* URL, so probing it would only duplicate the health check the start cycle
|
|
64
|
+
* just ran.
|
|
65
|
+
*/
|
|
66
|
+
const shouldRunPostStartProbe = (deployment) => {
|
|
67
|
+
return deployment.mode === "remote" && deployment.publicUrl !== undefined;
|
|
68
|
+
};
|
|
62
69
|
/**
|
|
63
70
|
* One-shot informational probe of the public /healthz after a confirmed
|
|
64
71
|
* container start. Never a gate: a failure warns and the command still
|
|
@@ -127,7 +134,7 @@ export const recreateContainer = async (params, deps) => {
|
|
|
127
134
|
spinner.stop("Server is up — health check passed.");
|
|
128
135
|
// Informational only — the container is confirmed healthy above, so the
|
|
129
136
|
// public-URL result never changes the exit code.
|
|
130
|
-
if (deployment
|
|
137
|
+
if (shouldRunPostStartProbe(deployment)) {
|
|
131
138
|
await reportPublicUrlProbe(deployment.publicUrl, { prompts, fetchFn });
|
|
132
139
|
}
|
|
133
140
|
return 0;
|
|
@@ -157,7 +164,7 @@ export const runDown = async (flags, deps) => {
|
|
|
157
164
|
return 1;
|
|
158
165
|
}
|
|
159
166
|
prompts.log("Container stopped and removed. Your vault data, search index, and settings are untouched.");
|
|
160
|
-
prompts.outro(`Start again with: npx vault-cortex@latest
|
|
167
|
+
prompts.outro(`Start again with: npx vault-cortex@latest start --dir "${initialized.targetDir}"`);
|
|
161
168
|
return 0;
|
|
162
169
|
};
|
|
163
170
|
/**
|
|
@@ -174,7 +181,7 @@ export const runLogs = async (flags, deps) => {
|
|
|
174
181
|
if (!ensureDaemonRunning(docker, prompts))
|
|
175
182
|
return 1;
|
|
176
183
|
if (!docker.containerExists()) {
|
|
177
|
-
prompts.error(
|
|
184
|
+
prompts.error(`No vault-cortex container — start it with: npx vault-cortex@latest start --dir "${initialized.targetDir}"`);
|
|
178
185
|
return 1;
|
|
179
186
|
}
|
|
180
187
|
return await docker.streamLogs({
|
|
@@ -183,13 +190,13 @@ export const runLogs = async (flags, deps) => {
|
|
|
183
190
|
});
|
|
184
191
|
};
|
|
185
192
|
/**
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
193
|
+
* Shared start/restart cycle: re-create the container from the .env on disk
|
|
194
|
+
* and verify health. One implementation, two command names — the labels are
|
|
195
|
+
* the only divergence, phrased for the intent each name serves.
|
|
189
196
|
*/
|
|
190
|
-
|
|
197
|
+
const runRecreateFromEnv = async (flags, deps, labels) => {
|
|
191
198
|
const { prompts, docker, fetchFn } = deps;
|
|
192
|
-
prompts.intro(
|
|
199
|
+
prompts.intro(labels.introTitle);
|
|
193
200
|
const deployment = resolveDeployment(flags.dir, prompts);
|
|
194
201
|
if (!deployment)
|
|
195
202
|
return 1;
|
|
@@ -198,7 +205,33 @@ export const runRestart = async (flags, deps) => {
|
|
|
198
205
|
const exitCode = await recreateContainer({ deployment, healthTimeoutMs: deps.healthTimeoutMs }, { prompts, docker, fetchFn });
|
|
199
206
|
if (exitCode !== 0)
|
|
200
207
|
return exitCode;
|
|
201
|
-
prompts.log(
|
|
202
|
-
prompts.outro(
|
|
208
|
+
prompts.log(labels.successLog);
|
|
209
|
+
prompts.outro(labels.outroMessage);
|
|
203
210
|
return 0;
|
|
204
211
|
};
|
|
212
|
+
/**
|
|
213
|
+
* Starts the server from the saved .env — the command name users reach for
|
|
214
|
+
* when nothing is running yet (after `down`, or an init that skipped the
|
|
215
|
+
* start offer). Same cycle as restart: if a container is already running it
|
|
216
|
+
* is safely replaced, and `docker run` pulls the image when it's missing.
|
|
217
|
+
*/
|
|
218
|
+
export const runStart = async (flags, deps) => {
|
|
219
|
+
return runRecreateFromEnv(flags, deps, {
|
|
220
|
+
introTitle: "vault-cortex start",
|
|
221
|
+
successLog: "Started with the settings from .env.",
|
|
222
|
+
outroMessage: "Start complete.",
|
|
223
|
+
});
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* Re-creates the container from the .env on disk and verifies health.
|
|
227
|
+
* Unlike `docker restart`, this applies .env edits (the env-file is only
|
|
228
|
+
* read at container creation); unlike upgrade, it never replaces an image
|
|
229
|
+
* you already have (`docker run` still pulls when none exists locally).
|
|
230
|
+
*/
|
|
231
|
+
export const runRestart = async (flags, deps) => {
|
|
232
|
+
return runRecreateFromEnv(flags, deps, {
|
|
233
|
+
introTitle: "vault-cortex restart",
|
|
234
|
+
successLog: "Applied the current .env settings.",
|
|
235
|
+
outroMessage: "Restart complete.",
|
|
236
|
+
});
|
|
237
|
+
};
|
package/dist/main.js
CHANGED
|
@@ -2,7 +2,7 @@ import { runConfigure } from "./configure.js";
|
|
|
2
2
|
import { createDockerRunner } from "./docker.js";
|
|
3
3
|
import { runGetSyncToken } from "./get-sync-token.js";
|
|
4
4
|
import { runInit } from "./init.js";
|
|
5
|
-
import { runDown, runLogs, runRestart } from "./lifecycle.js";
|
|
5
|
+
import { runDown, runLogs, runRestart, runStart } from "./lifecycle.js";
|
|
6
6
|
import { buildProgram } from "./program.js";
|
|
7
7
|
import { createPrompts } from "./prompts.js";
|
|
8
8
|
import { runUpgrade } from "./upgrade.js";
|
|
@@ -24,6 +24,11 @@ export const run = async (version) => {
|
|
|
24
24
|
docker: createDockerRunner(),
|
|
25
25
|
fetchFn: fetch,
|
|
26
26
|
}),
|
|
27
|
+
runStart: (flags) => runStart(flags, {
|
|
28
|
+
prompts: createPrompts(),
|
|
29
|
+
docker: createDockerRunner(),
|
|
30
|
+
fetchFn: fetch,
|
|
31
|
+
}),
|
|
27
32
|
runRestart: (flags) => runRestart(flags, {
|
|
28
33
|
prompts: createPrompts(),
|
|
29
34
|
docker: createDockerRunner(),
|
package/dist/messages.js
CHANGED
|
@@ -45,14 +45,18 @@ export const buildDockerNotInstalledMessage = (params) => {
|
|
|
45
45
|
// targetDir is quoted: these lines are meant to be copy-pasted into a
|
|
46
46
|
// shell, and an unquoted path breaks on spaces or special characters.
|
|
47
47
|
const upgradeCommand = (targetDir) => `npx vault-cortex@latest upgrade --dir "${targetDir}"`;
|
|
48
|
-
|
|
48
|
+
// Start guidance prints `start`, not `upgrade` — telling a user who has never
|
|
49
|
+
// started anything to run "upgrade" reads as updating something they don't
|
|
50
|
+
// have. `start` runs the same re-create cycle and pulls the image on demand.
|
|
51
|
+
export const startCommand = (targetDir) => `npx vault-cortex@latest start --dir "${targetDir}"`;
|
|
52
|
+
const startServerLine = (targetDir) => `Start the server:\n ${startCommand(targetDir)}`;
|
|
49
53
|
/** Remote start line: running, blocked on the missing sync token, or ready to start. */
|
|
50
54
|
const remoteStartLine = (params) => {
|
|
51
55
|
const { targetDir, started, obsidianTokenMissing } = params;
|
|
52
56
|
if (started)
|
|
53
57
|
return "The server is running.";
|
|
54
58
|
if (obsidianTokenMissing) {
|
|
55
|
-
return `Fill in OBSIDIAN_AUTH_TOKEN in ${targetDir}/.env, then start the server:\n ${
|
|
59
|
+
return `Fill in OBSIDIAN_AUTH_TOKEN in ${targetDir}/.env, then start the server:\n ${startCommand(targetDir)}`;
|
|
56
60
|
}
|
|
57
61
|
return startServerLine(targetDir);
|
|
58
62
|
};
|
package/dist/program.js
CHANGED
|
@@ -29,6 +29,13 @@ export const buildProgram = (options) => {
|
|
|
29
29
|
.action(async (flags) => {
|
|
30
30
|
process.exitCode = await options.runUpgrade(flags);
|
|
31
31
|
});
|
|
32
|
+
program
|
|
33
|
+
.command("start")
|
|
34
|
+
.description("Start the server with the saved settings and verify health (same cycle as restart)")
|
|
35
|
+
.option("--dir <path>", "directory containing .env (default: ./vault-cortex)")
|
|
36
|
+
.action(async (flags) => {
|
|
37
|
+
process.exitCode = await options.runStart(flags);
|
|
38
|
+
});
|
|
32
39
|
program
|
|
33
40
|
.command("restart")
|
|
34
41
|
.description("Re-create the container from .env and verify health (applies .env edits; no image pull)")
|
package/dist/scaffold.js
CHANGED
|
@@ -40,8 +40,11 @@ export const readEnvVaultPath = (envFilePath) => {
|
|
|
40
40
|
};
|
|
41
41
|
/**
|
|
42
42
|
* Returns true when the .env file has an active (uncommented) PUBLIC_URL line.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
43
|
+
* It's the FALSE result that carries the signal: the old compose-based CLI's
|
|
44
|
+
* generated .env never held a PUBLIC_URL line (the compose file's environment
|
|
45
|
+
* defaults supplied it), so a local .env without one predates the docker-run
|
|
46
|
+
* migration — callers use the negation to ask the user to add the line
|
|
47
|
+
* instead of starting a server missing a required variable.
|
|
45
48
|
*/
|
|
46
49
|
export const hasEnvPublicUrl = (envFilePath) => {
|
|
47
50
|
if (!existsSync(envFilePath))
|
|
@@ -61,7 +64,11 @@ export const readEnvPublicUrl = (envFilePath) => {
|
|
|
61
64
|
// A whitespace-only line matches the regex and trims to "" — normalize to
|
|
62
65
|
// undefined so the non-empty contract holds ("" is never a legitimate URL).
|
|
63
66
|
const publicUrlValue = match?.[1].trim();
|
|
64
|
-
|
|
67
|
+
// Strip trailing slashes (mirroring askPublicUrl's prompt-side
|
|
68
|
+
// normalization): consumers append paths to this base, and a hand-edited
|
|
69
|
+
// `https://host/` would otherwise print broken `//mcp` connect URLs.
|
|
70
|
+
const normalizedPublicUrl = publicUrlValue?.replace(/\/+$/, "");
|
|
71
|
+
return normalizedPublicUrl || undefined;
|
|
65
72
|
};
|
|
66
73
|
/**
|
|
67
74
|
* Detects the deployment mode from a .env file. Remote mode requires
|