vault-cortex 0.11.0 → 0.12.0-beta.61

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 CHANGED
@@ -61,7 +61,8 @@ Re-running init where a setup already exists asks first — declining leaves
61
61
  everything unchanged and points you at [`configure`](#configure), the right
62
62
  tool for changing settings in place. Existing files are never overwritten
63
63
  without asking. During a remote setup, init offers to run
64
- [`get-sync-token`](#get-sync-token) for you when Docker is available.
64
+ [`get-sync-token`](#get-sync-token) for you sign in to your Obsidian
65
+ account right from the terminal.
65
66
 
66
67
  Flags:
67
68
 
@@ -194,17 +195,16 @@ remote setups — without leaving the CLI:
194
195
  npx vault-cortex@latest get-sync-token
195
196
  ```
196
197
 
197
- The command opens the Obsidian login inside Docker. Once you've signed in, it
198
- captures your token and prints it nothing to dig out of the login output.
199
- Use `--dir <path>` to write the token straight into an existing `.env`
200
- instead:
198
+ The command prompts for your Obsidian account email, password, and MFA code
199
+ (if enabled), signs in via the Obsidian API, and prints the token. No Docker
200
+ required. Use `--dir <path>` to write the token straight into an existing
201
+ `.env` instead:
201
202
 
202
203
  ```bash
203
204
  npx vault-cortex@latest get-sync-token --dir ./vault-cortex
204
205
  ```
205
206
 
206
- During `init --mode remote`, this flow is offered automatically when Docker
207
- is available.
207
+ During `init --mode remote`, this flow is offered automatically.
208
208
 
209
209
  ## Requirements
210
210
 
package/dist/docker.js CHANGED
@@ -2,36 +2,6 @@ import { spawn, spawnSync } from "node:child_process";
2
2
  export const LOCAL_IMAGE = "ghcr.io/aliasunder/vault-cortex:latest";
3
3
  export const REMOTE_IMAGE = "ghcr.io/aliasunder/vault-cortex:remote";
4
4
  export const CONTAINER_NAME = "vault-cortex";
5
- /**
6
- * Builds the `docker run` args for the Obsidian login with a volume mount
7
- * that captures the auth token file. Runs `ob login` directly instead of
8
- * the image's get-sync-token script: the script's additions are locating and
9
- * printing the token, and the mount makes both unnecessary — the CLI reads
10
- * the token file itself, and not echoing a credential keeps it out of
11
- * terminal scrollback. Pure function for testability.
12
- *
13
- * On Linux, includes `--user uid:gid` when uid/gid are provided — Node
14
- * exposes process.getuid/getgid on every POSIX platform, so in practice the
15
- * flag is always set there — keeping the token file host-user-owned. macOS
16
- * Docker Desktop translates UIDs automatically, so no flag is needed.
17
- */
18
- export const buildObsidianLoginArgs = (params) => {
19
- const { configMountPath, platform = process.platform, uid, gid } = params;
20
- const args = [
21
- "run",
22
- "--rm",
23
- "-it",
24
- "--entrypoint",
25
- "ob",
26
- "-v",
27
- `${configMountPath}:/home/obsidian/.config`,
28
- ];
29
- if (platform === "linux" && uid !== undefined && gid !== undefined) {
30
- args.push("--user", `${uid}:${gid}`);
31
- }
32
- args.push(REMOTE_IMAGE, "login");
33
- return args;
34
- };
35
5
  /**
36
6
  * Container-internal env vars that must override the user's .env values.
37
7
  * VAULT_PATH in .env is the host path (for the -v mount); the container
@@ -130,10 +100,7 @@ export const createDockerRunner = () => ({
130
100
  // stdout is discarded: `docker run -d` prints only the container ID there,
131
101
  // which lands as a raw hex line between the wizard's prompts. stderr stays
132
102
  // inherited — image-pull progress and error output print live, which the
133
- // "see output above" failure messages rely on. stdin is ignored on purpose:
134
- // buildDockerRunArgs always runs detached (never -it), and the prompt
135
- // library owns the terminal's stdin — interactive flows go through
136
- // runObsidianLogin, which inherits all three streams.
103
+ // "see output above" failure messages rely on.
137
104
  dockerRun: (params) => spawnSync("docker", buildDockerRunArgs(params), {
138
105
  stdio: ["ignore", "ignore", "inherit"],
139
106
  }).status === 0,
@@ -166,11 +133,6 @@ export const createDockerRunner = () => ({
166
133
  // convention for ctrl-C (128 + SIGINT = 130).
167
134
  child.once("close", (code) => resolveExitCode(code ?? 130));
168
135
  }),
169
- runObsidianLogin: (configMountPath) => spawnSync("docker", buildObsidianLoginArgs({
170
- configMountPath,
171
- uid: process.getuid?.(),
172
- gid: process.getgid?.(),
173
- }), { stdio: "inherit" }).status === 0,
174
136
  });
175
137
  /** Default bound on a single health request (shared by probe and poll). */
176
138
  const PROBE_TIMEOUT_MS = 10_000;
package/dist/env.js CHANGED
@@ -94,17 +94,28 @@ MEMORY_DIR=About Me
94
94
  # Host port to expose (default: 8000).
95
95
  PORT=8000
96
96
 
97
- # Client-IP trust for OAuth rate limiting and logs (defaults shown).
98
- # With nothing in front of the server, leave both untouched — each visitor
99
- # is identified by their own connection, and faked Forwarded/X-Forwarded-For
100
- # headers are ignored.
101
- # With a proxy or tunnel you control in front (Caddy, nginx, Cloudflare
102
- # Tunnel), set TRUST_PROXY_HOPS=1 so visitors are told apart by their real
103
- # IP — otherwise they all share one rate-limit budget.
104
- # Set TRUST_FORWARDED_HEADER=true only if the proxy reports each visitor's
105
- # IP in the RFC 7239 Forwarded header (e.g. AWS API Gateway).
97
+ # These two settings choose the client IP used for OAuth rate limiting and
98
+ # logs (defaults shown below). Without the right values, every visitor
99
+ # behind a proxy shares one rate-limit budget. TRUST_PROXY_HOPS counts the
100
+ # proxies you control that write X-Forwarded-For; TRUST_FORWARDED_HOPS
101
+ # counts the ones that write the RFC 7239 Forwarded header
102
+ # (https://www.rfc-editor.org/rfc/rfc7239), and 0 ignores that header.
103
+ #
104
+ # What sits in front of the server TRUST_PROXY_HOPS TRUST_FORWARDED_HOPS Client IP is
105
+ # Nothing (default) 0 0 the visitor (socket peer)
106
+ # A proxy or tunnel you control 1 0 the visitor (X-Forwarded-For)
107
+ # (Caddy, nginx, Cloudflare Tunnel)
108
+ # A proxy that reports visitors in 1 1 the visitor (Forwarded)
109
+ # Forwarded (e.g. AWS API Gateway)
110
+ # A CDN in front of that proxy, and 1 2 the visitor (Forwarded)
111
+ # the CDN is the only way to reach it
112
+ #
113
+ # When the Forwarded header is read (TRUST_FORWARDED_HOPS above 0), it wins
114
+ # and TRUST_PROXY_HOPS is not consulted; TRUST_PROXY_HOPS is the fallback
115
+ # when that header is ignored or absent. Faked headers from visitors are
116
+ # ignored in every row — only the counted proxies are trusted.
106
117
  # TRUST_PROXY_HOPS=0
107
- # TRUST_FORWARDED_HEADER=false
118
+ # TRUST_FORWARDED_HOPS=0
108
119
 
109
120
  # Log verbosity: debug | info | warn | error (default: info).
110
121
  LOG_LEVEL=info
@@ -221,17 +232,28 @@ MEMORY_DIR=About Me
221
232
  # Host port to expose (default: 8000).
222
233
  PORT=8000
223
234
 
224
- # Client-IP trust for OAuth rate limiting and logs (defaults shown).
225
- # With nothing in front of the server, leave both untouched — each visitor
226
- # is identified by their own connection, and faked Forwarded/X-Forwarded-For
227
- # headers are ignored.
228
- # With a proxy or tunnel you control in front (Caddy, nginx, Cloudflare
229
- # Tunnel), set TRUST_PROXY_HOPS=1 so visitors are told apart by their real
230
- # IP — otherwise they all share one rate-limit budget.
231
- # Set TRUST_FORWARDED_HEADER=true only if the proxy reports each visitor's
232
- # IP in the RFC 7239 Forwarded header (e.g. AWS API Gateway).
235
+ # These two settings choose the client IP used for OAuth rate limiting and
236
+ # logs (defaults shown below). Without the right values, every visitor
237
+ # behind a proxy shares one rate-limit budget. TRUST_PROXY_HOPS counts the
238
+ # proxies you control that write X-Forwarded-For; TRUST_FORWARDED_HOPS
239
+ # counts the ones that write the RFC 7239 Forwarded header
240
+ # (https://www.rfc-editor.org/rfc/rfc7239), and 0 ignores that header.
241
+ #
242
+ # What sits in front of the server TRUST_PROXY_HOPS TRUST_FORWARDED_HOPS Client IP is
243
+ # Nothing (default) 0 0 the visitor (socket peer)
244
+ # A proxy or tunnel you control 1 0 the visitor (X-Forwarded-For)
245
+ # (Caddy, nginx, Cloudflare Tunnel)
246
+ # A proxy that reports visitors in 1 1 the visitor (Forwarded)
247
+ # Forwarded (e.g. AWS API Gateway)
248
+ # A CDN in front of that proxy, and 1 2 the visitor (Forwarded)
249
+ # the CDN is the only way to reach it
250
+ #
251
+ # When the Forwarded header is read (TRUST_FORWARDED_HOPS above 0), it wins
252
+ # and TRUST_PROXY_HOPS is not consulted; TRUST_PROXY_HOPS is the fallback
253
+ # when that header is ignored or absent. Faked headers from visitors are
254
+ # ignored in every row — only the counted proxies are trusted.
233
255
  # TRUST_PROXY_HOPS=0
234
- # TRUST_FORWARDED_HEADER=false
256
+ # TRUST_FORWARDED_HOPS=0
235
257
 
236
258
  # Log verbosity: debug | info | warn | error (default: info).
237
259
  LOG_LEVEL=info
@@ -1,140 +1,130 @@
1
- import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
1
  import { join, resolve } from "node:path";
4
- import { buildDaemonNotRunningMessage, buildDockerNotInstalledMessage, } from "./messages.js";
5
2
  import { patchEnvObsidianToken } from "./scaffold.js";
6
3
  import { expandTilde } from "./vault.js";
7
- /** Message from an unknown throw — Error instances keep their message. */
4
+ const OBSIDIAN_SIGNIN_URL = "https://api.obsidian.md/user/signin";
5
+ const SIGNIN_TIMEOUT_MS = 30_000;
8
6
  const describeError = (error) => error instanceof Error ? error.message : String(error);
9
7
  /**
10
- * Creates the temp dir the container's config mount writes into.
11
- * Returns undefined (after warning) when creation fails.
8
+ * Calls the Obsidian Sync signin API. Returns the parsed JSON on success,
9
+ * or throws on HTTP/network errors. The API returns { error: string } for
10
+ * auth failures (200 with an error field), and non-200 for server errors.
12
11
  */
13
- const makeTempMountDir = (prompts) => {
14
- try {
15
- return mkdtempSync(join(tmpdir(), "vault-cortex-sync-token-"));
12
+ const callSigninApi = async (params, fetchFn) => {
13
+ const response = await fetchFn(OBSIDIAN_SIGNIN_URL, {
14
+ method: "POST",
15
+ headers: {
16
+ "Content-Type": "application/json",
17
+ Origin: "https://obsidian.md",
18
+ },
19
+ body: JSON.stringify({
20
+ email: params.email,
21
+ password: params.password,
22
+ mfa: params.mfa,
23
+ }),
24
+ signal: AbortSignal.timeout(SIGNIN_TIMEOUT_MS),
25
+ });
26
+ if (!response.ok) {
27
+ throw new Error(`HTTP Error ${response.status}`);
16
28
  }
17
- catch (error) {
18
- prompts.warn(`Could not create a temp directory for token capture — ${describeError(error)}`);
19
- return undefined;
20
- }
21
- };
22
- /**
23
- * Runs the interactive Obsidian login container. A throw from the Docker
24
- * runner is reported and treated the same as a non-zero exit.
25
- */
26
- const runLoginContainer = (configMountPath, deps) => {
27
- const { docker, prompts } = deps;
29
+ let body;
28
30
  try {
29
- return docker.runObsidianLogin(configMountPath);
31
+ body = await response.json();
30
32
  }
31
- catch (error) {
32
- prompts.warn(`Docker run failed ${describeError(error)}`);
33
- return false;
33
+ catch {
34
+ throw new Error("Unexpected response from Obsidian API (not JSON)");
34
35
  }
35
- };
36
- /**
37
- * Reads the captured token file from the config mount. Returns undefined
38
- * when the file is missing, empty, or unreadable — the caller treats all
39
- * three as "no token captured".
40
- */
41
- const readCapturedTokenFile = (configMountPath) => {
42
- const tokenPath = join(configMountPath, "obsidian-headless", "auth_token");
43
- try {
44
- if (!existsSync(tokenPath))
45
- return undefined;
46
- const token = readFileSync(tokenPath, "utf8").trim();
47
- return token || undefined;
36
+ const isRecord = (value) => typeof value === "object" && value !== null;
37
+ if (!isRecord(body)) {
38
+ throw new Error("Unexpected response from Obsidian API (not JSON)");
48
39
  }
49
- catch {
50
- return undefined;
40
+ if ("error" in body && typeof body.error === "string") {
41
+ throw new ObsidianApiError(body.error);
42
+ }
43
+ const token = "token" in body && typeof body.token === "string" ? body.token : undefined;
44
+ if (!token) {
45
+ throw new Error("Unexpected response from Obsidian API (no token)");
51
46
  }
47
+ const name = "name" in body && typeof body.name === "string" ? body.name : "";
48
+ const email = "email" in body && typeof body.email === "string" ? body.email : "";
49
+ return { token, name, email };
52
50
  };
51
+ class ObsidianApiError extends Error {
52
+ constructor(message) {
53
+ super(message);
54
+ this.name = "ObsidianApiError";
55
+ }
56
+ }
53
57
  /**
54
- * Best-effort removal of the temp mount dir. Failing to remove it (e.g.
55
- * root-owned files left by the container) must not turn a successful
56
- * capture into a failure, so it warns instead of throwing.
58
+ * Signs in to the user's Obsidian account via the Sync API and returns
59
+ * the auth token. Prompts for email, password, and MFA code (when 2FA
60
+ * is enabled). Returns the token on success, undefined on any failure.
57
61
  */
58
- const removeTempMountDir = (configMountPath, prompts) => {
62
+ export const captureObsidianToken = async (deps) => {
63
+ const { prompts, fetchFn } = deps;
64
+ const email = await prompts.text("Obsidian account email:", {
65
+ placeholder: "you@example.com",
66
+ });
67
+ const password = await prompts.password("Password:");
68
+ const spinner = prompts.spinner();
69
+ spinner.start("Signing in to Obsidian...");
59
70
  try {
60
- rmSync(configMountPath, { recursive: true, force: true });
71
+ const result = await callSigninApi({ email, password, mfa: "" }, fetchFn);
72
+ spinner.stop(`Signed in as ${result.name} (${result.email}).`);
73
+ return result.token;
61
74
  }
62
75
  catch (error) {
63
- prompts.warn(`Could not remove temp directory ${configMountPath}${describeError(error)}`);
64
- }
65
- };
66
- /**
67
- * Runs the Obsidian login (`ob login`) inside a Docker container with a
68
- * volume mount that captures the auth token file. The interactive login
69
- * (email, password, MFA) shows in the terminal, but the resulting token is
70
- * read from the mounted config dir — never printed, so it stays out of
71
- * terminal scrollback.
72
- *
73
- * tokenDestinationMessage finishes the handoff message by telling the user
74
- * where the captured token ends up — the destination differs per flow
75
- * (init stores it in the generated .env; the subcommand prints it, or
76
- * writes it to an existing .env with --dir).
77
- *
78
- * Returns the token string on success, undefined on any failure — each
79
- * fallible operation is wrapped individually by the helpers above, so no
80
- * catch-all is needed here. The bare try/finally only scopes the temp dir
81
- * (acquire → release); it has no catch and swallows nothing.
82
- */
83
- export const captureObsidianToken = (deps, tokenDestinationMessage) => {
84
- const { prompts } = deps;
85
- const configMountPath = makeTempMountDir(prompts);
86
- if (!configMountPath)
87
- return undefined;
88
- try {
89
- prompts.log("Handing the terminal to the Obsidian login — it will ask for your " +
90
- `account email, password, and MFA code. ${tokenDestinationMessage}`);
91
- const loginSucceeded = runLoginContainer(configMountPath, deps);
92
- if (!loginSucceeded) {
93
- prompts.warn("The Obsidian login did not complete — you can run it later with:\n" +
94
- " npx vault-cortex@latest get-sync-token");
95
- return undefined;
76
+ // MFA required: the API returns an error containing "2FA code" prompt
77
+ // and retry. "2FA code is incorrect" is a wrong-code rejection, not a
78
+ // prompt-for-code signal. Mirrors the obsidian-headless v0.0.14 logic.
79
+ if (error instanceof ObsidianApiError &&
80
+ error.message.includes("2FA code") &&
81
+ !error.message.includes("2FA code is incorrect")) {
82
+ spinner.stop("Two-factor authentication required.");
83
+ const mfaCode = await prompts.text("2FA code:");
84
+ spinner.start("Verifying...");
85
+ try {
86
+ const result = await callSigninApi({ email, password, mfa: mfaCode }, fetchFn);
87
+ spinner.stop(`Signed in as ${result.name} (${result.email}).`);
88
+ return result.token;
89
+ }
90
+ catch (retryError) {
91
+ spinner.stop("Sign-in failed.");
92
+ if (retryError instanceof Error && retryError.name === "TimeoutError") {
93
+ prompts.warn("Request timed out check your internet connection and try again.");
94
+ return undefined;
95
+ }
96
+ const retryHint = retryError instanceof ObsidianApiError
97
+ ? "\n Check your 2FA code and try again."
98
+ : "";
99
+ prompts.warn(`Could not sign in: ${describeError(retryError)}${retryHint}`);
100
+ return undefined;
101
+ }
96
102
  }
97
- const token = readCapturedTokenFile(configMountPath);
98
- if (!token) {
99
- prompts.warn("The Obsidian login finished, but no token was captured the " +
100
- "token file was missing, empty, or unreadable. You can retry with:\n" +
101
- " npx vault-cortex@latest get-sync-token");
103
+ spinner.stop("Sign-in failed.");
104
+ if (error instanceof Error && error.name === "TimeoutError") {
105
+ prompts.warn("Request timed out check your internet connection and try again.");
102
106
  return undefined;
103
107
  }
104
- return token;
105
- }
106
- finally {
107
- removeTempMountDir(configMountPath, prompts);
108
+ prompts.warn(`Could not sign in: ${describeError(error)}`);
109
+ return undefined;
108
110
  }
109
111
  };
110
112
  /**
111
- * Subcommand entry: generate an Obsidian Sync token via Docker.
113
+ * Subcommand entry: generate an Obsidian Sync token via the Obsidian API.
112
114
  * Without --dir, prints the token to stdout.
113
115
  * With --dir, writes it directly to `<dir>/.env`.
114
116
  */
115
117
  export const runGetSyncToken = async (flags, deps) => {
116
- const { prompts, docker } = deps;
117
- const daemonStatus = docker.daemonStatus();
118
- if (daemonStatus !== "running") {
119
- prompts.error(daemonStatus === "not-installed"
120
- ? buildDockerNotInstalledMessage({ nextStep: "\nThen try again." })
121
- : buildDaemonNotRunningMessage(" and try again."));
122
- return 1;
123
- }
118
+ const { prompts } = deps;
124
119
  prompts.intro("vault-cortex get-sync-token");
125
- // Resolve the destination up front so the login handoff message can tell
126
- // the user where the token will end up.
127
- const envFilePath = flags.dir
128
- ? join(resolve(expandTilde(flags.dir)), ".env")
129
- : undefined;
130
- const tokenDestinationMessage = envFilePath
131
- ? `The token is captured automatically and written to ${envFilePath}.`
132
- : "The token is captured automatically and printed at the end.";
133
- const token = captureObsidianToken({ docker, prompts }, tokenDestinationMessage);
120
+ const token = await captureObsidianToken(deps);
134
121
  if (!token) {
135
122
  prompts.error("Could not capture the auth token.");
136
123
  return 1;
137
124
  }
125
+ const envFilePath = flags.dir
126
+ ? join(resolve(expandTilde(flags.dir)), ".env")
127
+ : undefined;
138
128
  if (!envFilePath) {
139
129
  prompts.log("Your OBSIDIAN_AUTH_TOKEN:");
140
130
  prompts.print(`\n ${token}\n`);
package/dist/init.js CHANGED
@@ -27,15 +27,15 @@ const askMode = async (prompts) => {
27
27
  return isMode(selected) ? selected : "local";
28
28
  };
29
29
  /**
30
- * Offers to auto-capture the Obsidian Sync token via a Docker volume mount.
31
- * Returns the captured token string, or undefined when the user declines or
32
- * the capture fails (the caller falls back to a paste prompt).
30
+ * Offers to sign in to the Obsidian account and capture the Sync token.
31
+ * Returns the captured token string, or undefined when the user declines
32
+ * or the capture fails (the caller falls back to a paste prompt).
33
33
  */
34
- const offerSyncTokenCapture = async (prompts, docker) => {
34
+ const offerSyncTokenCapture = async (prompts, fetchFn) => {
35
35
  const runNow = await prompts.confirm("Generate the token now?", true);
36
36
  if (!runNow)
37
37
  return undefined;
38
- return captureObsidianToken({ docker, prompts }, "The token is captured automatically and stored in your .env — nothing to copy.");
38
+ return captureObsidianToken({ prompts, fetchFn });
39
39
  };
40
40
  /**
41
41
  * Asks for the vault path, recursing to re-prompt until it gets a usable
@@ -285,12 +285,12 @@ const runLocalInit = async (flags, deps) => {
285
285
  return 0;
286
286
  };
287
287
  // Remote flow (VPS + Obsidian Sync): resolve target dir → PUBLIC_URL →
288
- // VAULT_NAME → Obsidian Sync token (optionally running the Obsidian login via
289
- // Docker) → optional E2E vault password → generate token → write .env →
290
- // optionally start → print connect instructions. Always interactive —
291
- // the sync-token step can't be defaulted.
288
+ // VAULT_NAME → Obsidian Sync token (sign in via the Obsidian API) → optional
289
+ // E2E vault password → generate token → write .env → optionally start → print
290
+ // connect instructions. Always interactive — the sync-token step can't be
291
+ // defaulted.
292
292
  const runRemoteInit = async (flags, deps) => {
293
- const { prompts, docker } = deps;
293
+ const { prompts, fetchFn } = deps;
294
294
  // expandTilde before resolve: resolve() treats a leading `~` as a literal
295
295
  // path segment, so a quoted "~/path" would create a directory named "~".
296
296
  const targetDir = resolve(expandTilde(flags.dir ??
@@ -303,14 +303,9 @@ const runRemoteInit = async (flags, deps) => {
303
303
  return 0;
304
304
  const publicUrl = await askPublicUrl(prompts);
305
305
  const vaultName = await askVaultName(prompts);
306
- // Auto-capture the Obsidian Sync token via a Docker volume mount when
307
- // the daemon is reachable. Falls back to a paste prompt when capture
308
- // fails or the user declines. Both non-running states stay silent here —
309
- // the paste fallback is fully functional without Docker, and the start
310
- // offer surfaces the differentiated runtime guidance later in the flow.
311
- const capturedToken = docker.daemonStatus() === "running"
312
- ? await offerSyncTokenCapture(prompts, docker)
313
- : undefined;
306
+ // Sign in to Obsidian and capture the Sync token directly via the API.
307
+ // Falls back to a paste prompt when the user declines or capture fails.
308
+ const capturedToken = await offerSyncTokenCapture(prompts, fetchFn);
314
309
  // Masked prompt: the sync token is a credential and must not echo into
315
310
  // the terminal or scrollback. An empty submission still means "fill in
316
311
  // .env later" — clack's password prompt accepts blank input.
package/dist/main.js CHANGED
@@ -44,7 +44,7 @@ export const run = async (version) => {
44
44
  }),
45
45
  runGetSyncToken: (flags) => runGetSyncToken(flags, {
46
46
  prompts: createPrompts(),
47
- docker: createDockerRunner(),
47
+ fetchFn: fetch,
48
48
  }),
49
49
  });
50
50
  await program.parseAsync();
package/dist/messages.js CHANGED
@@ -33,7 +33,7 @@ const dockerInstallLine = (platform) => {
33
33
  /**
34
34
  * "No runtime at all" guidance — distinct from the daemon-stopped message so
35
35
  * the user isn't told to start something that isn't installed. platform is a
36
- * defaulted param (mirroring buildObsidianLoginArgs) so each branch stays
36
+ * defaulted param so each branch stays
37
37
  * testable; `nextStep` is appended verbatim, as in
38
38
  * buildDaemonNotRunningMessage.
39
39
  */
package/dist/program.js CHANGED
@@ -61,7 +61,7 @@ export const buildProgram = (options) => {
61
61
  });
62
62
  program
63
63
  .command("get-sync-token")
64
- .description("Generate an Obsidian Sync auth token via Docker and print it or write it to .env")
64
+ .description("Sign in to your Obsidian account and print the Sync auth token, or write it to .env")
65
65
  .option("--dir <path>", "directory containing .env to update with the token")
66
66
  .action(async (flags) => {
67
67
  process.exitCode = await options.runGetSyncToken(flags);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vault-cortex",
3
- "version": "0.11.0",
3
+ "version": "0.12.0-beta.61",
4
4
  "description": "Set up a Vault Cortex MCP server for your Obsidian vault in one command: npx vault-cortex@latest init",
5
5
  "license": "MIT",
6
6
  "type": "module",